i_slint_core/model/
adapters.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4//! This module contains adapter models.
5
6use super::*;
7
8#[cfg(test)]
9#[derive(Default)]
10struct TestView {
11    // Track the parameters reported by the model (row counts, indices, etc.).
12    // The last field in the tuple is the row size the model reports at the time
13    // of callback
14    changed_rows: RefCell<Vec<usize>>,
15    added_rows: RefCell<Vec<(usize, usize)>>,
16    removed_rows: RefCell<Vec<(usize, usize)>>,
17    reset: RefCell<usize>,
18}
19
20#[cfg(test)]
21impl TestView {
22    fn clear(&self) {
23        self.changed_rows.borrow_mut().clear();
24        self.added_rows.borrow_mut().clear();
25        self.removed_rows.borrow_mut().clear();
26    }
27}
28
29#[cfg(test)]
30impl ModelChangeListener for TestView {
31    fn row_changed(self: Pin<&Self>, row: usize) {
32        self.changed_rows.borrow_mut().push(row);
33    }
34
35    fn row_added(self: Pin<&Self>, index: usize, count: usize) {
36        self.added_rows.borrow_mut().push((index, count));
37    }
38
39    fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
40        self.removed_rows.borrow_mut().push((index, count));
41    }
42    fn reset(self: Pin<&Self>) {
43        *self.reset.borrow_mut() += 1;
44    }
45}
46
47#[cfg(test)]
48struct ModelChecker<Data: PartialEq + core::fmt::Debug + 'static> {
49    model: Rc<dyn Model<Data = Data>>,
50    rows_copy: RefCell<Vec<Data>>,
51}
52
53#[cfg(test)]
54impl<Data: PartialEq + core::fmt::Debug + 'static> ModelChangeListener for ModelChecker<Data> {
55    fn row_changed(self: Pin<&Self>, row: usize) {
56        self.rows_copy.borrow_mut()[row] = self.model.row_data(row).unwrap();
57    }
58
59    fn row_added(self: Pin<&Self>, index: usize, count: usize) {
60        let mut copy = self.rows_copy.borrow_mut();
61        for row in index..index + count {
62            copy.insert(row, self.model.row_data(row).unwrap());
63        }
64    }
65
66    fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
67        self.rows_copy.borrow_mut().drain(index..index + count);
68    }
69    fn reset(self: Pin<&Self>) {
70        *self.rows_copy.borrow_mut() = ModelRc::from(self.model.clone()).iter().collect()
71    }
72}
73
74#[cfg(test)]
75impl<Data: PartialEq + core::fmt::Debug + 'static> ModelChecker<Data> {
76    pub fn new(
77        model: Rc<impl Model<Data = Data> + 'static>,
78    ) -> Pin<Box<ModelChangeListenerContainer<Self>>> {
79        let s = Self { rows_copy: RefCell::new(model.iter().collect()), model: model.clone() };
80        let s = Box::pin(ModelChangeListenerContainer::new(s));
81        model.model_tracker().attach_peer(s.as_ref().model_peer());
82        s
83    }
84
85    #[track_caller]
86    pub fn check(&self) {
87        assert_eq!(
88            *self.rows_copy.borrow(),
89            ModelRc::from(self.model.clone()).iter().collect::<Vec<_>>()
90        );
91    }
92}
93
94#[cfg(test)]
95impl<Data: PartialEq + core::fmt::Debug + 'static> Drop for ModelChecker<Data> {
96    fn drop(&mut self) {
97        self.check();
98    }
99}
100
101/// Provides rows that are generated by a map function based on the rows of another Model
102///
103/// When the other Model is updated, the `MapModel` is updated accordingly.
104///
105/// Generic parameters:
106/// * `M` the type of the wrapped `Model`.
107/// * `F` the map function.
108///
109/// ## Example
110///
111/// Here we have a [`VecModel`] holding rows of a custom type `Name`.
112/// It is then mapped into a `MapModel` of [`SharedString`]s
113///
114/// ```
115/// # use slint::{Model, VecModel, SharedString, MapModel};
116/// #[derive(Clone)]
117/// struct Name {
118///     first: String,
119///     last: String,
120/// }
121///
122/// let model = VecModel::from(vec![
123///     Name { first: "Hans".to_string(), last: "Emil".to_string() },
124///     Name { first: "Max".to_string(), last: "Mustermann".to_string() },
125///     Name { first: "Roman".to_string(), last: "Tisch".to_string() },
126/// ]);
127///
128/// let mapped_model = MapModel::new(model, |n|
129///     slint::format!("{}, {}", n.last, n.first)
130/// );
131///
132/// assert_eq!(mapped_model.row_data(0).unwrap(), SharedString::from("Emil, Hans"));
133/// assert_eq!(mapped_model.row_data(1).unwrap(), SharedString::from("Mustermann, Max"));
134/// assert_eq!(mapped_model.row_data(2).unwrap(), SharedString::from("Tisch, Roman"));
135///
136/// ```
137///
138/// Alternatively you can use the shortcut [`ModelExt::map`].
139/// ```
140/// # use slint::{Model, ModelExt, VecModel, SharedString, MapModel};
141/// # #[derive(Clone)]
142/// # struct Name {
143/// #     first: String,
144/// #     last: String,
145/// # }
146/// let mapped_model = VecModel::from(vec![
147///     Name { first: "Hans".to_string(), last: "Emil".to_string() },
148///     Name { first: "Max".to_string(), last: "Mustermann".to_string() },
149///     Name { first: "Roman".to_string(), last: "Tisch".to_string() },
150/// ])
151/// .map(|n| slint::format!("{}, {}", n.last, n.first));
152/// # assert_eq!(mapped_model.row_data(0).unwrap(), SharedString::from("Emil, Hans"));
153/// # assert_eq!(mapped_model.row_data(1).unwrap(), SharedString::from("Mustermann, Max"));
154/// # assert_eq!(mapped_model.row_data(2).unwrap(), SharedString::from("Tisch, Roman"));
155/// ```
156///
157/// If you want to modify the underlying [`VecModel`] you can give it a [`Rc`] of the MapModel:
158/// ```
159/// # use std::rc::Rc;
160/// # use slint::{Model, VecModel, SharedString, MapModel};
161/// # #[derive(Clone)]
162/// # struct Name {
163/// #     first: String,
164/// #     last: String,
165/// # }
166/// let model = Rc::new(VecModel::from(vec![
167///     Name { first: "Hans".to_string(), last: "Emil".to_string() },
168///     Name { first: "Max".to_string(), last: "Mustermann".to_string() },
169///     Name { first: "Roman".to_string(), last: "Tisch".to_string() },
170/// ]));
171///
172/// let mapped_model = MapModel::new(model.clone(), |n|
173///     slint::format!("{}, {}", n.last, n.first)
174/// );
175///
176/// model.set_row_data(1, Name { first: "Minnie".to_string(), last: "Musterfrau".to_string() });
177///
178/// assert_eq!(mapped_model.row_data(0).unwrap(), SharedString::from("Emil, Hans"));
179/// assert_eq!(mapped_model.row_data(1).unwrap(), SharedString::from("Musterfrau, Minnie"));
180/// assert_eq!(mapped_model.row_data(2).unwrap(), SharedString::from("Tisch, Roman"));
181///
182/// ```
183pub struct MapModel<M, F> {
184    wrapped_model: M,
185    map_function: F,
186}
187
188impl<M, F, T, U> Model for MapModel<M, F>
189where
190    M: 'static,
191    F: 'static,
192    F: Fn(T) -> U,
193    M: Model<Data = T>,
194{
195    type Data = U;
196
197    fn row_count(&self) -> usize {
198        self.wrapped_model.row_count()
199    }
200
201    fn row_data(&self, row: usize) -> Option<Self::Data> {
202        self.wrapped_model.row_data(row).map(|x| (self.map_function)(x))
203    }
204
205    fn model_tracker(&self) -> &dyn ModelTracker {
206        self.wrapped_model.model_tracker()
207    }
208
209    fn as_any(&self) -> &dyn core::any::Any {
210        self
211    }
212}
213
214impl<M, F, T, U> MapModel<M, F>
215where
216    M: 'static,
217    F: 'static,
218    F: Fn(T) -> U,
219    M: Model<Data = T>,
220{
221    /// Creates a new MapModel based on the given `wrapped_model` and `map_function`.
222    /// Alternatively you can use [`ModelExt::map`] on your Model.
223    pub fn new(wrapped_model: M, map_function: F) -> Self {
224        Self { wrapped_model, map_function }
225    }
226
227    /// Returns a reference to the inner model
228    pub fn source_model(&self) -> &M {
229        &self.wrapped_model
230    }
231}
232
233#[test]
234fn test_map_model() {
235    use alloc::string::ToString;
236    let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3]));
237    let map = MapModel::new(wrapped_rc.clone(), |x| x.to_string());
238
239    wrapped_rc.set_row_data(2, 42);
240    wrapped_rc.push(4);
241
242    assert_eq!(map.row_data(2).unwrap(), "42");
243    assert_eq!(map.row_data(3).unwrap(), "4");
244    assert_eq!(map.row_data(1).unwrap(), "2");
245}
246
247struct FilterModelInner<M, F>
248where
249    M: Model + 'static,
250    F: Fn(&M::Data) -> bool + 'static,
251{
252    wrapped_model: M,
253    filter_function: F,
254    // This vector saves the indices of the elements that are not filtered out
255    mapping: RefCell<Vec<usize>>,
256    notify: ModelNotify,
257}
258
259impl<M, F> FilterModelInner<M, F>
260where
261    M: Model + 'static,
262    F: Fn(&M::Data) -> bool + 'static,
263{
264    fn build_mapping_vec(&self) {
265        let mut mapping = self.mapping.borrow_mut();
266        *mapping = self
267            .wrapped_model
268            .iter()
269            .enumerate()
270            .filter_map(|(i, e)| (self.filter_function)(&e).then_some(i))
271            .collect();
272    }
273}
274
275impl<M, F> ModelChangeListener for FilterModelInner<M, F>
276where
277    M: Model + 'static,
278    F: Fn(&M::Data) -> bool + 'static,
279{
280    fn row_changed(self: Pin<&Self>, row: usize) {
281        let mut mapping = self.mapping.borrow_mut();
282
283        let (index, is_contained) = match mapping.binary_search(&row) {
284            Ok(index) => (index, true),
285            Err(index) => (index, false),
286        };
287
288        let should_be_contained =
289            (self.filter_function)(&self.wrapped_model.row_data(row).unwrap());
290
291        if is_contained && should_be_contained {
292            drop(mapping);
293            self.notify.row_changed(index);
294        } else if !is_contained && should_be_contained {
295            mapping.insert(index, row);
296            drop(mapping);
297            self.notify.row_added(index, 1);
298        } else if is_contained && !should_be_contained {
299            mapping.remove(index);
300            drop(mapping);
301            self.notify.row_removed(index, 1);
302        }
303    }
304
305    fn row_added(self: Pin<&Self>, index: usize, count: usize) {
306        if count == 0 {
307            return;
308        }
309
310        let insertion: Vec<usize> = self
311            .wrapped_model
312            .iter()
313            .enumerate()
314            .skip(index)
315            .take(count)
316            .filter_map(|(i, e)| (self.filter_function)(&e).then_some(i))
317            .collect();
318
319        let mut mapping = self.mapping.borrow_mut();
320        let insertion_point = mapping.binary_search(&index).unwrap_or_else(|ip| ip);
321        mapping[insertion_point..].iter_mut().for_each(|i| *i += count);
322
323        if !insertion.is_empty() {
324            let insertion_len = insertion.len();
325            mapping.splice(insertion_point..insertion_point, insertion);
326
327            drop(mapping);
328            self.notify.row_added(insertion_point, insertion_len);
329        }
330    }
331
332    fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
333        if count == 0 {
334            return;
335        }
336        let mut mapping = self.mapping.borrow_mut();
337
338        let start = mapping.binary_search(&index).unwrap_or_else(|s| s);
339        let end = mapping.binary_search(&(index + count)).unwrap_or_else(|e| e);
340        let range = start..end;
341
342        mapping[end..].iter_mut().for_each(|i| *i -= count);
343
344        if !range.is_empty() {
345            mapping.drain(range.clone());
346            drop(mapping);
347            self.notify.row_removed(start, range.len());
348        }
349    }
350
351    fn reset(self: Pin<&Self>) {
352        self.build_mapping_vec();
353        self.notify.reset();
354    }
355}
356
357/// Provides a filtered subset of rows by another [`Model`].
358///
359/// When the other Model is updated, the `FilterModel` is updated accordingly.
360///
361/// Generic parameters:
362/// * `M` the type of the wrapped `Model`.
363/// * `F` the filter function.
364///
365/// ## Example
366///
367/// Here we have a [`VecModel`] holding [`crate::SharedString`]s.
368/// It is then filtered into a `FilterModel`.
369///
370/// ```
371/// # use slint::{Model, VecModel, SharedString, FilterModel};
372/// let model = VecModel::from(vec![
373///     SharedString::from("Lorem"),
374///     SharedString::from("ipsum"),
375///     SharedString::from("dolor"),
376/// ]);
377///
378/// let filtered_model = FilterModel::new(model, |s| s.contains('o'));
379///
380/// assert_eq!(filtered_model.row_data(0).unwrap(), SharedString::from("Lorem"));
381/// assert_eq!(filtered_model.row_data(1).unwrap(), SharedString::from("dolor"));
382/// ```
383///
384/// Alternatively you can use the shortcut [`ModelExt::filter`].
385/// ```
386/// # use slint::{Model, ModelExt, VecModel, SharedString, FilterModel};
387/// let filtered_model = VecModel::from(vec![
388///     SharedString::from("Lorem"),
389///     SharedString::from("ipsum"),
390///     SharedString::from("dolor"),
391/// ]).filter(|s| s.contains('o'));
392/// # assert_eq!(filtered_model.row_data(0).unwrap(), SharedString::from("Lorem"));
393/// # assert_eq!(filtered_model.row_data(1).unwrap(), SharedString::from("dolor"));
394/// ```
395///
396/// If you want to modify the underlying [`VecModel`] you can give it a [`Rc`] of the FilterModel:
397/// ```
398/// # use std::rc::Rc;
399/// # use slint::{Model, VecModel, SharedString, FilterModel};
400/// let model = Rc::new(VecModel::from(vec![
401///     SharedString::from("Lorem"),
402///     SharedString::from("ipsum"),
403///     SharedString::from("dolor"),
404/// ]));
405///
406/// let filtered_model = FilterModel::new(model.clone(), |s| s.contains('o'));
407///
408/// assert_eq!(filtered_model.row_data(0).unwrap(), SharedString::from("Lorem"));
409/// assert_eq!(filtered_model.row_data(1).unwrap(), SharedString::from("dolor"));
410///
411/// model.set_row_data(1, SharedString::from("opsom"));
412///
413/// assert_eq!(filtered_model.row_data(0).unwrap(), SharedString::from("Lorem"));
414/// assert_eq!(filtered_model.row_data(1).unwrap(), SharedString::from("opsom"));
415/// assert_eq!(filtered_model.row_data(2).unwrap(), SharedString::from("dolor"));
416/// ```
417pub struct FilterModel<M, F>(Pin<Box<ModelChangeListenerContainer<FilterModelInner<M, F>>>>)
418where
419    M: Model + 'static,
420    F: Fn(&M::Data) -> bool + 'static;
421
422impl<M, F> FilterModel<M, F>
423where
424    M: Model + 'static,
425    F: Fn(&M::Data) -> bool + 'static,
426{
427    /// Creates a new FilterModel based on the given `wrapped_model` and filtered by `filter_function`.
428    /// Alternatively you can use [`ModelExt::filter`] on your Model.
429    pub fn new(wrapped_model: M, filter_function: F) -> Self {
430        let filter_model_inner = FilterModelInner {
431            wrapped_model,
432            filter_function,
433            mapping: RefCell::new(Vec::new()),
434            notify: Default::default(),
435        };
436
437        filter_model_inner.build_mapping_vec();
438
439        let container = Box::pin(ModelChangeListenerContainer::new(filter_model_inner));
440
441        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());
442
443        Self(container)
444    }
445
446    /// Manually reapply the filter. You need to run this e.g. if the filtering function depends on
447    /// mutable state and it has changed.
448    pub fn reset(&self) {
449        self.0.as_ref().get().reset();
450    }
451
452    /// Gets the row index of the underlying unfiltered model for a given filtered row index.
453    pub fn unfiltered_row(&self, filtered_row: usize) -> usize {
454        self.0.mapping.borrow()[filtered_row]
455    }
456
457    /// Returns a reference to the inner model
458    pub fn source_model(&self) -> &M {
459        &self.0.as_ref().get().get_ref().wrapped_model
460    }
461}
462
463impl<M, F> Model for FilterModel<M, F>
464where
465    M: Model + 'static,
466    F: Fn(&M::Data) -> bool + 'static,
467{
468    type Data = M::Data;
469
470    fn row_count(&self) -> usize {
471        self.0.mapping.borrow().len()
472    }
473
474    fn row_data(&self, row: usize) -> Option<Self::Data> {
475        self.0
476            .mapping
477            .borrow()
478            .get(row)
479            .and_then(|&wrapped_row| self.0.wrapped_model.row_data(wrapped_row))
480    }
481
482    fn set_row_data(&self, row: usize, data: Self::Data) {
483        let wrapped_row = self.0.mapping.borrow()[row];
484        self.0.wrapped_model.set_row_data(wrapped_row, data);
485    }
486
487    fn model_tracker(&self) -> &dyn ModelTracker {
488        &self.0.notify
489    }
490
491    fn as_any(&self) -> &dyn core::any::Any {
492        self
493    }
494}
495
496#[test]
497fn test_filter_model() {
498    let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3, 4, 5, 6]));
499    let filter = Rc::new(FilterModel::new(wrapped_rc.clone(), |x| x % 2 == 0));
500
501    let _checker = ModelChecker::new(filter.clone());
502
503    assert_eq!(filter.row_data(0).unwrap(), 2);
504    assert_eq!(filter.row_data(1).unwrap(), 4);
505    assert_eq!(filter.row_data(2).unwrap(), 6);
506    assert_eq!(filter.row_count(), 3);
507
508    wrapped_rc.remove(1);
509    assert_eq!(filter.row_data(0).unwrap(), 4);
510    assert_eq!(filter.row_data(1).unwrap(), 6);
511    assert_eq!(filter.row_count(), 2);
512
513    wrapped_rc.push(8);
514    wrapped_rc.push(7);
515    assert_eq!(filter.row_data(0).unwrap(), 4);
516    assert_eq!(filter.row_data(1).unwrap(), 6);
517    assert_eq!(filter.row_data(2).unwrap(), 8);
518    assert_eq!(filter.row_count(), 3);
519
520    wrapped_rc.set_row_data(1, 2);
521    assert_eq!(filter.row_data(0).unwrap(), 2);
522    assert_eq!(filter.row_data(1).unwrap(), 4);
523    assert_eq!(filter.row_data(2).unwrap(), 6);
524    assert_eq!(filter.row_data(3).unwrap(), 8);
525    assert_eq!(filter.row_count(), 4);
526
527    wrapped_rc.insert(2, 12);
528    assert_eq!(filter.row_data(0).unwrap(), 2);
529    assert_eq!(filter.row_data(1).unwrap(), 12);
530    assert_eq!(filter.row_data(2).unwrap(), 4);
531    assert_eq!(filter.row_data(3).unwrap(), 6);
532    assert_eq!(filter.row_data(4).unwrap(), 8);
533    assert_eq!(filter.row_count(), 5);
534}
535
536#[test]
537fn test_filter_model_source_model() {
538    let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3, 4]));
539    let model = Rc::new(FilterModel::new(wrapped_rc.clone(), |x| x % 2 == 0));
540
541    let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
542    model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
543
544    let _checker = ModelChecker::new(model.clone());
545
546    model.source_model().push(5);
547    model.source_model().push(6);
548
549    let expected = &[2, 4, 6];
550    assert_eq!(model.row_count(), expected.len());
551    for (i, v) in expected.iter().enumerate() {
552        assert_eq!(model.row_data(i), Some(*v), "Expected {v} at index {i}");
553    }
554}
555
556pub trait SortHelper<D> {
557    fn cmp(&mut self, lhs: &D, rhs: &D) -> core::cmp::Ordering;
558}
559
560pub struct AscendingSortHelper;
561
562impl<D> SortHelper<D> for AscendingSortHelper
563where
564    D: core::cmp::Ord,
565{
566    fn cmp(&mut self, lhs: &D, rhs: &D) -> core::cmp::Ordering {
567        lhs.cmp(rhs)
568    }
569}
570
571impl<F, D> SortHelper<D> for F
572where
573    F: FnMut(&D, &D) -> core::cmp::Ordering + 'static,
574{
575    fn cmp(&mut self, lhs: &D, rhs: &D) -> core::cmp::Ordering {
576        (self)(lhs, rhs)
577    }
578}
579
580struct SortModelInner<M, S>
581where
582    M: Model + 'static,
583    S: SortHelper<M::Data> + 'static,
584{
585    wrapped_model: M,
586    sort_helper: RefCell<S>,
587    // This vector saves the indices of the elements in sorted order.
588    mapping: RefCell<Vec<usize>>,
589    notify: ModelNotify,
590    sorted_rows_dirty: Cell<bool>,
591}
592
593impl<M, S> SortModelInner<M, S>
594where
595    M: Model + 'static,
596    S: SortHelper<M::Data>,
597{
598    fn build_mapping_vec(&self) {
599        if !self.sorted_rows_dirty.get() {
600            return;
601        }
602
603        let mut mapping = self.mapping.borrow_mut();
604
605        mapping.clear();
606        mapping.extend(0..self.wrapped_model.row_count());
607        mapping.sort_by(|lhs, rhs| {
608            self.sort_helper.borrow_mut().cmp(
609                &self.wrapped_model.row_data(*lhs).unwrap(),
610                &self.wrapped_model.row_data(*rhs).unwrap(),
611            )
612        });
613
614        self.sorted_rows_dirty.set(false);
615    }
616}
617
618impl<M, S> ModelChangeListener for SortModelInner<M, S>
619where
620    M: Model + 'static,
621    S: SortHelper<M::Data> + 'static,
622{
623    fn row_changed(self: Pin<&Self>, row: usize) {
624        if self.sorted_rows_dirty.get() {
625            self.reset();
626            return;
627        }
628
629        let mut mapping = self.mapping.borrow_mut();
630        let removed_index = mapping.iter().position(|r| *r == row).unwrap();
631        mapping.remove(removed_index);
632
633        let changed_data = self.wrapped_model.row_data(row).unwrap();
634        let insertion_index = mapping.partition_point(|existing_row| {
635            self.sort_helper
636                .borrow_mut()
637                .cmp(&self.wrapped_model.row_data(*existing_row).unwrap(), &changed_data)
638                == core::cmp::Ordering::Less
639        });
640
641        mapping.insert(insertion_index, row);
642
643        drop(mapping);
644
645        if insertion_index == removed_index {
646            self.notify.row_changed(removed_index);
647        } else {
648            self.notify.row_removed(removed_index, 1);
649            self.notify.row_added(insertion_index, 1);
650        }
651    }
652
653    fn row_added(self: Pin<&Self>, index: usize, count: usize) {
654        if count == 0 {
655            return;
656        }
657
658        if self.sorted_rows_dirty.get() {
659            self.reset();
660            return;
661        }
662
663        // Adjust the existing sorted row indices to match the updated source model
664        for row in self.mapping.borrow_mut().iter_mut() {
665            if *row >= index {
666                *row += count;
667            }
668        }
669
670        for row in index..(index + count) {
671            let added_data = self.wrapped_model.row_data(row).unwrap();
672            let insertion_index = self.mapping.borrow().partition_point(|existing_row| {
673                self.sort_helper
674                    .borrow_mut()
675                    .cmp(&self.wrapped_model.row_data(*existing_row).unwrap(), &added_data)
676                    == core::cmp::Ordering::Less
677            });
678
679            self.mapping.borrow_mut().insert(insertion_index, row);
680            self.notify.row_added(insertion_index, 1)
681        }
682    }
683
684    fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
685        if count == 0 {
686            return;
687        }
688
689        if self.sorted_rows_dirty.get() {
690            self.reset();
691            return;
692        }
693
694        let mut removed_rows = Vec::new();
695
696        let mut i = 0;
697
698        loop {
699            if i >= self.mapping.borrow().len() {
700                break;
701            }
702
703            let sort_index = self.mapping.borrow()[i];
704
705            if sort_index >= index {
706                if sort_index < index + count {
707                    removed_rows.push(i);
708                    self.mapping.borrow_mut().remove(i);
709                    continue;
710                } else {
711                    self.mapping.borrow_mut()[i] -= count;
712                }
713            }
714
715            i += 1;
716        }
717
718        for removed_row in removed_rows {
719            self.notify.row_removed(removed_row, 1);
720        }
721    }
722
723    fn reset(self: Pin<&Self>) {
724        self.sorted_rows_dirty.set(true);
725        self.notify.reset();
726    }
727}
728
729/// Provides a sorted view of rows by another [`Model`].
730///
731/// When the other Model is updated, the `Sorted` is updated accordingly.
732///
733/// Generic parameters:
734/// * `M` the type of the wrapped `Model`.
735/// * `F` a type that provides an order to model rows. It is constrained by the internal trait `SortHelper`, which is used to sort the model in ascending order if the model data supports it, or by a given sort function.
736///
737/// ## Example
738///
739/// Here we have a [`VecModel`] holding [`crate::SharedString`]s.
740/// It is then sorted into a `SortModel`.
741///
742/// ```
743/// # use slint::{Model, VecModel, SharedString, SortModel};
744/// let model = VecModel::from(vec![
745///     SharedString::from("Lorem"),
746///     SharedString::from("ipsum"),
747///     SharedString::from("dolor"),
748/// ]);
749///
750/// let sorted_model = SortModel::new(model, |lhs, rhs| lhs.to_lowercase().cmp(&rhs.to_lowercase()));
751///
752/// assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from("dolor"));
753/// assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from("ipsum"));
754/// assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from("Lorem"));
755/// ```
756///
757/// Alternatively you can use the shortcut [`ModelExt::sort_by`].
758/// ```
759/// # use slint::{Model, ModelExt, VecModel, SharedString, SortModel};
760/// let sorted_model = VecModel::from(vec![
761///     SharedString::from("Lorem"),
762///     SharedString::from("ipsum"),
763///     SharedString::from("dolor"),
764/// ]).sort_by(|lhs, rhs| lhs.to_lowercase().cmp(&rhs.to_lowercase()));
765/// # assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from("dolor"));
766/// # assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from("ipsum"));
767/// # assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from("Lorem"));
768/// ```
769///
770/// It is also possible to get a ascending sorted  `SortModel` order for `core::cmp::Ord` type items.
771///
772/// ```
773/// # use slint::{Model, VecModel, SortModel};
774/// let model = VecModel::from(vec![
775///     5,
776///     1,
777///     3,
778/// ]);
779///
780/// let sorted_model = SortModel::new_ascending(model);
781///
782/// assert_eq!(sorted_model.row_data(0).unwrap(), 1);
783/// assert_eq!(sorted_model.row_data(1).unwrap(), 3);
784/// assert_eq!(sorted_model.row_data(2).unwrap(), 5);
785/// ```
786///
787/// Alternatively you can use the shortcut [`ModelExt::sort`].
788/// ```
789/// # use slint::{Model, ModelExt, VecModel, SharedString, SortModel};
790/// let sorted_model = VecModel::from(vec![
791///     5,
792///     1,
793///     3,
794/// ]).sort();
795/// # assert_eq!(sorted_model.row_data(0).unwrap(), 1);
796/// # assert_eq!(sorted_model.row_data(1).unwrap(), 3);
797/// # assert_eq!(sorted_model.row_data(2).unwrap(), 5);
798/// ```
799///
800/// If you want to modify the underlying [`VecModel`] you can give it a [`Rc`] of the SortModel:
801/// ```
802/// # use std::rc::Rc;
803/// # use slint::{Model, VecModel, SharedString, SortModel};
804/// let model = Rc::new(VecModel::from(vec![
805///     SharedString::from("Lorem"),
806///     SharedString::from("ipsum"),
807///     SharedString::from("dolor"),
808/// ]));
809///
810/// let sorted_model = SortModel::new(model.clone(), |lhs, rhs| lhs.to_lowercase().cmp(&rhs.to_lowercase()));
811///
812/// assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from("dolor"));
813/// assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from("ipsum"));
814/// assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from("Lorem"));
815///
816/// model.set_row_data(1, SharedString::from("opsom"));
817///
818/// assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from("dolor"));
819/// assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from("Lorem"));
820/// assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from("opsom"));
821/// ```
822pub struct SortModel<M, F>(Pin<Box<ModelChangeListenerContainer<SortModelInner<M, F>>>>)
823where
824    M: Model + 'static,
825    F: SortHelper<M::Data> + 'static;
826
827impl<M, F> SortModel<M, F>
828where
829    M: Model + 'static,
830    F: FnMut(&M::Data, &M::Data) -> core::cmp::Ordering + 'static,
831{
832    /// Creates a new SortModel based on the given `wrapped_model` and sorted by `sort_function`.
833    /// Alternatively you can use [`ModelExt::sort_by`] on your Model.
834    pub fn new(wrapped_model: M, sort_function: F) -> Self
835    where
836        F: FnMut(&M::Data, &M::Data) -> core::cmp::Ordering + 'static,
837    {
838        let sorted_model_inner = SortModelInner {
839            wrapped_model,
840            sort_helper: RefCell::new(sort_function),
841            mapping: RefCell::new(Vec::new()),
842            notify: Default::default(),
843            sorted_rows_dirty: Cell::new(true),
844        };
845
846        let container = Box::pin(ModelChangeListenerContainer::new(sorted_model_inner));
847
848        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());
849
850        Self(container)
851    }
852
853    /// Returns a reference to the inner model
854    pub fn source_model(&self) -> &M {
855        &self.0.as_ref().get().get_ref().wrapped_model
856    }
857}
858
859impl<M> SortModel<M, AscendingSortHelper>
860where
861    M: Model + 'static,
862    M::Data: core::cmp::Ord,
863{
864    /// Creates a new SortModel based on the given `wrapped_model` and sorted in ascending order.
865    /// Alternatively you can use [`ModelExt::sort`] on your Model.
866    pub fn new_ascending(wrapped_model: M) -> Self
867    where
868        M::Data: core::cmp::Ord,
869    {
870        let sorted_model_inner = SortModelInner {
871            wrapped_model,
872            sort_helper: RefCell::new(AscendingSortHelper),
873            mapping: RefCell::new(Vec::new()),
874            notify: Default::default(),
875            sorted_rows_dirty: Cell::new(true),
876        };
877
878        let container = Box::pin(ModelChangeListenerContainer::new(sorted_model_inner));
879
880        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());
881
882        Self(container)
883    }
884
885    /// Manually reapply the sorting. You need to run this e.g. if the sort function depends
886    /// on mutable state and it has changed.
887    pub fn reset(&self) {
888        self.0.as_ref().get().reset();
889    }
890
891    /// Gets the row index of the underlying unsorted model for a given sorted row index.
892    pub fn unsorted_row(&self, sorted_row: usize) -> usize {
893        self.0.build_mapping_vec();
894        self.0.mapping.borrow()[sorted_row]
895    }
896}
897
898impl<M, S> Model for SortModel<M, S>
899where
900    M: Model + 'static,
901    S: SortHelper<M::Data>,
902{
903    type Data = M::Data;
904
905    fn row_count(&self) -> usize {
906        self.0.wrapped_model.row_count()
907    }
908
909    fn row_data(&self, row: usize) -> Option<Self::Data> {
910        self.0.build_mapping_vec();
911
912        self.0
913            .mapping
914            .borrow()
915            .get(row)
916            .and_then(|&wrapped_row| self.0.wrapped_model.row_data(wrapped_row))
917    }
918
919    fn set_row_data(&self, row: usize, data: Self::Data) {
920        let wrapped_row = self.0.mapping.borrow()[row];
921        self.0.wrapped_model.set_row_data(wrapped_row, data);
922    }
923
924    fn model_tracker(&self) -> &dyn ModelTracker {
925        &self.0.notify
926    }
927
928    fn as_any(&self) -> &dyn core::any::Any {
929        self
930    }
931}
932
933#[cfg(test)]
934mod sort_tests {
935    use super::*;
936    use std::vec;
937
938    #[test]
939    fn test_sorted_model_insert() {
940        let wrapped_rc = Rc::new(VecModel::from(std::vec![3, 4, 1, 2]));
941        let sorted_model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));
942
943        let _checker = ModelChecker::new(sorted_model.clone());
944
945        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
946        sorted_model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
947
948        assert_eq!(sorted_model.row_count(), 4);
949        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
950        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
951        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
952        assert_eq!(sorted_model.row_data(3).unwrap(), 4);
953
954        wrapped_rc.insert(0, 10);
955
956        assert_eq!(observer.added_rows.borrow().len(), 1);
957        assert!(observer.added_rows.borrow().eq(&[(4, 1)]));
958        assert!(observer.changed_rows.borrow().is_empty());
959        assert!(observer.removed_rows.borrow().is_empty());
960        assert_eq!(*observer.reset.borrow(), 0);
961        observer.clear();
962
963        assert_eq!(sorted_model.row_count(), 5);
964        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
965        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
966        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
967        assert_eq!(sorted_model.row_data(3).unwrap(), 4);
968        assert_eq!(sorted_model.row_data(4).unwrap(), 10);
969    }
970
971    #[test]
972    fn test_sorted_model_remove() {
973        let wrapped_rc = Rc::new(VecModel::from(vec![3, 4, 1, 2]));
974        let sorted_model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));
975
976        let _checker = ModelChecker::new(sorted_model.clone());
977
978        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
979        sorted_model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
980
981        assert_eq!(sorted_model.row_count(), 4);
982        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
983        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
984        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
985        assert_eq!(sorted_model.row_data(3).unwrap(), 4);
986
987        // Remove the entry with the value 4
988        wrapped_rc.remove(1);
989
990        assert!(observer.added_rows.borrow().is_empty());
991        assert!(observer.changed_rows.borrow().is_empty());
992        assert_eq!(observer.removed_rows.borrow().len(), 1);
993        assert!(observer.removed_rows.borrow().eq(&[(3, 1)]));
994        assert_eq!(*observer.reset.borrow(), 0);
995        observer.clear();
996
997        assert_eq!(sorted_model.row_count(), 3);
998        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
999        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
1000        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
1001    }
1002
1003    #[test]
1004    fn test_sorted_model_changed() {
1005        let wrapped_rc = Rc::new(VecModel::from(vec![3, 4, 1, 2]));
1006        let sorted_model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));
1007
1008        let _checker = ModelChecker::new(sorted_model.clone());
1009
1010        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1011        sorted_model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1012
1013        assert_eq!(sorted_model.row_count(), 4);
1014        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
1015        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
1016        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
1017        assert_eq!(sorted_model.row_data(3).unwrap(), 4);
1018
1019        // Change the entry with the value 4 to 10 -> maintain order
1020        wrapped_rc.set_row_data(1, 10);
1021
1022        assert!(observer.added_rows.borrow().is_empty());
1023        assert_eq!(observer.changed_rows.borrow().len(), 1);
1024        assert_eq!(*observer.changed_rows.borrow().first().unwrap(), 3);
1025        assert!(observer.removed_rows.borrow().is_empty());
1026        assert_eq!(*observer.reset.borrow(), 0);
1027        observer.clear();
1028
1029        assert_eq!(sorted_model.row_count(), 4);
1030        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
1031        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
1032        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
1033        assert_eq!(sorted_model.row_data(3).unwrap(), 10);
1034
1035        // Change the entry with the value 10 to 0 -> new order with remove and insert
1036        wrapped_rc.set_row_data(1, 0);
1037
1038        assert_eq!(observer.added_rows.borrow().len(), 1);
1039        assert!(observer.added_rows.borrow().first().unwrap().eq(&(0, 1)));
1040        assert!(observer.changed_rows.borrow().is_empty());
1041        assert_eq!(observer.removed_rows.borrow().len(), 1);
1042        assert!(observer.removed_rows.borrow().first().unwrap().eq(&(3, 1)));
1043        assert_eq!(*observer.reset.borrow(), 0);
1044        observer.clear();
1045
1046        assert_eq!(sorted_model.row_count(), 4);
1047        assert_eq!(sorted_model.row_data(0).unwrap(), 0);
1048        assert_eq!(sorted_model.row_data(1).unwrap(), 1);
1049        assert_eq!(sorted_model.row_data(2).unwrap(), 2);
1050        assert_eq!(sorted_model.row_data(3).unwrap(), 3);
1051    }
1052
1053    #[test]
1054    fn test_sorted_model_source_model() {
1055        let wrapped_rc = Rc::new(VecModel::from(vec![3, 4, 1, 2]));
1056        let model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));
1057        let _checker = ModelChecker::new(model.clone());
1058
1059        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1060        model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1061
1062        model.source_model().push(6);
1063        model.source_model().push(5);
1064
1065        let expected = &[1, 2, 3, 4, 5, 6];
1066        assert_eq!(model.row_count(), expected.len());
1067        for (i, v) in expected.iter().enumerate() {
1068            assert_eq!(model.row_data(i), Some(*v), "Expected {v} at index {i}");
1069        }
1070    }
1071}
1072
1073/// Provides a reversed view of another [`Model`].
1074///
1075/// When the other Model is updated, the `ReverseModel` is updated accordingly.
1076///
1077/// Generic parameters:
1078/// * `M` the type of the wrapped `Model`.
1079///
1080/// ## Example
1081///
1082/// Here we have a [`VecModel`] holding [`crate::SharedString`]s.
1083/// It is then reversed into a `ReverseModel`.
1084///
1085/// ```
1086/// # use slint::{Model, VecModel, SharedString, ReverseModel};
1087/// let model = VecModel::from(vec![
1088///     SharedString::from("Lorem"),
1089///     SharedString::from("ipsum"),
1090///     SharedString::from("dolor"),
1091/// ]);
1092///
1093/// let reverse_model = ReverseModel::new(model);
1094///
1095/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from("dolor"));
1096/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from("ipsum"));
1097/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from("Lorem"));
1098/// ```
1099///
1100/// Alternatively you can use the shortcut [`ModelExt::reverse`].
1101/// ```
1102/// # use slint::{Model, ModelExt, VecModel, SharedString};
1103/// let reverse_model = VecModel::from(vec![
1104///     SharedString::from("Lorem"),
1105///     SharedString::from("ipsum"),
1106///     SharedString::from("dolor"),
1107/// ]).reverse();
1108/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from("dolor"));
1109/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from("ipsum"));
1110/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from("Lorem"));
1111/// ```
1112///
1113/// If you want to modify the underlying [`VecModel`] you can give the ReverseModel a [`Rc`] of it:
1114/// ```
1115/// # use std::rc::Rc;
1116/// # use slint::{Model, VecModel, SharedString, ReverseModel};
1117/// let model = Rc::new(VecModel::from(vec![
1118///     SharedString::from("Lorem"),
1119///     SharedString::from("ipsum"),
1120///     SharedString::from("dolor"),
1121/// ]));
1122///
1123/// let reverse_model = ReverseModel::new(model.clone());
1124///
1125/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from("dolor"));
1126/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from("ipsum"));
1127/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from("Lorem"));
1128///
1129/// model.push(SharedString::from("opsom"));
1130///
1131/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from("opsom"));
1132/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from("dolor"));
1133/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from("ipsum"));
1134/// assert_eq!(reverse_model.row_data(3).unwrap(), SharedString::from("Lorem"));
1135/// ```
1136pub struct ReverseModel<M>(Pin<Box<ModelChangeListenerContainer<ReverseModelInner<M>>>>)
1137where
1138    M: Model + 'static;
1139
1140struct ReverseModelInner<M>
1141where
1142    M: Model + 'static,
1143{
1144    wrapped_model: M,
1145    notify: ModelNotify,
1146}
1147
1148impl<M> ModelChangeListener for ReverseModelInner<M>
1149where
1150    M: Model + 'static,
1151{
1152    fn row_changed(self: Pin<&Self>, row: usize) {
1153        self.notify.row_changed(self.wrapped_model.row_count() - 1 - row);
1154    }
1155
1156    fn row_added(self: Pin<&Self>, index: usize, count: usize) {
1157        let row_count = self.wrapped_model.row_count();
1158        let old_row_count = row_count - count;
1159        let index = old_row_count - index;
1160        self.notify.row_added(index, count);
1161    }
1162
1163    fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
1164        let row_count = self.wrapped_model.row_count();
1165        self.notify.row_removed(row_count - index, count);
1166    }
1167
1168    fn reset(self: Pin<&Self>) {
1169        self.notify.reset()
1170    }
1171}
1172
1173impl<M> ReverseModel<M>
1174where
1175    M: Model + 'static,
1176{
1177    /// Creates a new ReverseModel based on the given `wrapped_model`.
1178    /// Alternatively you can use [`ModelExt::reverse`] on your Model.
1179    pub fn new(wrapped_model: M) -> Self {
1180        let inner = ReverseModelInner { wrapped_model, notify: Default::default() };
1181        let container = Box::pin(ModelChangeListenerContainer::new(inner));
1182        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());
1183        Self(container)
1184    }
1185
1186    /// Returns a reference to the inner model
1187    pub fn source_model(&self) -> &M {
1188        &self.0.as_ref().get().get_ref().wrapped_model
1189    }
1190}
1191
1192impl<M> Model for ReverseModel<M>
1193where
1194    M: Model + 'static,
1195{
1196    type Data = M::Data;
1197
1198    fn row_count(&self) -> usize {
1199        self.0.wrapped_model.row_count()
1200    }
1201
1202    fn row_data(&self, row: usize) -> Option<Self::Data> {
1203        let count = self.0.wrapped_model.row_count();
1204        self.0.wrapped_model.row_data(count.checked_sub(row + 1)?)
1205    }
1206    fn set_row_data(&self, row: usize, data: Self::Data) {
1207        let count = self.0.as_ref().wrapped_model.row_count();
1208        self.0.wrapped_model.set_row_data(count - row - 1, data);
1209    }
1210
1211    fn model_tracker(&self) -> &dyn ModelTracker {
1212        &self.0.notify
1213    }
1214
1215    fn as_any(&self) -> &dyn core::any::Any {
1216        self
1217    }
1218}
1219
1220#[cfg(test)]
1221mod reversed_tests {
1222    use super::*;
1223    use std::vec;
1224
1225    #[track_caller]
1226    fn check_content(model: &ReverseModel<Rc<VecModel<i32>>>, expected: &[i32]) {
1227        assert_eq!(model.row_count(), expected.len());
1228        for (i, v) in expected.iter().enumerate() {
1229            assert_eq!(model.row_data(i), Some(*v), "Expected {v} at index {i}");
1230        }
1231    }
1232
1233    #[test]
1234    fn test_reversed_model() {
1235        let wrapped_rc = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
1236        let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
1237        let _checker = ModelChecker::new(model.clone());
1238
1239        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1240        model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1241
1242        check_content(&model, &[4, 3, 2, 1]);
1243    }
1244
1245    #[test]
1246    fn test_reversed_model_insert() {
1247        for (idx, mapped_idx) in [(0, 4), (1, 3), (2, 2), (3, 1), (4, 0)] {
1248            std::println!("Inserting at {idx} expecting mapped to {mapped_idx}");
1249            let wrapped_rc = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
1250            let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
1251            let _checker = ModelChecker::new(model.clone());
1252
1253            let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1254            model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1255
1256            wrapped_rc.insert(idx, 10);
1257
1258            assert_eq!(observer.added_rows.borrow().len(), 1);
1259            assert!(
1260                observer.added_rows.borrow().eq(&[(mapped_idx, 1)]),
1261                "Added rows: {:?}",
1262                observer.added_rows.borrow()
1263            );
1264            assert!(observer.changed_rows.borrow().is_empty());
1265            assert!(observer.removed_rows.borrow().is_empty());
1266            assert_eq!(*observer.reset.borrow(), 0);
1267            assert_eq!(model.row_data(mapped_idx), Some(10));
1268        }
1269    }
1270
1271    #[test]
1272    fn test_reversed_model_remove() {
1273        for (idx, mapped_idx) in [(0, 3), (1, 2), (2, 1), (3, 0)] {
1274            std::println!("Removing at {idx} expecting mapped to {mapped_idx}");
1275            let wrapped_rc = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
1276            let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
1277            let _checker = ModelChecker::new(model.clone());
1278
1279            let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1280            model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1281
1282            wrapped_rc.remove(idx);
1283
1284            assert_eq!(observer.removed_rows.borrow().len(), 1);
1285            assert!(
1286                observer.removed_rows.borrow().eq(&[(mapped_idx, 1)]),
1287                "Remove rows: {:?}",
1288                observer.removed_rows.borrow()
1289            );
1290            assert!(observer.added_rows.borrow().is_empty());
1291            assert!(observer.changed_rows.borrow().is_empty());
1292            assert_eq!(*observer.reset.borrow(), 0);
1293        }
1294    }
1295
1296    #[test]
1297    fn test_reversed_model_changed() {
1298        for (idx, mapped_idx) in [(0, 3), (1, 2), (2, 1), (3, 0)] {
1299            std::println!("Changing at {idx} expecting mapped to {mapped_idx}");
1300            let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3, 4]));
1301            let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
1302            let _checker = ModelChecker::new(model.clone());
1303
1304            let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1305            model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1306
1307            wrapped_rc.set_row_data(idx, 10);
1308
1309            assert_eq!(observer.changed_rows.borrow().len(), 1);
1310            assert!(
1311                observer.changed_rows.borrow().eq(&[mapped_idx]),
1312                "Changed rows: {:?}",
1313                observer.changed_rows.borrow()
1314            );
1315            assert!(observer.added_rows.borrow().is_empty());
1316            assert!(observer.removed_rows.borrow().is_empty());
1317            assert_eq!(*observer.reset.borrow(), 0);
1318            assert_eq!(model.row_data(mapped_idx), Some(10));
1319        }
1320    }
1321
1322    #[test]
1323    fn test_reversed_model_source_model() {
1324        let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3, 4]));
1325        let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
1326        let _checker = ModelChecker::new(model.clone());
1327
1328        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1329        model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1330
1331        model.source_model().push(5);
1332
1333        check_content(&model, &[5, 4, 3, 2, 1]);
1334    }
1335}
1336
1337#[test]
1338fn test_long_chain_integrity() {
1339    use alloc::string::ToString;
1340    let origin_model = Rc::new(VecModel::from((0..100).collect::<Vec<_>>()));
1341    let checker1 = ModelChecker::new(origin_model.clone());
1342    let fizzbuzz = Rc::new(MapModel::new(origin_model.clone(), |number| {
1343        if (number % 3) == 0 && (number % 5) == 0 {
1344            "FizzBuzz".to_string()
1345        } else if (number % 3) == 0 {
1346            "Fizz".to_string()
1347        } else if (number % 5) == 0 {
1348            "Buzz".to_string()
1349        } else {
1350            number.to_string()
1351        }
1352    }));
1353    let checker2 = ModelChecker::new(fizzbuzz.clone());
1354    let filter = Rc::new(FilterModel::new(fizzbuzz, |s| s != "FizzBuzz"));
1355    let checker3 = ModelChecker::new(filter.clone());
1356    let reverse = Rc::new(ReverseModel::new(filter));
1357    let checker4 = ModelChecker::new(reverse.clone());
1358    let sorted = Rc::new(SortModel::new_ascending(reverse));
1359    let checker5 = ModelChecker::new(sorted.clone());
1360    let filter2 = Rc::new(FilterModel::new(sorted, |s| s != "Fizz"));
1361    let checker6 = ModelChecker::new(filter2.clone());
1362
1363    let check_all = || {
1364        checker1.check();
1365        checker2.check();
1366        checker3.check();
1367        checker4.check();
1368        checker5.check();
1369        checker6.check();
1370    };
1371
1372    origin_model.extend(50..150);
1373    check_all();
1374    origin_model.insert(8, 1000);
1375    check_all();
1376    origin_model.remove(9);
1377    check_all();
1378    origin_model.remove(10);
1379    origin_model.remove(11);
1380    origin_model.set_row_data(55, 10001);
1381    check_all();
1382    origin_model.set_row_data(58, 10002);
1383    origin_model.set_row_data(59, 10003);
1384    origin_model.remove(28);
1385    origin_model.remove(29);
1386    origin_model.insert(100, 8888);
1387    origin_model.remove(30);
1388    origin_model.set_row_data(60, 10004);
1389    origin_model.remove(130);
1390    origin_model.set_row_data(61, 10005);
1391    origin_model.remove(131);
1392    check_all();
1393    origin_model.remove(12);
1394    origin_model.remove(13);
1395    origin_model.remove(14);
1396    origin_model.set_row_data(62, 10006);
1397    origin_model.set_row_data(63, 10007);
1398    origin_model.set_row_data(64, 10008);
1399    origin_model.set_row_data(65, 10009);
1400    check_all();
1401
1402    // Since VecModel don't have this as public API, just add some function that use row_removed on a wider range.
1403    trait RemoveRange {
1404        fn remove_range(&self, range: core::ops::Range<usize>);
1405    }
1406    impl<T> RemoveRange for VecModel<T> {
1407        fn remove_range(&self, range: core::ops::Range<usize>) {
1408            self.array.borrow_mut().drain(range.clone());
1409            self.notify.row_removed(range.start, range.len())
1410        }
1411    }
1412
1413    origin_model.remove_range(25..110);
1414    check_all();
1415
1416    origin_model.extend(900..910);
1417    origin_model.set_row_data(45, 44444);
1418    origin_model.remove_range(10..30);
1419    origin_model.insert(45, 3000);
1420    origin_model.insert(45, 3001);
1421    origin_model.insert(45, 3002);
1422    origin_model.insert(45, 3003);
1423    origin_model.insert(45, 3004);
1424    origin_model.insert(45, 3006);
1425    origin_model.insert(45, 3007);
1426    check_all();
1427}