Skip to main content

rx_rust/operators/creating/
from_try_future.rs

1use crate::utils::types::MaybeSend;
2use crate::{
3    observable::{Observable, Subscription},
4    observer::{Observer, Termination},
5    scheduler::Scheduler,
6};
7use educe::Educe;
8
9/// Converts a `Future` of a `Result` into an Observable.
10/// See <https://reactivex.io/documentation/operators/from.html>
11///
12/// An `Ok` is emitted as the single item, and the Observable then completes; an `Err` terminates it
13/// with that error. This is how a one-shot result, the `Single` of ReactiveX, enters a pipeline.
14/// A future that cannot fail goes through
15/// [`FromFuture`](crate::operators::creating::from_future::FromFuture) instead.
16///
17/// # Examples
18/// ```rust
19/// # #[cfg(not(feature = "tokio-scheduler"))]
20/// # fn main() {}
21/// # #[cfg(feature = "tokio-scheduler")]
22/// #[tokio::main]
23/// async fn main() {
24///     use rx_rust::{
25///         observable::ObservableExt,
26///         observer::Termination,
27///         operators::creating::from_try_future::FromTryFuture,
28///     };
29///     use std::sync::{Arc, Mutex};
30///     use tokio::time::{sleep, Duration};
31///
32///     let values = Arc::new(Mutex::new(Vec::new()));
33///     let terminations = Arc::new(Mutex::new(Vec::new()));
34///     let values_observer = Arc::clone(&values);
35///     let terminations_observer = Arc::clone(&terminations);
36///     let handle = tokio::runtime::Handle::current();
37///
38///     let subscription = FromTryFuture::new(async { Err::<i32, _>("boom") }, handle)
39///         .subscribe_with_callback(
40///             move |value| values_observer.lock().unwrap().push(value),
41///             move |termination| terminations_observer
42///                 .lock()
43///                 .unwrap()
44///                 .push(termination),
45///         );
46///
47///     sleep(Duration::from_millis(10)).await;
48///     drop(subscription);
49///
50///     assert!(values.lock().unwrap().is_empty());
51///     assert_eq!(
52///         &*terminations.lock().unwrap(),
53///         &[Termination::Error("boom")]
54///     );
55/// }
56/// ```
57#[derive(Educe)]
58#[educe(Debug, Clone)]
59pub struct FromTryFuture<FU, S> {
60    future: FU,
61    scheduler: S,
62}
63
64impl<FU, S> FromTryFuture<FU, S> {
65    pub fn new(future: FU, scheduler: S) -> Self {
66        Self { future, scheduler }
67    }
68}
69
70impl<T, E, FU, S> Observable<'static, T, E> for FromTryFuture<FU, S>
71where
72    FU: Future<Output = Result<T, E>> + MaybeSend + 'static,
73    S: Scheduler,
74{
75    type D = S::D;
76
77    fn subscribe(
78        self,
79        mut observer: impl Observer<T, E> + MaybeSend + 'static,
80    ) -> Subscription<Self::D> {
81        self.scheduler.spawn_future(async {
82            match self.future.await {
83                Ok(value) => {
84                    if observer.on_next(value).is_continue() {
85                        observer.on_termination(Termination::Completed);
86                    }
87                }
88                Err(error) => observer.on_termination(Termination::Error(error)),
89            }
90        })
91    }
92}