Skip to main content

ferroui_dynamic_data/list/
testing.rs

1//! The aids for tests that DynamicData ships with the library (`List/Tests`, namespace
2//! `DynamicData.Tests`): `ChangeSetAggregator<TObject>`.
3
4use super::{ChangeSet, IObservableList, ObservableList, ObservableListEx};
5use ferroui_reactive::disposables::Disposable;
6use ferroui_reactive::ObservableExt;
7use ferroui_system::{IDisposable, IObservable, ObservableError};
8use std::cell::{Cell, RefCell};
9use std::rc::Rc;
10
11struct State<T> {
12    messages: RefCell<Vec<ChangeSet<T>>>,
13    error: RefCell<Option<ObservableError>>,
14    is_completed: Cell<bool>,
15}
16
17/// Records what a sequence of change sets of a list produces (`ChangeSetAggregator<TObject>`).
18pub struct ChangeSetAggregator<T> {
19    state: Rc<State<T>>,
20    data: ObservableList<T>,
21    disposer: Rc<dyn IDisposable>,
22}
23
24impl<T: Clone + PartialEq + 'static> ChangeSetAggregator<T> {
25    /// Subscribes to `source` (`ChangeSetAggregator(IObservable<IChangeSet<TObject>>)`).
26    pub fn new(source: Rc<dyn IObservable<ChangeSet<T>>>) -> Self {
27        let state = Rc::new(State { messages: RefCell::new(Vec::new()), error: RefCell::new(None), is_completed: Cell::new(false) });
28        let published = source.publish();
29        let published_source: Rc<dyn IObservable<ChangeSet<T>>> = published.clone();
30        let data = published_source.as_observable_list();
31        let (on_next, on_error, on_completed) = (state.clone(), state.clone(), state.clone());
32        let results = published_source.subscribe_all(
33            move |changes| on_next.messages.borrow_mut().push(changes),
34            move |error| *on_error.error.borrow_mut() = Some(error),
35            move || on_completed.is_completed.set(true),
36        );
37        let connected = published.connect();
38        let list = data.clone();
39        let disposer = Disposable::create(move || {
40            list.dispose();
41            connected.dispose();
42            results.dispose();
43        });
44        Self { state, data, disposer }
45    }
46
47    /// The items the change sets make (`Data`).
48    pub fn data(&self) -> &ObservableList<T> {
49        &self.data
50    }
51
52    /// The change sets so far (`Messages`).
53    pub fn messages(&self) -> Vec<ChangeSet<T>> {
54        self.state.messages.borrow().clone()
55    }
56
57    /// The error of the sequence (`Exception`).
58    pub fn error(&self) -> Option<ObservableError> {
59        self.state.error.borrow().clone()
60    }
61
62    /// Whether the sequence has ended (`IsCompleted`).
63    pub fn is_completed(&self) -> bool {
64        self.state.is_completed.get()
65    }
66
67    /// The number of items the change sets make.
68    pub fn count(&self) -> usize {
69        self.data.count()
70    }
71}
72
73impl<T> IDisposable for ChangeSetAggregator<T> {
74    fn dispose(&self) {
75        self.disposer.dispose();
76    }
77}
78
79impl<T> Drop for ChangeSetAggregator<T> {
80    fn drop(&mut self) {
81        self.disposer.dispose();
82    }
83}