ferroui_dynamic_data/kernel/
internal_ex.rs1use ferroui_reactive::concurrency::{IScheduler, SchedulerExt};
7use ferroui_reactive::disposables::Disposable;
8use ferroui_reactive::{Observable, ObservableExt};
9use ferroui_system::{IDisposable, IObservable, IObserver, ObservableError};
10use std::rc::Rc;
11use std::time::Duration;
12
13type BackOffStrategy<E> = Rc<dyn Fn(&E, usize) -> Option<Duration>>;
14
15fn retry<T: 'static, E: std::error::Error + 'static>(source: Rc<dyn IObservable<T>>, back_off_strategy: BackOffStrategy<E>, failure_count: usize) -> Rc<dyn IObservable<T>> {
16 let retried = source.clone();
17 source.catch_of::<E>(move |error: ObservableError| {
18 let typed = error.downcast_ref::<E>().expect("catch_of hands over the errors of its type");
19 match back_off_strategy(typed, failure_count) {
20 None => Observable::throw::<T>(error),
21 Some(delay) => {
22 let next = retry(retried.clone(), back_off_strategy.clone(), failure_count + 1);
23 Observable::timer(delay).select_many(move |_| next.clone())
24 }
25 }
26 })
27}
28
29pub fn retry_with_back_off<T: 'static, E: std::error::Error + 'static>(
33 source: Rc<dyn IObservable<T>>,
34 back_off_strategy: impl Fn(&E, usize) -> Option<Duration> + 'static,
35) -> Rc<dyn IObservable<T>> {
36 retry(source, Rc::new(back_off_strategy), 0)
37}
38
39pub fn schedule_recurring_action(scheduler: &Rc<dyn IScheduler>, interval: Duration, action: impl Fn() + 'static) -> Rc<dyn IDisposable> {
42 scheduler.schedule_recursive_after(interval, move |schedule_next: &dyn Fn(Duration)| {
43 action();
44 schedule_next(interval);
45 })
46}
47
48pub fn schedule_recurring_action_with(scheduler: &Rc<dyn IScheduler>, interval: impl Fn() -> Duration + 'static, action: impl Fn() + 'static) -> Rc<dyn IDisposable> {
51 let first = interval();
52 scheduler.schedule_recursive_after(first, move |schedule_next: &dyn Fn(Duration)| {
53 action();
54 schedule_next(interval());
55 })
56}
57
58pub fn to_unit<T: 'static>(source: &Rc<dyn IObservable<T>>) -> Rc<dyn IObservable<()>> {
60 source.select(|_| ())
61}
62
63pub(crate) fn return_with<T: 'static>(source: impl Fn() -> T + 'static) -> Rc<dyn IObservable<T>> {
66 Observable::create(move |observer: Rc<dyn IObserver<T>>| {
67 observer.on_next(source());
68 observer.on_completed();
69 Disposable::empty()
70 })
71}
72
73pub(crate) fn dotnet_binary_search<I, S>(list: &[I], value: &S, comparer: impl Fn(&I, &S) -> std::cmp::Ordering) -> Result<usize, usize> {
77 let (mut lower, mut upper) = (0isize, list.len() as isize - 1);
78 while lower <= upper {
79 let middle = lower + ((upper - lower) >> 1);
80 match comparer(&list[middle as usize], value) {
81 std::cmp::Ordering::Equal => return Ok(middle as usize),
82 std::cmp::Ordering::Less => lower = middle + 1,
83 std::cmp::Ordering::Greater => upper = middle - 1,
84 }
85 }
86 Err(lower as usize)
87}