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