i_slint_core/model/
adapters.rs

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