Skip to main content

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