ferroui_dynamic_data/list/
i_list.rs1use super::{Change, ChangeAwareList, ChangeSet, IExtendedList, ListChangeReason};
10
11pub trait IList<T: Clone + PartialEq> {
14 fn count(&self) -> usize;
16 fn get(&self, index: usize) -> T;
18 fn set(&mut self, index: usize, item: T);
20 fn insert(&mut self, index: usize, item: T);
22 fn remove_at(&mut self, index: usize);
24 fn clear(&mut self);
26
27 fn add(&mut self, item: T) {
29 let index = self.count();
30 self.insert(index, item);
31 }
32
33 fn index_of(&self, item: &T) -> Option<usize> {
35 (0..self.count()).find(|&index| &self.get(index) == item)
36 }
37
38 fn index_of_with(&self, item: &T, comparer: &dyn Fn(&T, &T) -> bool) -> Option<usize> {
40 (0..self.count()).find(|&index| comparer(item, &self.get(index)))
41 }
42
43 fn remove(&mut self, item: &T) -> bool {
45 match self.index_of(item) {
46 Some(index) => {
47 self.remove_at(index);
48 true
49 }
50 None => false,
51 }
52 }
53
54 fn add_range(&mut self, items: Vec<T>) {
56 for item in items {
57 self.add(item);
58 }
59 }
60
61 fn add_or_insert_range(&mut self, items: Vec<T>, index: Option<usize>) {
64 match index {
65 Some(index) => {
66 for item in items.into_iter().rev() {
67 self.insert(index, item);
68 }
69 }
70 None => self.add_range(items),
71 }
72 }
73
74 fn remove_range(&mut self, _index: usize, _count: usize) {
79 panic!("Cannot remove range from this list");
80 }
81
82 fn supports_ranges(&self) -> bool {
84 false
85 }
86
87 fn move_item(&mut self, original: usize, destination: usize) {
89 let item = self.get(original);
90 self.remove_at(original);
91 self.insert(destination, item);
92 }
93
94 fn refresh_at(&mut self, index: usize, item: T) {
97 self.remove_at(index);
98 self.insert(index, item);
99 }
100}
101
102impl<T: Clone + PartialEq> IList<T> for Vec<T> {
103 fn count(&self) -> usize {
104 self.len()
105 }
106
107 fn get(&self, index: usize) -> T {
108 self[index].clone()
109 }
110
111 fn set(&mut self, index: usize, item: T) {
112 self[index] = item;
113 }
114
115 fn insert(&mut self, index: usize, item: T) {
116 Vec::insert(self, index, item);
117 }
118
119 fn remove_at(&mut self, index: usize) {
120 Vec::remove(self, index);
121 }
122
123 fn clear(&mut self) {
124 Vec::clear(self);
125 }
126
127 fn index_of(&self, item: &T) -> Option<usize> {
128 self.iter().position(|candidate| candidate == item)
129 }
130
131 fn add_range(&mut self, items: Vec<T>) {
132 self.extend(items);
133 }
134
135 fn add_or_insert_range(&mut self, items: Vec<T>, index: Option<usize>) {
136 match index {
137 Some(index) => {
138 self.splice(index..index, items);
139 }
140 None => self.extend(items),
141 }
142 }
143
144 fn remove_range(&mut self, index: usize, count: usize) {
145 self.drain(index..index + count);
146 }
147
148 fn supports_ranges(&self) -> bool {
149 true
150 }
151}
152
153impl<T: Clone + PartialEq> IList<T> for ChangeAwareList<T> {
154 fn count(&self) -> usize {
155 ChangeAwareList::count(self)
156 }
157
158 fn get(&self, index: usize) -> T {
159 ChangeAwareList::get(self, index).clone()
160 }
161
162 fn set(&mut self, index: usize, item: T) {
163 ChangeAwareList::set(self, index, item);
164 }
165
166 fn insert(&mut self, index: usize, item: T) {
167 ChangeAwareList::insert(self, index, item);
168 }
169
170 fn remove_at(&mut self, index: usize) {
171 ChangeAwareList::remove_at(self, index);
172 }
173
174 fn clear(&mut self) {
175 ChangeAwareList::clear(self);
176 }
177
178 fn add(&mut self, item: T) {
179 ChangeAwareList::add(self, item);
180 }
181
182 fn index_of(&self, item: &T) -> Option<usize> {
183 ChangeAwareList::index_of(self, item)
184 }
185
186 fn remove(&mut self, item: &T) -> bool {
187 ChangeAwareList::remove(self, item)
188 }
189
190 fn add_range(&mut self, items: Vec<T>) {
191 ChangeAwareList::add_range(self, items);
192 }
193
194 fn add_or_insert_range(&mut self, items: Vec<T>, index: Option<usize>) {
195 match index {
196 Some(index) => IExtendedList::insert_range(self, items, index),
197 None => ChangeAwareList::add_range(self, items),
198 }
199 }
200
201 fn remove_range(&mut self, index: usize, count: usize) {
202 ChangeAwareList::remove_range(self, index, count);
203 }
204
205 fn supports_ranges(&self) -> bool {
206 true
207 }
208
209 fn move_item(&mut self, original: usize, destination: usize) {
210 IExtendedList::move_index(self, original, destination);
211 }
212
213 fn refresh_at(&mut self, index: usize, _item: T) {
214 ChangeAwareList::refresh_at(self, index);
215 }
216}
217
218pub fn clone_changes<T: Clone + PartialEq>(target: &mut dyn IList<T>, changes: &ChangeSet<T>) {
220 for change in changes {
221 clone_change(target, change, &|a, b| a == b);
222 }
223}
224
225pub fn clone_changes_with<T: Clone + PartialEq>(target: &mut dyn IList<T>, changes: &[Change<T>], comparer: &dyn Fn(&T, &T) -> bool) {
228 for change in changes {
229 clone_change(target, change, comparer);
230 }
231}
232
233pub fn clear_or_remove_many<T: Clone + PartialEq>(target: &mut dyn IList<T>, change: &Change<T>) {
236 if target.count() == change.range().count() {
237 target.clear();
238 } else {
239 remove_many(target, change.range().items());
240 }
241}
242
243pub fn remove_many<T: Clone + PartialEq>(target: &mut dyn IList<T>, items: &[T]) {
246 let mut indexes: Vec<(usize, &T)> = items.iter().filter_map(|item| target.index_of(item).map(|index| (index, item))).collect();
247 indexes.sort_by(|a, b| b.0.cmp(&a.0));
248 let has_duplicates = indexes.iter().enumerate().any(|(i, (_, item))| indexes[..i].iter().any(|(_, other)| other == item));
249 if has_duplicates {
250 for item in items {
251 target.remove(item);
252 }
253 } else {
254 for (index, _) in indexes {
255 target.remove_at(index);
256 }
257 }
258}
259
260pub fn replace_or_add<T: Clone + PartialEq>(target: &mut dyn IList<T>, original: &T, replace_with: T) {
263 match target.index_of(original) {
264 Some(index) => target.set(index, replace_with),
265 None => target.add(replace_with),
266 }
267}
268
269pub fn replace<T: Clone + PartialEq>(target: &mut dyn IList<T>, original: &T, replace_with: T) {
274 let index = target.index_of(original).expect("Cannot find index of original item. Either it does not exist in the list or the hashcode has mutated");
275 target.set(index, replace_with);
276}
277
278pub fn binary_search_by<T: Clone + PartialEq, S>(list: &dyn IList<T>, value: &S, comparer: &dyn Fn(&S, &T) -> std::cmp::Ordering) -> Result<usize, usize> {
281 let (mut lower, mut upper) = (0isize, list.count() as isize - 1);
282 while lower <= upper {
283 let middle = lower + (upper - lower) / 2;
284 match comparer(value, &list.get(middle as usize)) {
285 std::cmp::Ordering::Less => upper = middle - 1,
286 std::cmp::Ordering::Greater => lower = middle + 1,
287 std::cmp::Ordering::Equal => return Ok(middle as usize),
288 }
289 }
290 Err(lower as usize)
291}
292
293pub(crate) fn moved_within_range<T>(change: &Change<T>, start_index: usize, end_index: usize) -> bool {
295 if change.reason() != ListChangeReason::Moved {
296 return false;
297 }
298 let item = change.item();
299 let within = |index: Option<usize>| index.is_some_and(|index| index >= start_index && index <= end_index);
300 within(item.current_index()) || within(item.previous_index())
301}
302
303fn clone_change<T: Clone + PartialEq>(target: &mut dyn IList<T>, change: &Change<T>, comparer: &dyn Fn(&T, &T) -> bool) {
305 match change.reason() {
306 ListChangeReason::Add => {
307 let item = change.item();
308 match item.current_index() {
309 Some(index) => target.insert(index, item.current().clone()),
310 None => target.add(item.current().clone()),
311 }
312 }
313 ListChangeReason::AddRange => target.add_or_insert_range(change.range().items().to_vec(), change.range().index()),
314 ListChangeReason::Clear => clear_or_remove_many(target, change),
315 ListChangeReason::Replace => {
316 let item = change.item();
317 if item.current_index().is_some() && item.current_index() == item.previous_index() {
318 target.set(item.current_index().expect("checked"), item.current().clone());
319 } else {
320 match item.previous_index() {
321 None => {
322 target.remove(item.previous().expect("a replacement has a previous item"));
323 }
324 Some(index) => target.remove_at(index),
326 }
327 match item.current_index() {
328 None => target.add(item.current().clone()),
329 Some(index) => target.insert(index, item.current().clone()),
330 }
331 }
332 }
333 ListChangeReason::Refresh => {
334 let item = change.item();
335 let index = item.current_index().expect("a refresh has an index");
336 target.refresh_at(index, item.current().clone());
337 }
338 ListChangeReason::Remove => {
339 let item = change.item();
340 match item.current_index() {
341 Some(index) => target.remove_at(index),
342 None => {
343 if let Some(index) = target.index_of_with(item.current(), comparer) {
344 target.remove_at(index);
345 }
346 }
347 }
348 }
349 ListChangeReason::RemoveRange => {
350 match change.range().index() {
353 Some(index) if target.supports_ranges() => target.remove_range(index, change.range().count()),
354 _ => remove_many(target, change.range().items()),
355 }
356 }
357 ListChangeReason::Moved => {
358 let item = change.item();
359 let current = item.current_index().expect("Cannot move as an index was not specified");
360 let previous = item.previous_index().expect("Cannot move as an index was not specified");
361 target.move_item(previous, current);
362 }
363 }
364}