use super::combined_reactive_command::CombinedReactiveCommand;
use super::reactive_command_t_param_t_result::{ExecutionSource, ReactiveCommand};
use super::IReactiveCommandOf;
use crate::internal::task_observable::TaskObservable;
use crate::mixins::observable_mixins::{from_async_with_all_notifications, from_async_with_all_notifications_param, AsyncExecution};
use crate::primitives::start_signal::StartSignal;
use crate::RxSchedulers;
use ferroui_reactive::concurrency::{IScheduler, ImmediateScheduler};
use ferroui_reactive::ObservableExt;
use ferroui_system::threading::tasks::Task;
use ferroui_system::threading::CancellationToken;
use ferroui_system::{IObservable, ObservableError};
use std::future::Future;
use std::rc::Rc;
pub type OptionalCanExecute = Option<Rc<dyn IObservable<bool>>>;
pub type OptionalScheduler = Option<Rc<dyn IScheduler>>;
fn cancellable_source<R: 'static>(executions: Rc<dyn IObservable<AsyncExecution<R>>>) -> Rc<dyn IObservable<ExecutionSource<R>>> {
executions.select(|(result, cancel)| {
let source: ExecutionSource<R> = (result, Some(cancel));
source
})
}
impl ReactiveCommand<(), ()> {
pub fn create<R: Clone + 'static>(execute: impl Fn() -> R + 'static) -> ReactiveCommand<(), R> {
Self::create_with(execute, None, None)
}
pub fn create_with<R: Clone + 'static>(
execute: impl Fn() -> R + 'static,
can_execute: OptionalCanExecute,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<(), R> {
Self::try_create_with(move || Ok(execute()), can_execute, output_scheduler)
}
pub fn try_create<R: Clone + 'static>(execute: impl Fn() -> Result<R, ObservableError> + 'static) -> ReactiveCommand<(), R> {
Self::try_create_with(execute, None, None)
}
pub fn try_create_with<R: Clone + 'static>(
execute: impl Fn() -> Result<R, ObservableError> + 'static,
can_execute: OptionalCanExecute,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<(), R> {
let execute = Rc::new(execute);
ReactiveCommand::from_observable(
move |_: ()| {
let execute = execute.clone();
let source: Rc<dyn IObservable<R>> = StartSignal::new(move || execute(), ImmediateScheduler::instance());
Ok(source)
},
can_execute,
output_scheduler,
)
}
pub fn create_param<P: Clone + Default + 'static, R: Clone + 'static>(execute: impl Fn(P) -> R + 'static) -> ReactiveCommand<P, R> {
Self::create_param_with(execute, None, None)
}
pub fn create_param_with<P: Clone + Default + 'static, R: Clone + 'static>(
execute: impl Fn(P) -> R + 'static,
can_execute: OptionalCanExecute,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<P, R> {
Self::try_create_param_with(move |parameter| Ok(execute(parameter)), can_execute, output_scheduler)
}
pub fn try_create_param<P: Clone + Default + 'static, R: Clone + 'static>(
execute: impl Fn(P) -> Result<R, ObservableError> + 'static,
) -> ReactiveCommand<P, R> {
Self::try_create_param_with(execute, None, None)
}
pub fn try_create_param_with<P: Clone + Default + 'static, R: Clone + 'static>(
execute: impl Fn(P) -> Result<R, ObservableError> + 'static,
can_execute: OptionalCanExecute,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<P, R> {
let execute = Rc::new(execute);
ReactiveCommand::from_observable(
move |parameter: P| {
let execute = execute.clone();
let source: Rc<dyn IObservable<R>> = StartSignal::new(move || execute(parameter.clone()), ImmediateScheduler::instance());
Ok(source)
},
can_execute,
output_scheduler,
)
}
pub fn create_run_in_background<R: Clone + 'static>(execute: impl Fn() -> R + 'static) -> ReactiveCommand<(), R> {
Self::create_run_in_background_with(execute, None, None, None)
}
pub fn create_run_in_background_with<R: Clone + 'static>(
execute: impl Fn() -> R + 'static,
can_execute: OptionalCanExecute,
background_scheduler: OptionalScheduler,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<(), R> {
Self::try_create_run_in_background_with(move || Ok(execute()), can_execute, background_scheduler, output_scheduler)
}
pub fn try_create_run_in_background<R: Clone + 'static>(
execute: impl Fn() -> Result<R, ObservableError> + 'static,
) -> ReactiveCommand<(), R> {
Self::try_create_run_in_background_with(execute, None, None, None)
}
pub fn try_create_run_in_background_with<R: Clone + 'static>(
execute: impl Fn() -> Result<R, ObservableError> + 'static,
can_execute: OptionalCanExecute,
background_scheduler: OptionalScheduler,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<(), R> {
let execute = Rc::new(execute);
Self::create_from_observable_with(
move || {
let execute = execute.clone();
let scheduler = background_scheduler.clone().unwrap_or_else(RxSchedulers::task_pool_scheduler);
let source: Rc<dyn IObservable<R>> = StartSignal::new(move || execute(), scheduler);
source
},
can_execute,
output_scheduler,
)
}
pub fn create_run_in_background_param<P: Clone + Default + 'static, R: Clone + 'static>(
execute: impl Fn(P) -> R + 'static,
) -> ReactiveCommand<P, R> {
Self::create_run_in_background_param_with(execute, None, None, None)
}
pub fn create_run_in_background_param_with<P: Clone + Default + 'static, R: Clone + 'static>(
execute: impl Fn(P) -> R + 'static,
can_execute: OptionalCanExecute,
background_scheduler: OptionalScheduler,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<P, R> {
Self::try_create_run_in_background_param_with(
move |parameter| Ok(execute(parameter)),
can_execute,
background_scheduler,
output_scheduler,
)
}
pub fn try_create_run_in_background_param<P: Clone + Default + 'static, R: Clone + 'static>(
execute: impl Fn(P) -> Result<R, ObservableError> + 'static,
) -> ReactiveCommand<P, R> {
Self::try_create_run_in_background_param_with(execute, None, None, None)
}
pub fn try_create_run_in_background_param_with<P: Clone + Default + 'static, R: Clone + 'static>(
execute: impl Fn(P) -> Result<R, ObservableError> + 'static,
can_execute: OptionalCanExecute,
background_scheduler: OptionalScheduler,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<P, R> {
let execute = Rc::new(execute);
Self::create_from_observable_param_with(
move |parameter: P| {
let execute = execute.clone();
let scheduler = background_scheduler.clone().unwrap_or_else(RxSchedulers::task_pool_scheduler);
let source: Rc<dyn IObservable<R>> = StartSignal::new(move || execute(parameter.clone()), scheduler);
source
},
can_execute,
output_scheduler,
)
}
pub fn create_combined<P, R, C>(child_commands: impl IntoIterator<Item = C>) -> CombinedReactiveCommand<P, R>
where
P: Clone + Default + 'static,
R: Clone + 'static,
C: IReactiveCommandOf<P, R> + 'static,
{
Self::create_combined_with(child_commands, None, None)
}
pub fn create_combined_with<P, R, C>(
child_commands: impl IntoIterator<Item = C>,
can_execute: OptionalCanExecute,
output_scheduler: OptionalScheduler,
) -> CombinedReactiveCommand<P, R>
where
P: Clone + Default + 'static,
R: Clone + 'static,
C: IReactiveCommandOf<P, R> + 'static,
{
let children = child_commands.into_iter().map(|child| {
let child: Rc<dyn IReactiveCommandOf<P, R>> = Rc::new(child);
child
});
CombinedReactiveCommand::new(children, can_execute, output_scheduler)
}
pub fn create_from_observable<R: Clone + 'static>(execute: impl Fn() -> Rc<dyn IObservable<R>> + 'static) -> ReactiveCommand<(), R> {
Self::create_from_observable_with(execute, None, None)
}
pub fn create_from_observable_with<R: Clone + 'static>(
execute: impl Fn() -> Rc<dyn IObservable<R>> + 'static,
can_execute: OptionalCanExecute,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<(), R> {
Self::try_create_from_observable_with(move || Ok(execute()), can_execute, output_scheduler)
}
pub fn try_create_from_observable<R: Clone + 'static>(
execute: impl Fn() -> Result<Rc<dyn IObservable<R>>, ObservableError> + 'static,
) -> ReactiveCommand<(), R> {
Self::try_create_from_observable_with(execute, None, None)
}
pub fn try_create_from_observable_with<R: Clone + 'static>(
execute: impl Fn() -> Result<Rc<dyn IObservable<R>>, ObservableError> + 'static,
can_execute: OptionalCanExecute,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<(), R> {
ReactiveCommand::from_observable(move |_: ()| execute(), can_execute, output_scheduler)
}
pub fn create_from_observable_param<P: Clone + Default + 'static, R: Clone + 'static>(
execute: impl Fn(P) -> Rc<dyn IObservable<R>> + 'static,
) -> ReactiveCommand<P, R> {
Self::create_from_observable_param_with(execute, None, None)
}
pub fn create_from_observable_param_with<P: Clone + Default + 'static, R: Clone + 'static>(
execute: impl Fn(P) -> Rc<dyn IObservable<R>> + 'static,
can_execute: OptionalCanExecute,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<P, R> {
Self::try_create_from_observable_param_with(move |parameter| Ok(execute(parameter)), can_execute, output_scheduler)
}
pub fn try_create_from_observable_param<P: Clone + Default + 'static, R: Clone + 'static>(
execute: impl Fn(P) -> Result<Rc<dyn IObservable<R>>, ObservableError> + 'static,
) -> ReactiveCommand<P, R> {
Self::try_create_from_observable_param_with(execute, None, None)
}
pub fn try_create_from_observable_param_with<P: Clone + Default + 'static, R: Clone + 'static>(
execute: impl Fn(P) -> Result<Rc<dyn IObservable<R>>, ObservableError> + 'static,
can_execute: OptionalCanExecute,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<P, R> {
ReactiveCommand::from_observable(execute, can_execute, output_scheduler)
}
pub fn create_from_task<R: Clone + 'static, Fut: Future<Output = Result<R, ObservableError>> + 'static>(
execute: impl Fn() -> Fut + 'static,
) -> ReactiveCommand<(), R> {
Self::create_from_task_with(execute, None, None)
}
pub fn create_from_task_with<R: Clone + 'static, Fut: Future<Output = Result<R, ObservableError>> + 'static>(
execute: impl Fn() -> Fut + 'static,
can_execute: OptionalCanExecute,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<(), R> {
Self::create_from_observable_with(
move || {
let source: Rc<dyn IObservable<R>> = TaskObservable::new(Task::spawn_local(execute()));
source
},
can_execute,
output_scheduler,
)
}
pub fn create_from_task_param<P: Clone + Default + 'static, R: Clone + 'static, Fut: Future<Output = Result<R, ObservableError>> + 'static>(
execute: impl Fn(P) -> Fut + 'static,
) -> ReactiveCommand<P, R> {
Self::create_from_task_param_with(execute, None, None)
}
pub fn create_from_task_param_with<P: Clone + Default + 'static, R: Clone + 'static, Fut: Future<Output = Result<R, ObservableError>> + 'static>(
execute: impl Fn(P) -> Fut + 'static,
can_execute: OptionalCanExecute,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<P, R> {
Self::create_from_observable_param_with(
move |parameter| {
let source: Rc<dyn IObservable<R>> = TaskObservable::new(Task::spawn_local(execute(parameter)));
source
},
can_execute,
output_scheduler,
)
}
pub fn create_from_task_cancellable<R: Clone + 'static, Fut: Future<Output = Result<R, ObservableError>> + 'static>(
execute: impl Fn(CancellationToken) -> Fut + 'static,
) -> ReactiveCommand<(), R> {
Self::create_from_task_cancellable_with(execute, None, None)
}
pub fn create_from_task_cancellable_with<R: Clone + 'static, Fut: Future<Output = Result<R, ObservableError>> + 'static>(
execute: impl Fn(CancellationToken) -> Fut + 'static,
can_execute: OptionalCanExecute,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<(), R> {
let execute = Rc::new(execute);
Self::create_from_observable_cancellable(
move |_: ()| {
let execute = execute.clone();
cancellable_source(from_async_with_all_notifications(move |token| execute(token)))
},
can_execute,
output_scheduler,
)
}
pub fn create_from_task_param_cancellable<
P: Clone + Default + 'static,
R: Clone + 'static,
Fut: Future<Output = Result<R, ObservableError>> + 'static,
>(
execute: impl Fn(P, CancellationToken) -> Fut + 'static,
) -> ReactiveCommand<P, R> {
Self::create_from_task_param_cancellable_with(execute, None, None)
}
pub fn create_from_task_param_cancellable_with<
P: Clone + Default + 'static,
R: Clone + 'static,
Fut: Future<Output = Result<R, ObservableError>> + 'static,
>(
execute: impl Fn(P, CancellationToken) -> Fut + 'static,
can_execute: OptionalCanExecute,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<P, R> {
let execute = Rc::new(execute);
Self::create_from_observable_cancellable(
move |parameter: P| {
let execute = execute.clone();
cancellable_source(from_async_with_all_notifications_param(move |parameter, token| execute(parameter, token), parameter))
},
can_execute,
output_scheduler,
)
}
pub(crate) fn create_from_observable_cancellable<P: Clone + Default + 'static, R: Clone + 'static>(
execute: impl Fn(P) -> Rc<dyn IObservable<ExecutionSource<R>>> + 'static,
can_execute: OptionalCanExecute,
output_scheduler: OptionalScheduler,
) -> ReactiveCommand<P, R> {
ReactiveCommand::from_cancellable(move |parameter| Ok(execute(parameter)), can_execute, output_scheduler)
}
}