cranpose_foundation/lazy/
nearest_range.rs1use std::ops::Range;
11
12pub const NEAREST_ITEMS_SLIDING_WINDOW_SIZE: usize = 30;
15
16pub const NEAREST_ITEMS_EXTRA_COUNT: usize = 100;
19
20#[derive(Debug, Clone)]
28pub struct NearestRangeState {
29 value: Range<usize>,
31 last_first_visible_item: usize,
33 sliding_window_size: usize,
35 extra_item_count: usize,
37}
38
39impl Default for NearestRangeState {
40 fn default() -> Self {
41 Self::new(0)
42 }
43}
44
45impl NearestRangeState {
46 pub fn new(first_visible_item: usize) -> Self {
48 Self::with_sizes(
49 first_visible_item,
50 NEAREST_ITEMS_SLIDING_WINDOW_SIZE,
51 NEAREST_ITEMS_EXTRA_COUNT,
52 )
53 }
54
55 pub fn with_sizes(
57 first_visible_item: usize,
58 sliding_window_size: usize,
59 extra_item_count: usize,
60 ) -> Self {
61 let value =
62 Self::calculate_range(first_visible_item, sliding_window_size, extra_item_count);
63 Self {
64 value,
65 last_first_visible_item: first_visible_item,
66 sliding_window_size,
67 extra_item_count,
68 }
69 }
70
71 pub fn range(&self) -> Range<usize> {
73 self.value.clone()
74 }
75
76 pub fn update(&mut self, first_visible_item: usize) {
79 if first_visible_item != self.last_first_visible_item {
80 self.last_first_visible_item = first_visible_item;
81 self.value = Self::calculate_range(
82 first_visible_item,
83 self.sliding_window_size,
84 self.extra_item_count,
85 );
86 }
87 }
88
89 fn calculate_range(
92 first_visible_item: usize,
93 sliding_window_size: usize,
94 extra_item_count: usize,
95 ) -> Range<usize> {
96 let sliding_window_start =
97 sliding_window_size.saturating_mul(first_visible_item / sliding_window_size);
98 let start = sliding_window_start.saturating_sub(extra_item_count);
99 let end = sliding_window_start
100 .saturating_add(sliding_window_size)
101 .saturating_add(extra_item_count);
102 start..end
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn test_initial_range() {
112 let state = NearestRangeState::new(0);
113 assert_eq!(state.range(), 0..130);
115 }
116
117 #[test]
118 fn test_range_after_small_scroll() {
119 let mut state = NearestRangeState::new(0);
120 state.update(5);
121 assert_eq!(state.range(), 0..130);
123 }
124
125 #[test]
126 fn test_range_after_crossing_window() {
127 let mut state = NearestRangeState::new(0);
128 state.update(35);
129 assert_eq!(state.range(), 0..160);
133 }
134
135 #[test]
136 fn test_range_far_scroll() {
137 let mut state = NearestRangeState::new(0);
138 state.update(1000);
139 assert_eq!(state.range(), 890..1120);
143 }
144}