promkit_widgets/
cursor.rs1pub mod len;
2use len::Len;
3
4#[derive(Clone)]
11pub struct Cursor<C> {
12 contents: C,
13 position: usize,
14 cyclic: bool,
15}
16
17impl<C: Len> Cursor<C> {
18 pub fn new(contents: C, position: usize, cyclic: bool) -> Self {
23 let adjusted_position = if position >= contents.len() {
24 contents.len().saturating_sub(1)
25 } else {
26 position
27 };
28
29 Self {
30 contents,
31 position: adjusted_position,
32 cyclic,
33 }
34 }
35
36 pub fn contents(&self) -> &C {
38 &self.contents
39 }
40
41 pub fn contents_mut(&mut self) -> &mut C {
43 &mut self.contents
44 }
45
46 pub fn replace_contents(&mut self, contents: C) {
48 self.contents = contents;
49 if self.position >= self.contents.len() {
50 self.position = self.contents.len().saturating_sub(1);
51 }
52 }
53
54 pub fn position(&self) -> usize {
56 self.position
57 }
58
59 pub fn shift(&mut self, backward: usize, forward: usize) -> bool {
60 let len = self.contents.len();
61 if self.cyclic {
62 let total_move = forward as isize - backward as isize;
63 let new_position =
64 (self.position as isize + total_move).rem_euclid(len as isize) as usize;
65 self.position = new_position;
66 true
67 } else if backward > self.position {
68 false
69 } else {
70 let new_position = self.position - backward;
71 if new_position + forward < len {
72 self.position = new_position + forward;
73 true
74 } else {
75 false
76 }
77 }
78 }
79
80 pub fn backward(&mut self) -> bool {
83 self.shift(1, 0)
84 }
85
86 pub fn forward(&mut self) -> bool {
89 self.shift(0, 1)
90 }
91
92 pub fn move_to_head(&mut self) {
94 self.move_to(0);
95 }
96
97 pub fn is_head(&self) -> bool {
99 self.position == 0
100 }
101
102 pub fn move_to_tail(&mut self) {
104 self.move_to(self.contents.len().saturating_sub(1));
105 }
106
107 pub fn is_tail(&self) -> bool {
109 self.position == self.contents.len().saturating_sub(1)
110 }
111
112 pub fn move_to(&mut self, position: usize) -> bool {
113 if position < self.contents.len() {
114 self.position = position;
115 true
116 } else {
117 false
118 }
119 }
120}
121
122#[cfg(test)]
123mod test {
124 use super::*;
125
126 mod shift {
127 use super::*;
128
129 #[test]
130 fn test_cyclic_forward() {
131 let mut cursor = Cursor::new(vec!["a", "b", "c"], 0, true);
132 assert!(cursor.shift(0, 2)); assert_eq!(cursor.position(), 2);
134 }
135
136 #[test]
137 fn test_cyclic_backward() {
138 let mut cursor = Cursor::new(vec!["a", "b", "c"], 2, true);
139 assert!(cursor.shift(2, 0)); assert_eq!(cursor.position(), 0);
141 }
142
143 #[test]
144 fn test_cyclic_wrap_around() {
145 let mut cursor = Cursor::new(vec!["a", "b", "c"], 2, true);
146 assert!(cursor.shift(0, 1)); assert_eq!(cursor.position(), 0);
148 }
149
150 #[test]
151 fn test_non_cyclic_forward_fail() {
152 let mut cursor = Cursor::new(vec!["a", "b", "c"], 2, false);
153 assert!(!cursor.shift(0, 1)); }
155
156 #[test]
157 fn test_non_cyclic_backward_fail() {
158 let mut cursor = Cursor::new(vec!["a", "b", "c"], 0, false);
159 assert!(!cursor.shift(1, 0)); }
161
162 #[test]
163 fn test_non_cyclic_forward_success() {
164 let mut cursor = Cursor::new(vec!["a", "b", "c"], 1, false);
165 assert!(cursor.shift(0, 1)); assert_eq!(cursor.position(), 2);
167 }
168
169 #[test]
170 fn test_non_cyclic_backward_success() {
171 let mut cursor = Cursor::new(vec!["a", "b", "c"], 2, false);
172 assert!(cursor.shift(1, 0)); assert_eq!(cursor.position(), 1);
174 }
175 }
176
177 mod backward {
178 use super::*;
179
180 #[test]
181 fn test() {
182 let mut b = Cursor::new(vec!["a", "b", "c"], 0, false);
183 assert!(!b.backward());
184 b.position = 1;
185 assert!(b.backward());
186 }
187 }
188
189 mod forward {
190 use super::*;
191
192 #[test]
193 fn test() {
194 let mut b = Cursor::new(vec!["a", "b", "c"], 0, false);
195 assert!(b.forward());
196 b.position = b.contents.len() - 1;
197 assert!(!b.forward());
198 }
199 }
200}