1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//! `TransformAsync` (`List/ObservableListEx.TransformAsync.cs`).
//!
//! Each item in the form that a future gives it, at the same position. The change sets are handled
//! one after another, and the change set of the transformed items is emitted when every future of
//! its change set has ended; an error of a future ends the sequence. The disposal of the
//! subscription cancels the token of the futures in flight.
//!
//! Deviation (DEVIATIONS.md, DynamicData): upstream's factory returns a `Task<TDestination>`; here
//! it returns a future of `Result<TDestination, ObservableError>`, which runs as a task of the
//! thread (docs/porting/reactive.md, section 5.8), and takes its arguments by value, so that the
//! future owns them. The overloads are named as those of `transform`: each takes
//! `bool transformOnRefresh = false`; the plain factory has a form with the flag
//! (`transform_async_with`), as do the factory of the item, the value it had and its index
//! (`transform_async_with_previous_and_index`) and the one that also takes the token
//! (`transform_async_with_token`); the others use `false`.
macro_rules! transform_async_methods {
() => {
/// Each item in the form the future of `transform_factory` gives it, at the same position:
/// an addition or a replacement awaits the factory, a refresh is forwarded, and removals and
/// moves apply to the transformed items
/// (`TransformAsync(Func<TSource, Task<TDestination>>, bool transformOnRefresh = false)`).
fn transform_async<U: Clone + PartialEq + 'static, Fut: std::future::Future<Output = Result<U, ferroui_system::ObservableError>> + 'static>(
&self,
transform_factory: impl Fn(T) -> Fut + 'static,
) -> std::rc::Rc<dyn ferroui_system::IObservable<crate::list::ChangeSet<U>>> {
self.transform_async_with(transform_factory, false)
}
/// [`transform_async`](Self::transform_async) that, when `transform_on_refresh` is true,
/// transforms a refreshed item again and emits a replacement
/// (`TransformAsync(Func<TSource, Task<TDestination>>, bool transformOnRefresh)`).
fn transform_async_with<U: Clone + PartialEq + 'static, Fut: std::future::Future<Output = Result<U, ferroui_system::ObservableError>> + 'static>(
&self,
transform_factory: impl Fn(T) -> Fut + 'static,
transform_on_refresh: bool,
) -> std::rc::Rc<dyn ferroui_system::IObservable<crate::list::ChangeSet<U>>> {
crate::list::internal::transform_async(
self.change_sets(),
crate::list::internal::list_async_transform_factory(move |item: T, _previous: Option<U>, _index: usize, _token: ferroui_system::threading::CancellationToken| transform_factory(item)),
transform_on_refresh,
)
}
/// [`transform_async`](Self::transform_async) with a factory of the item and its index
/// (`TransformAsync(Func<TSource, int, Task<TDestination>>, bool transformOnRefresh = false)`).
fn transform_async_with_index<U: Clone + PartialEq + 'static, Fut: std::future::Future<Output = Result<U, ferroui_system::ObservableError>> + 'static>(
&self,
transform_factory: impl Fn(T, usize) -> Fut + 'static,
) -> std::rc::Rc<dyn ferroui_system::IObservable<crate::list::ChangeSet<U>>> {
crate::list::internal::transform_async(
self.change_sets(),
crate::list::internal::list_async_transform_factory(move |item: T, _previous: Option<U>, index: usize, _token: ferroui_system::threading::CancellationToken| transform_factory(item, index)),
false,
)
}
/// [`transform_async`](Self::transform_async) with a factory of the item and the value it
/// had (for a replacement, or a refresh that transforms)
/// (`TransformAsync(Func<TSource, Optional<TDestination>, Task<TDestination>>, bool transformOnRefresh = false)`).
fn transform_async_with_previous<U: Clone + PartialEq + 'static, Fut: std::future::Future<Output = Result<U, ferroui_system::ObservableError>> + 'static>(
&self,
transform_factory: impl Fn(T, Option<U>) -> Fut + 'static,
) -> std::rc::Rc<dyn ferroui_system::IObservable<crate::list::ChangeSet<U>>> {
crate::list::internal::transform_async(
self.change_sets(),
crate::list::internal::list_async_transform_factory(move |item: T, previous: Option<U>, _index: usize, _token: ferroui_system::threading::CancellationToken| transform_factory(item, previous)),
false,
)
}
/// [`transform_async`](Self::transform_async) with a factory of the item, the value it had
/// and its index, and the flag of [`transform_async_with`](Self::transform_async_with)
/// (`TransformAsync(Func<TSource, Optional<TDestination>, int, Task<TDestination>>, bool transformOnRefresh)`).
fn transform_async_with_previous_and_index<U: Clone + PartialEq + 'static, Fut: std::future::Future<Output = Result<U, ferroui_system::ObservableError>> + 'static>(
&self,
transform_factory: impl Fn(T, Option<U>, usize) -> Fut + 'static,
transform_on_refresh: bool,
) -> std::rc::Rc<dyn ferroui_system::IObservable<crate::list::ChangeSet<U>>> {
crate::list::internal::transform_async(
self.change_sets(),
crate::list::internal::list_async_transform_factory(move |item: T, previous: Option<U>, index: usize, _token: ferroui_system::threading::CancellationToken| {
transform_factory(item, previous, index)
}),
transform_on_refresh,
)
}
/// [`transform_async_with_previous_and_index`](Self::transform_async_with_previous_and_index)
/// whose factory also takes the token that the disposal of the subscription cancels
/// (`TransformAsync(Func<TSource, Optional<TDestination>, int, CancellationToken, Task<TDestination>>, bool transformOnRefresh)`).
fn transform_async_with_token<U: Clone + PartialEq + 'static, Fut: std::future::Future<Output = Result<U, ferroui_system::ObservableError>> + 'static>(
&self,
transform_factory: impl Fn(T, Option<U>, usize, ferroui_system::threading::CancellationToken) -> Fut + 'static,
transform_on_refresh: bool,
) -> std::rc::Rc<dyn ferroui_system::IObservable<crate::list::ChangeSet<U>>> {
crate::list::internal::transform_async(self.change_sets(), crate::list::internal::list_async_transform_factory(transform_factory), transform_on_refresh)
}
};
}
pub(crate) use transform_async_methods;