use std::convert::Infallible;
use crate::{
context::Context,
observable::{CoreObservable, ObservableType},
observer::Observer,
};
#[derive(Clone)]
pub struct FromFn<F>(pub F);
impl<F, T> ObservableType for FromFn<F>
where
F: FnOnce() -> T,
{
type Item<'a>
= T
where
Self: 'a;
type Err = Infallible;
}
impl<C, F, T> CoreObservable<C> for FromFn<F>
where
C: Context,
C::Inner: Observer<T, Infallible>,
F: FnOnce() -> T,
{
type Unsub = ();
fn subscribe(self, context: C) -> Self::Unsub {
let value = (self.0)();
let mut observer = context.into_inner();
observer.next(value);
observer.complete();
}
}
#[cfg(test)]
mod tests {
use std::{cell::RefCell, rc::Rc};
use crate::prelude::*;
#[rxrust_macro::test(local)]
async fn test_from_fn_emits_value() {
let result = Rc::new(RefCell::new(None));
let result_clone = result.clone();
Local::from_fn(|| 42).subscribe(move |v| {
*result_clone.borrow_mut() = Some(v);
});
assert_eq!(*result.borrow(), Some(42));
}
#[rxrust_macro::test(local)]
async fn test_from_fn_with_different_types() {
let string_result = Rc::new(RefCell::new(None));
let string_result_clone = string_result.clone();
Local::from_fn(|| "hello".to_string()).subscribe(move |v| {
*string_result_clone.borrow_mut() = Some(v);
});
assert_eq!(*string_result.borrow(), Some("hello".to_string()));
let bool_result = Rc::new(RefCell::new(None));
let bool_result_clone = bool_result.clone();
Local::from_fn(|| true).subscribe(move |v| {
*bool_result_clone.borrow_mut() = Some(v);
});
assert_eq!(*bool_result.borrow(), Some(true));
}
#[rxrust_macro::test(local)]
async fn test_from_fn_executes_at_subscription_time() {
let counter = Rc::new(RefCell::new(0));
let counter_clone = counter.clone();
let observable = Local::from_fn(move || {
*counter_clone.borrow_mut() += 1;
*counter_clone.borrow()
});
assert_eq!(*counter.borrow(), 0);
let result = Rc::new(RefCell::new(None));
let result_clone = result.clone();
observable.clone().subscribe(move |v| {
*result_clone.borrow_mut() = Some(v);
});
assert_eq!(*counter.borrow(), 1);
assert_eq!(*result.borrow(), Some(1));
let result2 = Rc::new(RefCell::new(None));
let result2_clone = result2.clone();
observable.clone().subscribe(move |v| {
*result2_clone.borrow_mut() = Some(v);
});
assert_eq!(*counter.borrow(), 2);
assert_eq!(*result2.borrow(), Some(2));
}
#[rxrust_macro::test]
async fn test_from_fn_with_shared_context() {
let result = std::sync::Arc::new(std::sync::Mutex::new(None));
let result_clone = result.clone();
Shared::from_fn(|| 123).subscribe(move |v| {
*result_clone.lock().unwrap() = Some(v);
});
assert_eq!(*result.lock().unwrap(), Some(123));
}
}