use ferroui_reactive::disposables::Disposable;
use ferroui_system::threading::tasks::{Task, TaskCanceledError};
use ferroui_system::{IDisposable, IObservable, IObserver, ObservableError};
use std::rc::Rc;
pub struct TaskObservable<T> {
task: Task<T>,
}
impl<T: Clone + 'static> TaskObservable<T> {
pub fn new(task: Task<T>) -> Rc<Self> {
Rc::new(Self { task })
}
}
impl<T: Clone + 'static> IObservable<T> for TaskObservable<T> {
fn subscribe(&self, observer: Rc<dyn IObserver<T>>) -> Rc<dyn IDisposable> {
subscribe(&self.task, observer)
}
}
pub(crate) fn subscribe<T: Clone + 'static>(task: &Task<T>, observer: Rc<dyn IObserver<T>>) -> Rc<dyn IDisposable> {
let forward = move |completed: &Task<T>| {
if completed.is_canceled() {
observer.on_error(Rc::new(TaskCanceledError { task_id: Some(completed.id()) }) as ObservableError);
return;
}
match completed.result() {
Ok(value) => {
observer.on_next(value);
observer.on_completed();
}
Err(error) => observer.on_error(error),
}
};
let _ = task.continue_with(forward);
Disposable::empty()
}