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        for row in self.mapping.borrow_mut().iter_mut() {
725            if *row >= index {
726                *row += count;
727            }
728        }
729
730        for row in index..(index + count) {
731            let insertion_index = if let Some(added_data) = self.wrapped_model.row_data(row) {
732                self.mapping.borrow().partition_point(|existing_row| {
733                    self.wrapped_model.row_data(*existing_row).is_some_and(|existing| {
734                        self.sort_helper.borrow_mut().cmp(&existing, &added_data)
735                            == core::cmp::Ordering::Less
736                    })
737                })
738            } else {
739                self.mapping.borrow().len()
740            };
741            self.mapping.borrow_mut().insert(insertion_index, row);
742            self.notify.row_added(insertion_index, 1)
743        }
744    }
745
746    fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
747        if count == 0 {
748            return;
749        }
750
751        if self.sorted_rows_dirty.get() {
752            self.reset();
753            return;
754        }
755
756        let mut removed_rows = Vec::new();
757
758        let mut i = 0;
759
760        loop {
761            if i >= self.mapping.borrow().len() {
762                break;
763            }
764
765            let sort_index = self.mapping.borrow()[i];
766
767            if sort_index >= index {
768                if sort_index < index + count {
769                    removed_rows.push(i);
770                    self.mapping.borrow_mut().remove(i);
771                    continue;
772                } else {
773                    self.mapping.borrow_mut()[i] -= count;
774                }
775            }
776
777            i += 1;
778        }
779
780        for removed_row in removed_rows {
781            self.notify.row_removed(removed_row, 1);
782        }
783    }
784
785    fn reset(self: Pin<&Self>) {
786        self.sorted_rows_dirty.set(true);
787        self.notify.reset();
788    }
789}
790
791/// Provides a sorted view of rows by another [`Model`].
792///
793/// When the other Model is updated, the `Sorted` is updated accordingly.
794///
795/// Generic parameters:
796/// * `M` the type of the wrapped `Model`.
797/// * `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.
798///
799/// ## Example
800///
801/// Here we have a [`VecModel`] holding [`crate::SharedString`]s.
802/// It is then sorted into a `SortModel`.
803///
804/// ```
805/// # use slint::{Model, VecModel, SharedString, SortModel};
806/// let model = VecModel::from(vec![
807///     SharedString::from("Lorem"),
808///     SharedString::from("ipsum"),
809///     SharedString::from("dolor"),
810/// ]);
811///
812/// let sorted_model = SortModel::new(model, |lhs, rhs| lhs.to_lowercase().cmp(&rhs.to_lowercase()));
813///
814/// assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from("dolor"));
815/// assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from("ipsum"));
816/// assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from("Lorem"));
817/// ```
818///
819/// Alternatively you can use the shortcut [`ModelExt::sort_by`].
820/// ```
821/// # use slint::{Model, ModelExt, VecModel, SharedString, SortModel};
822/// let sorted_model = VecModel::from(vec![
823///     SharedString::from("Lorem"),
824///     SharedString::from("ipsum"),
825///     SharedString::from("dolor"),
826/// ]).sort_by(|lhs, rhs| lhs.to_lowercase().cmp(&rhs.to_lowercase()));
827/// # assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from("dolor"));
828/// # assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from("ipsum"));
829/// # assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from("Lorem"));
830/// ```
831///
832/// It is also possible to get a ascending sorted  `SortModel` order for `core::cmp::Ord` type items.
833///
834/// ```
835/// # use slint::{Model, VecModel, SortModel};
836/// let model = VecModel::from(vec![
837///     5,
838///     1,
839///     3,
840/// ]);
841///
842/// let sorted_model = SortModel::new_ascending(model);
843///
844/// assert_eq!(sorted_model.row_data(0).unwrap(), 1);
845/// assert_eq!(sorted_model.row_data(1).unwrap(), 3);
846/// assert_eq!(sorted_model.row_data(2).unwrap(), 5);
847/// ```
848///
849/// Alternatively you can use the shortcut [`ModelExt::sort`].
850/// ```
851/// # use slint::{Model, ModelExt, VecModel, SharedString, SortModel};
852/// let sorted_model = VecModel::from(vec![
853///     5,
854///     1,
855///     3,
856/// ]).sort();
857/// # assert_eq!(sorted_model.row_data(0).unwrap(), 1);
858/// # assert_eq!(sorted_model.row_data(1).unwrap(), 3);
859/// # assert_eq!(sorted_model.row_data(2).unwrap(), 5);
860/// ```
861///
862/// If you want to modify the underlying [`VecModel`] you can give it a [`Rc`] of the SortModel:
863/// ```
864/// # use std::rc::Rc;
865/// # use slint::{Model, VecModel, SharedString, SortModel};
866/// let model = Rc::new(VecModel::from(vec![
867///     SharedString::from("Lorem"),
868///     SharedString::from("ipsum"),
869///     SharedString::from("dolor"),
870/// ]));
871///
872/// let sorted_model = SortModel::new(model.clone(), |lhs, rhs| lhs.to_lowercase().cmp(&rhs.to_lowercase()));
873///
874/// assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from("dolor"));
875/// assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from("ipsum"));
876/// assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from("Lorem"));
877///
878/// model.set_row_data(1, SharedString::from("opsom"));
879///
880/// assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from("dolor"));
881/// assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from("Lorem"));
882/// assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from("opsom"));
883/// ```
884pub struct SortModel<M, F>(ModelChangeListenerBox<SortModelInner<M, F>>)
885where
886    M: Model + 'static,
887    F: SortHelper<M::Data> + 'static;
888
889impl<M, F> SortModel<M, F>
890where
891    M: Model + 'static,
892    F: FnMut(&M::Data, &M::Data) -> core::cmp::Ordering + 'static,
893{
894    /// Creates a new SortModel based on the given `wrapped_model` and sorted by `sort_function`.
895    /// Alternatively you can use [`ModelExt::sort_by`] on your Model.
896    pub fn new(wrapped_model: M, sort_function: F) -> Self
897    where
898        F: FnMut(&M::Data, &M::Data) -> core::cmp::Ordering + 'static,
899    {
900        let sorted_model_inner = SortModelInner {
901            wrapped_model,
902            sort_helper: RefCell::new(sort_function),
903            mapping: RefCell::new(Vec::new()),
904            notify: Default::default(),
905            sorted_rows_dirty: Cell::new(true),
906        };
907
908        let container = ModelChangeListenerBox::new(sorted_model_inner);
909
910        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());
911
912        Self(container)
913    }
914}
915
916impl<M> SortModel<M, AscendingSortHelper>
917where
918    M: Model + 'static,
919    M::Data: core::cmp::Ord,
920{
921    /// Creates a new SortModel based on the given `wrapped_model` and sorted in ascending order.
922    /// Alternatively you can use [`ModelExt::sort`] on your Model.
923    pub fn new_ascending(wrapped_model: M) -> Self
924    where
925        M::Data: core::cmp::Ord,
926    {
927        let sorted_model_inner = SortModelInner {
928            wrapped_model,
929            sort_helper: RefCell::new(AscendingSortHelper),
930            mapping: RefCell::new(Vec::new()),
931            notify: Default::default(),
932            sorted_rows_dirty: Cell::new(true),
933        };
934
935        let container = ModelChangeListenerBox::new(sorted_model_inner);
936
937        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());
938
939        Self(container)
940    }
941}
942
943impl<M, S> SortModel<M, S>
944where
945    M: Model + 'static,
946    S: SortHelper<M::Data>,
947{
948    /// Returns a reference to the inner model
949    pub fn source_model(&self) -> &M {
950        &self.0.as_ref().get().get_ref().wrapped_model
951    }
952
953    /// Manually reapply the sorting. You need to run this e.g. if the sort function depends
954    /// on mutable state and it has changed.
955    pub fn reset(&self) {
956        self.0.as_ref().get().reset();
957    }
958
959    /// Gets the row index of the underlying unsorted model for a given sorted row index.
960    pub fn unsorted_row(&self, sorted_row: usize) -> usize {
961        self.0.build_mapping_vec();
962        self.0.mapping.borrow()[sorted_row]
963    }
964}
965
966impl<M, S> Model for SortModel<M, S>
967where
968    M: Model + 'static,
969    S: SortHelper<M::Data>,
970{
971    type Data = M::Data;
972
973    fn row_count(&self) -> usize {
974        self.0.wrapped_model.row_count()
975    }
976
977    fn row_data(&self, row: usize) -> Option<Self::Data> {
978        self.0.build_mapping_vec();
979
980        self.0
981            .mapping
982            .borrow()
983            .get(row)
984            .and_then(|&wrapped_row| self.0.wrapped_model.row_data(wrapped_row))
985    }
986
987    fn set_row_data(&self, row: usize, data: Self::Data) {
988        let wrapped_row = self.0.mapping.borrow()[row];
989        self.0.wrapped_model.set_row_data(wrapped_row, data);
990    }
991
992    fn model_tracker(&self) -> &dyn ModelTracker {
993        &self.0.notify
994    }
995
996    fn as_any(&self) -> &dyn core::any::Any {
997        self
998    }
999}
1000
1001#[cfg(test)]
1002mod sort_tests {
1003    use super::*;
1004    use std::vec;
1005    use tests_helper::*;
1006
1007    #[test]
1008    fn test_sorted_model_insert() {
1009        let wrapped_rc = Rc::new(VecModel::from(std::vec![3, 4, 1, 2]));
1010        let sorted_model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));
1011
1012        let _checker = ModelChecker::new(sorted_model.clone());
1013
1014        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1015        sorted_model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1016
1017        assert_eq!(sorted_model.row_count(), 4);
1018        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
1019        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
1020        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
1021        assert_eq!(sorted_model.row_data(3).unwrap(), 4);
1022
1023        wrapped_rc.insert(0, 10);
1024
1025        assert_eq!(observer.added_rows.borrow().len(), 1);
1026        assert!(observer.added_rows.borrow().eq(&[(4, 1)]));
1027        assert!(observer.changed_rows.borrow().is_empty());
1028        assert!(observer.removed_rows.borrow().is_empty());
1029        assert_eq!(*observer.reset.borrow(), 0);
1030        observer.clear();
1031
1032        assert_eq!(sorted_model.row_count(), 5);
1033        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
1034        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
1035        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
1036        assert_eq!(sorted_model.row_data(3).unwrap(), 4);
1037        assert_eq!(sorted_model.row_data(4).unwrap(), 10);
1038    }
1039
1040    #[test]
1041    fn test_sorted_model_remove() {
1042        let wrapped_rc = Rc::new(VecModel::from(vec![3, 4, 1, 2]));
1043        let sorted_model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));
1044
1045        let _checker = ModelChecker::new(sorted_model.clone());
1046
1047        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1048        sorted_model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1049
1050        assert_eq!(sorted_model.row_count(), 4);
1051        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
1052        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
1053        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
1054        assert_eq!(sorted_model.row_data(3).unwrap(), 4);
1055
1056        // Remove the entry with the value 4
1057        wrapped_rc.remove(1);
1058
1059        assert!(observer.added_rows.borrow().is_empty());
1060        assert!(observer.changed_rows.borrow().is_empty());
1061        assert_eq!(observer.removed_rows.borrow().len(), 1);
1062        assert!(observer.removed_rows.borrow().eq(&[(3, 1)]));
1063        assert_eq!(*observer.reset.borrow(), 0);
1064        observer.clear();
1065
1066        assert_eq!(sorted_model.row_count(), 3);
1067        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
1068        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
1069        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
1070    }
1071
1072    #[test]
1073    fn test_sorted_model_changed() {
1074        let wrapped_rc = Rc::new(VecModel::from(vec![3, 4, 1, 2]));
1075        let sorted_model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));
1076
1077        let _checker = ModelChecker::new(sorted_model.clone());
1078
1079        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1080        sorted_model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1081
1082        assert_eq!(sorted_model.row_count(), 4);
1083        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
1084        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
1085        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
1086        assert_eq!(sorted_model.row_data(3).unwrap(), 4);
1087
1088        // Change the entry with the value 4 to 10 -> maintain order
1089        wrapped_rc.set_row_data(1, 10);
1090
1091        assert!(observer.added_rows.borrow().is_empty());
1092        assert_eq!(observer.changed_rows.borrow().len(), 1);
1093        assert_eq!(*observer.changed_rows.borrow().first().unwrap(), 3);
1094        assert!(observer.removed_rows.borrow().is_empty());
1095        assert_eq!(*observer.reset.borrow(), 0);
1096        observer.clear();
1097
1098        assert_eq!(sorted_model.row_count(), 4);
1099        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
1100        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
1101        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
1102        assert_eq!(sorted_model.row_data(3).unwrap(), 10);
1103
1104        // Change the entry with the value 10 to 0 -> new order with remove and insert
1105        wrapped_rc.set_row_data(1, 0);
1106
1107        assert_eq!(observer.added_rows.borrow().len(), 1);
1108        assert!(observer.added_rows.borrow().first().unwrap().eq(&(0, 1)));
1109        assert!(observer.changed_rows.borrow().is_empty());
1110        assert_eq!(observer.removed_rows.borrow().len(), 1);
1111        assert!(observer.removed_rows.borrow().first().unwrap().eq(&(3, 1)));
1112        assert_eq!(*observer.reset.borrow(), 0);
1113        observer.clear();
1114
1115        assert_eq!(sorted_model.row_count(), 4);
1116        assert_eq!(sorted_model.row_data(0).unwrap(), 0);
1117        assert_eq!(sorted_model.row_data(1).unwrap(), 1);
1118        assert_eq!(sorted_model.row_data(2).unwrap(), 2);
1119        assert_eq!(sorted_model.row_data(3).unwrap(), 3);
1120    }
1121
1122    #[test]
1123    fn test_sorted_model_source_model() {
1124        let wrapped_rc = Rc::new(VecModel::from(vec![3, 4, 1, 2]));
1125        let model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));
1126        let _checker = ModelChecker::new(model.clone());
1127
1128        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1129        model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1130
1131        model.source_model().push(6);
1132        model.source_model().push(5);
1133
1134        let expected = &[1, 2, 3, 4, 5, 6];
1135        assert_eq!(model.row_count(), expected.len());
1136        for (i, v) in expected.iter().enumerate() {
1137            assert_eq!(model.row_data(i), Some(*v), "Expected {v} at index {i}");
1138        }
1139
1140        assert!(Rc::ptr_eq(model.source_model(), &wrapped_rc));
1141        model.reset();
1142        assert_eq!(*observer.reset.borrow(), 1);
1143    }
1144
1145    #[test]
1146    fn test_sorted_broken_model() {
1147        let wrapped_rc = BrokenModel::new(std::vec![
1148            Some("1"),
1149            Some("2"),
1150            None,
1151            Some("4"),
1152            None,
1153            Some("3"),
1154            Some("0"),
1155            Some("5")
1156        ]);
1157        let model = Rc::new(SortModel::new_ascending(wrapped_rc.clone()));
1158
1159        assert_eq!(model.row_count(), 8);
1160        assert_eq!(model.row_data(0), Some("0"));
1161        assert_eq!(model.row_data(1), Some("1"));
1162        assert_eq!(model.row_data(2), Some("2"));
1163        assert_eq!(model.row_data(3), Some("3"));
1164        assert_eq!(model.row_data(4), Some("4"));
1165        assert_eq!(model.row_data(5), Some("5"));
1166        assert_eq!(model.row_data(6), None);
1167        assert_eq!(model.row_data(7), None);
1168
1169        wrapped_rc.notify.row_removed(2, 2);
1170        wrapped_rc.notify.row_added(2, 2);
1171        wrapped_rc.data.borrow_mut()[1] = None;
1172        wrapped_rc.notify.row_changed(1);
1173        wrapped_rc.data.borrow_mut()[2] = Some("a");
1174        wrapped_rc.notify.row_changed(2);
1175
1176        assert_eq!(model.row_count(), 8);
1177        assert_eq!(model.row_data(0), Some("0"));
1178        assert_eq!(model.row_data(1), Some("1"));
1179        assert_eq!(model.row_data(2), Some("3"));
1180        assert_eq!(model.row_data(3), Some("4"));
1181        assert_eq!(model.row_data(4), Some("5"));
1182        assert_eq!(model.row_data(5), Some("a"));
1183        assert_eq!(model.row_data(6), None);
1184        assert_eq!(model.row_data(7), None);
1185
1186        assert!(Rc::ptr_eq(model.source_model(), &wrapped_rc));
1187    }
1188}
1189
1190/// Provides a reversed view of another [`Model`].
1191///
1192/// When the other Model is updated, the `ReverseModel` is updated accordingly.
1193///
1194/// Generic parameters:
1195/// * `M` the type of the wrapped `Model`.
1196///
1197/// ## Example
1198///
1199/// Here we have a [`VecModel`] holding [`crate::SharedString`]s.
1200/// It is then reversed into a `ReverseModel`.
1201///
1202/// ```
1203/// # use slint::{Model, VecModel, SharedString, ReverseModel};
1204/// let model = VecModel::from(vec![
1205///     SharedString::from("Lorem"),
1206///     SharedString::from("ipsum"),
1207///     SharedString::from("dolor"),
1208/// ]);
1209///
1210/// let reverse_model = ReverseModel::new(model);
1211///
1212/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from("dolor"));
1213/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from("ipsum"));
1214/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from("Lorem"));
1215/// ```
1216///
1217/// Alternatively you can use the shortcut [`ModelExt::reverse`].
1218/// ```
1219/// # use slint::{Model, ModelExt, VecModel, SharedString};
1220/// let reverse_model = VecModel::from(vec![
1221///     SharedString::from("Lorem"),
1222///     SharedString::from("ipsum"),
1223///     SharedString::from("dolor"),
1224/// ]).reverse();
1225/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from("dolor"));
1226/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from("ipsum"));
1227/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from("Lorem"));
1228/// ```
1229///
1230/// If you want to modify the underlying [`VecModel`] you can give the ReverseModel a [`Rc`] of it:
1231/// ```
1232/// # use std::rc::Rc;
1233/// # use slint::{Model, VecModel, SharedString, ReverseModel};
1234/// let model = Rc::new(VecModel::from(vec![
1235///     SharedString::from("Lorem"),
1236///     SharedString::from("ipsum"),
1237///     SharedString::from("dolor"),
1238/// ]));
1239///
1240/// let reverse_model = ReverseModel::new(model.clone());
1241///
1242/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from("dolor"));
1243/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from("ipsum"));
1244/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from("Lorem"));
1245///
1246/// model.push(SharedString::from("opsom"));
1247///
1248/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from("opsom"));
1249/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from("dolor"));
1250/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from("ipsum"));
1251/// assert_eq!(reverse_model.row_data(3).unwrap(), SharedString::from("Lorem"));
1252/// ```
1253pub struct ReverseModel<M>(ModelChangeListenerBox<ReverseModelInner<M>>)
1254where
1255    M: Model + 'static;
1256
1257struct ReverseModelInner<M>
1258where
1259    M: Model + 'static,
1260{
1261    wrapped_model: M,
1262    notify: ModelNotify,
1263}
1264
1265impl<M> ModelChangeListener for ReverseModelInner<M>
1266where
1267    M: Model + 'static,
1268{
1269    fn row_changed(self: Pin<&Self>, row: usize) {
1270        self.notify.row_changed(self.wrapped_model.row_count() - 1 - row);
1271    }
1272
1273    fn row_added(self: Pin<&Self>, index: usize, count: usize) {
1274        let row_count = self.wrapped_model.row_count();
1275        let old_row_count = row_count - count;
1276        let index = old_row_count - index;
1277        self.notify.row_added(index, count);
1278    }
1279
1280    fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
1281        let row_count = self.wrapped_model.row_count();
1282        self.notify.row_removed(row_count - index, count);
1283    }
1284
1285    fn reset(self: Pin<&Self>) {
1286        self.notify.reset()
1287    }
1288}
1289
1290impl<M> ReverseModel<M>
1291where
1292    M: Model + 'static,
1293{
1294    /// Creates a new ReverseModel based on the given `wrapped_model`.
1295    /// Alternatively you can use [`ModelExt::reverse`] on your Model.
1296    pub fn new(wrapped_model: M) -> Self {
1297        let inner = ReverseModelInner { wrapped_model, notify: Default::default() };
1298        let container = ModelChangeListenerBox::new(inner);
1299        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());
1300        Self(container)
1301    }
1302
1303    /// Returns a reference to the inner model
1304    pub fn source_model(&self) -> &M {
1305        &self.0.as_ref().get().get_ref().wrapped_model
1306    }
1307}
1308
1309impl<M> Model for ReverseModel<M>
1310where
1311    M: Model + 'static,
1312{
1313    type Data = M::Data;
1314
1315    fn row_count(&self) -> usize {
1316        self.0.wrapped_model.row_count()
1317    }
1318
1319    fn row_data(&self, row: usize) -> Option<Self::Data> {
1320        let count = self.0.wrapped_model.row_count();
1321        self.0.wrapped_model.row_data(count.checked_sub(row + 1)?)
1322    }
1323    fn set_row_data(&self, row: usize, data: Self::Data) {
1324        let count = self.0.as_ref().wrapped_model.row_count();
1325        self.0.wrapped_model.set_row_data(count - row - 1, data);
1326    }
1327
1328    fn model_tracker(&self) -> &dyn ModelTracker {
1329        &self.0.notify
1330    }
1331
1332    fn as_any(&self) -> &dyn core::any::Any {
1333        self
1334    }
1335}
1336
1337#[cfg(test)]
1338mod reversed_tests {
1339    use super::*;
1340    use std::vec;
1341    use tests_helper::*;
1342
1343    #[track_caller]
1344    fn check_content(model: &ReverseModel<Rc<VecModel<i32>>>, expected: &[i32]) {
1345        assert_eq!(model.row_count(), expected.len());
1346        for (i, v) in expected.iter().enumerate() {
1347            assert_eq!(model.row_data(i), Some(*v), "Expected {v} at index {i}");
1348        }
1349    }
1350
1351    #[test]
1352    fn test_reversed_model() {
1353        let wrapped_rc = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
1354        let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
1355        let _checker = ModelChecker::new(model.clone());
1356
1357        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1358        model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1359
1360        check_content(&model, &[4, 3, 2, 1]);
1361    }
1362
1363    #[test]
1364    fn test_reversed_model_insert() {
1365        for (idx, mapped_idx) in [(0, 4), (1, 3), (2, 2), (3, 1), (4, 0)] {
1366            std::println!("Inserting at {idx} expecting mapped to {mapped_idx}");
1367            let wrapped_rc = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
1368            let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
1369            let _checker = ModelChecker::new(model.clone());
1370
1371            let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1372            model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1373
1374            wrapped_rc.insert(idx, 10);
1375
1376            assert_eq!(observer.added_rows.borrow().len(), 1);
1377            assert!(
1378                observer.added_rows.borrow().eq(&[(mapped_idx, 1)]),
1379                "Added rows: {:?}",
1380                observer.added_rows.borrow()
1381            );
1382            assert!(observer.changed_rows.borrow().is_empty());
1383            assert!(observer.removed_rows.borrow().is_empty());
1384            assert_eq!(*observer.reset.borrow(), 0);
1385            assert_eq!(model.row_data(mapped_idx), Some(10));
1386        }
1387    }
1388
1389    #[test]
1390    fn test_reversed_model_remove() {
1391        for (idx, mapped_idx) in [(0, 3), (1, 2), (2, 1), (3, 0)] {
1392            std::println!("Removing at {idx} expecting mapped to {mapped_idx}");
1393            let wrapped_rc = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
1394            let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
1395            let _checker = ModelChecker::new(model.clone());
1396
1397            let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1398            model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1399
1400            wrapped_rc.remove(idx);
1401
1402            assert_eq!(observer.removed_rows.borrow().len(), 1);
1403            assert!(
1404                observer.removed_rows.borrow().eq(&[(mapped_idx, 1)]),
1405                "Remove rows: {:?}",
1406                observer.removed_rows.borrow()
1407            );
1408            assert!(observer.added_rows.borrow().is_empty());
1409            assert!(observer.changed_rows.borrow().is_empty());
1410            assert_eq!(*observer.reset.borrow(), 0);
1411        }
1412    }
1413
1414    #[test]
1415    fn test_reversed_model_changed() {
1416        for (idx, mapped_idx) in [(0, 3), (1, 2), (2, 1), (3, 0)] {
1417            std::println!("Changing at {idx} expecting mapped to {mapped_idx}");
1418            let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3, 4]));
1419            let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
1420            let _checker = ModelChecker::new(model.clone());
1421
1422            let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1423            model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1424
1425            wrapped_rc.set_row_data(idx, 10);
1426
1427            assert_eq!(observer.changed_rows.borrow().len(), 1);
1428            assert!(
1429                observer.changed_rows.borrow().eq(&[mapped_idx]),
1430                "Changed rows: {:?}",
1431                observer.changed_rows.borrow()
1432            );
1433            assert!(observer.added_rows.borrow().is_empty());
1434            assert!(observer.removed_rows.borrow().is_empty());
1435            assert_eq!(*observer.reset.borrow(), 0);
1436            assert_eq!(model.row_data(mapped_idx), Some(10));
1437        }
1438    }
1439
1440    #[test]
1441    fn test_reversed_model_source_model() {
1442        let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3, 4]));
1443        let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
1444        let _checker = ModelChecker::new(model.clone());
1445
1446        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1447        model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());
1448
1449        model.source_model().push(5);
1450
1451        check_content(&model, &[5, 4, 3, 2, 1]);
1452    }
1453
1454    #[test]
1455    fn test_reversed_broken_model() {
1456        let wrapped_rc = BrokenModel::new(std::vec![Some("1"), Some("2"), None, Some("4")]);
1457        let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
1458
1459        wrapped_rc.notify.row_added(1, 3);
1460
1461        assert_eq!(model.row_count(), 4);
1462        assert_eq!(model.row_data(0), Some("4"));
1463        assert_eq!(model.row_data(1), None);
1464        assert_eq!(model.row_data(2), Some("2"));
1465        assert_eq!(model.row_data(3), Some("1"));
1466    }
1467}
1468
1469#[test]
1470fn test_long_chain_integrity() {
1471    use alloc::string::ToString;
1472    use tests_helper::*;
1473    let origin_model = Rc::new(VecModel::from((0..100).collect::<Vec<_>>()));
1474    let checker1 = ModelChecker::new(origin_model.clone());
1475    let fizzbuzz = Rc::new(MapModel::new(origin_model.clone(), |number| {
1476        if (number % 3) == 0 && (number % 5) == 0 {
1477            "FizzBuzz".to_string()
1478        } else if (number % 3) == 0 {
1479            "Fizz".to_string()
1480        } else if (number % 5) == 0 {
1481            "Buzz".to_string()
1482        } else {
1483            number.to_string()
1484        }
1485    }));
1486    let checker2 = ModelChecker::new(fizzbuzz.clone());
1487    let filter = Rc::new(FilterModel::new(fizzbuzz, |s| s != "FizzBuzz"));
1488    let checker3 = ModelChecker::new(filter.clone());
1489    let reverse = Rc::new(ReverseModel::new(filter));
1490    let checker4 = ModelChecker::new(reverse.clone());
1491    let sorted = Rc::new(SortModel::new_ascending(reverse));
1492    let checker5 = ModelChecker::new(sorted.clone());
1493    let filter2 = Rc::new(FilterModel::new(sorted, |s| s != "Fizz"));
1494    let checker6 = ModelChecker::new(filter2.clone());
1495
1496    let check_all = || {
1497        checker1.check();
1498        checker2.check();
1499        checker3.check();
1500        checker4.check();
1501        checker5.check();
1502        checker6.check();
1503    };
1504
1505    origin_model.extend(50..150);
1506    check_all();
1507    origin_model.insert(8, 1000);
1508    check_all();
1509    origin_model.remove(9);
1510    check_all();
1511    origin_model.remove(10);
1512    origin_model.remove(11);
1513    origin_model.set_row_data(55, 10001);
1514    check_all();
1515    origin_model.set_row_data(58, 10002);
1516    origin_model.set_row_data(59, 10003);
1517    origin_model.remove(28);
1518    origin_model.remove(29);
1519    origin_model.insert(100, 8888);
1520    origin_model.remove(30);
1521    origin_model.set_row_data(60, 10004);
1522    origin_model.remove(130);
1523    origin_model.set_row_data(61, 10005);
1524    origin_model.remove(131);
1525    check_all();
1526    origin_model.remove(12);
1527    origin_model.remove(13);
1528    origin_model.remove(14);
1529    origin_model.set_row_data(62, 10006);
1530    origin_model.set_row_data(63, 10007);
1531    origin_model.set_row_data(64, 10008);
1532    origin_model.set_row_data(65, 10009);
1533    check_all();
1534
1535    // Since VecModel don't have this as public API, just add some function that use row_removed on a wider range.
1536    trait RemoveRange {
1537        fn remove_range(&self, range: core::ops::Range<usize>);
1538    }
1539    impl<T> RemoveRange for VecModel<T> {
1540        fn remove_range(&self, range: core::ops::Range<usize>) {
1541            self.array.borrow_mut().drain(range.clone());
1542            self.notify.row_removed(range.start, range.len())
1543        }
1544    }
1545
1546    origin_model.remove_range(25..110);
1547    check_all();
1548
1549    origin_model.extend(900..910);
1550    origin_model.set_row_data(45, 44444);
1551    origin_model.remove_range(10..30);
1552    origin_model.insert(45, 3000);
1553    origin_model.insert(45, 3001);
1554    origin_model.insert(45, 3002);
1555    origin_model.insert(45, 3003);
1556    origin_model.insert(45, 3004);
1557    origin_model.insert(45, 3006);
1558    origin_model.insert(45, 3007);
1559    check_all();
1560}