use super::{
cache_aggregate, list_aggregate, AggregateChangeSets, AggregateNumber, AggregateType, AggregateValue, IAggregateChangeSet, MaxOrMin, StdDevValue,
};
use crate::cache::ObservableCacheEx;
use crate::list::ObservableListEx;
use ferroui_reactive::ObservableExt;
use ferroui_system::IObservable;
use std::hash::Hash;
use std::rc::Rc;
pub(crate) fn accumulate<T: 'static, R: Clone + 'static>(
source: AggregateChangeSets<T>,
seed: R,
accessor: impl Fn(&T) -> R + 'static,
add_action: impl Fn(R, R) -> R + 'static,
remove_action: impl Fn(R, R) -> R + 'static,
) -> Rc<dyn IObservable<R>> {
source.scan_with(seed, move |state: R, changes: Rc<dyn IAggregateChangeSet<T>>| {
changes.items().fold(state, |current, aggregate_item| match aggregate_item.aggregate_type() {
AggregateType::Add => add_action(current, accessor(aggregate_item.item())),
AggregateType::Remove => remove_action(current, accessor(aggregate_item.item())),
})
})
}
pub trait AggregationCacheEx<T: Clone + 'static, K: Eq + Hash + Clone + 'static> {
fn for_aggregation(&self) -> AggregateChangeSets<T>;
fn avg<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static) -> Rc<dyn IObservable<<V::Number as AggregateNumber>::Average>>;
fn avg_with<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static, empty_value: V::Number) -> Rc<dyn IObservable<<V::Number as AggregateNumber>::Average>>;
fn count_cache(&self) -> Rc<dyn IObservable<usize>>;
fn is_empty_cache(&self) -> Rc<dyn IObservable<bool>>;
fn is_not_empty(&self) -> Rc<dyn IObservable<bool>>;
fn maximum<R: Copy + PartialOrd + Default + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static) -> Rc<dyn IObservable<R>>;
fn maximum_with<R: Copy + PartialOrd + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static, empty_value: R) -> Rc<dyn IObservable<R>>;
fn minimum<R: Copy + PartialOrd + Default + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static) -> Rc<dyn IObservable<R>>;
fn minimum_with<R: Copy + PartialOrd + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static, empty_value: R) -> Rc<dyn IObservable<R>>;
fn std_dev<V: StdDevValue>(&self, value_selector: impl Fn(&T) -> V + 'static, fallback_value: V) -> Rc<dyn IObservable<f64>>;
fn sum_cache<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static) -> Rc<dyn IObservable<V::Number>>;
}
impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static, C: crate::cache::IChangeSet<T, K>> AggregationCacheEx<T, K> for Rc<dyn IObservable<C>> {
fn for_aggregation(&self) -> AggregateChangeSets<T> {
ObservableCacheEx::<T, K>::change_sets(self).select(cache_aggregate::<T, K>)
}
fn avg<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static) -> Rc<dyn IObservable<<V::Number as AggregateNumber>::Average>> {
AggregationCacheEx::<T, K>::avg_with(self, value_selector, <V::Number as AggregateNumber>::ZERO)
}
fn avg_with<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static, empty_value: V::Number) -> Rc<dyn IObservable<<V::Number as AggregateNumber>::Average>> {
super::avg_ex::avg(AggregationCacheEx::<T, K>::for_aggregation(self), value_selector, empty_value)
}
fn count_cache(&self) -> Rc<dyn IObservable<usize>> {
super::count_ex::count(AggregationCacheEx::<T, K>::for_aggregation(self))
}
fn is_empty_cache(&self) -> Rc<dyn IObservable<bool>> {
super::count_ex::is_empty(AggregationCacheEx::<T, K>::for_aggregation(self))
}
fn is_not_empty(&self) -> Rc<dyn IObservable<bool>> {
super::count_ex::is_not_empty(AggregationCacheEx::<T, K>::for_aggregation(self))
}
fn maximum<R: Copy + PartialOrd + Default + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static) -> Rc<dyn IObservable<R>> {
AggregationCacheEx::<T, K>::maximum_with(self, value_selector, R::default())
}
fn maximum_with<R: Copy + PartialOrd + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static, empty_value: R) -> Rc<dyn IObservable<R>> {
let source = super::max_ex::cache_changes_and_collection(ObservableCacheEx::<T, K>::change_sets(self));
super::max_ex::calculate(source, Rc::new(value_selector), MaxOrMin::Max, empty_value)
}
fn minimum<R: Copy + PartialOrd + Default + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static) -> Rc<dyn IObservable<R>> {
AggregationCacheEx::<T, K>::minimum_with(self, value_selector, R::default())
}
fn minimum_with<R: Copy + PartialOrd + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static, empty_value: R) -> Rc<dyn IObservable<R>> {
let source = super::max_ex::cache_changes_and_collection(ObservableCacheEx::<T, K>::change_sets(self));
super::max_ex::calculate(source, Rc::new(value_selector), MaxOrMin::Min, empty_value)
}
fn std_dev<V: StdDevValue>(&self, value_selector: impl Fn(&T) -> V + 'static, fallback_value: V) -> Rc<dyn IObservable<f64>> {
super::std_dev_ex::std_dev(AggregationCacheEx::<T, K>::for_aggregation(self), value_selector, fallback_value)
}
fn sum_cache<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static) -> Rc<dyn IObservable<V::Number>> {
super::sum_ex::sum(AggregationCacheEx::<T, K>::for_aggregation(self), value_selector)
}
}
pub trait AggregationListEx<T: Clone + PartialEq + 'static> {
fn for_aggregation(&self) -> AggregateChangeSets<T>;
fn avg<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static) -> Rc<dyn IObservable<<V::Number as AggregateNumber>::Average>>;
fn avg_with<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static, empty_value: V::Number) -> Rc<dyn IObservable<<V::Number as AggregateNumber>::Average>>;
fn count_list(&self) -> Rc<dyn IObservable<usize>>;
fn is_empty_list(&self) -> Rc<dyn IObservable<bool>>;
fn is_not_empty(&self) -> Rc<dyn IObservable<bool>>;
fn maximum<R: Copy + PartialOrd + Default + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static) -> Rc<dyn IObservable<R>>;
fn maximum_with<R: Copy + PartialOrd + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static, empty_value: R) -> Rc<dyn IObservable<R>>;
fn minimum<R: Copy + PartialOrd + Default + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static) -> Rc<dyn IObservable<R>>;
fn minimum_with<R: Copy + PartialOrd + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static, empty_value: R) -> Rc<dyn IObservable<R>>;
fn std_dev<V: StdDevValue>(&self, value_selector: impl Fn(&T) -> V + 'static, fallback_value: V) -> Rc<dyn IObservable<f64>>;
fn sum_list<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static) -> Rc<dyn IObservable<V::Number>>;
}
impl<T: Clone + PartialEq + 'static, C: crate::list::IChangeSet<T>> AggregationListEx<T> for Rc<dyn IObservable<C>> {
fn for_aggregation(&self) -> AggregateChangeSets<T> {
ObservableListEx::<T>::change_sets(self).select(list_aggregate::<T>)
}
fn avg<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static) -> Rc<dyn IObservable<<V::Number as AggregateNumber>::Average>> {
AggregationListEx::<T>::avg_with(self, value_selector, <V::Number as AggregateNumber>::ZERO)
}
fn avg_with<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static, empty_value: V::Number) -> Rc<dyn IObservable<<V::Number as AggregateNumber>::Average>> {
super::avg_ex::avg(AggregationListEx::<T>::for_aggregation(self), value_selector, empty_value)
}
fn count_list(&self) -> Rc<dyn IObservable<usize>> {
super::count_ex::count(AggregationListEx::<T>::for_aggregation(self))
}
fn is_empty_list(&self) -> Rc<dyn IObservable<bool>> {
super::count_ex::is_empty(AggregationListEx::<T>::for_aggregation(self))
}
fn is_not_empty(&self) -> Rc<dyn IObservable<bool>> {
super::count_ex::is_not_empty(AggregationListEx::<T>::for_aggregation(self))
}
fn maximum<R: Copy + PartialOrd + Default + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static) -> Rc<dyn IObservable<R>> {
AggregationListEx::<T>::maximum_with(self, value_selector, R::default())
}
fn maximum_with<R: Copy + PartialOrd + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static, empty_value: R) -> Rc<dyn IObservable<R>> {
let source = super::max_ex::list_changes_and_collection(ObservableListEx::<T>::change_sets(self));
super::max_ex::calculate(source, Rc::new(value_selector), MaxOrMin::Max, empty_value)
}
fn minimum<R: Copy + PartialOrd + Default + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static) -> Rc<dyn IObservable<R>> {
AggregationListEx::<T>::minimum_with(self, value_selector, R::default())
}
fn minimum_with<R: Copy + PartialOrd + 'static>(&self, value_selector: impl Fn(&T) -> R + 'static, empty_value: R) -> Rc<dyn IObservable<R>> {
let source = super::max_ex::list_changes_and_collection(ObservableListEx::<T>::change_sets(self));
super::max_ex::calculate(source, Rc::new(value_selector), MaxOrMin::Min, empty_value)
}
fn std_dev<V: StdDevValue>(&self, value_selector: impl Fn(&T) -> V + 'static, fallback_value: V) -> Rc<dyn IObservable<f64>> {
super::std_dev_ex::std_dev(AggregationListEx::<T>::for_aggregation(self), value_selector, fallback_value)
}
fn sum_list<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static) -> Rc<dyn IObservable<V::Number>> {
super::sum_ex::sum(AggregationListEx::<T>::for_aggregation(self), value_selector)
}
}
pub trait AggregateChangeSetEx<T: 'static> {
fn avg<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static) -> Rc<dyn IObservable<<V::Number as AggregateNumber>::Average>>;
fn avg_with<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static, empty_value: V::Number) -> Rc<dyn IObservable<<V::Number as AggregateNumber>::Average>>;
fn count_aggregate(&self) -> Rc<dyn IObservable<usize>>;
fn std_dev<V: StdDevValue>(&self, value_selector: impl Fn(&T) -> V + 'static, fallback_value: V) -> Rc<dyn IObservable<f64>>;
fn sum_aggregate<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static) -> Rc<dyn IObservable<V::Number>>;
}
impl<T: 'static> AggregateChangeSetEx<T> for AggregateChangeSets<T> {
fn avg<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static) -> Rc<dyn IObservable<<V::Number as AggregateNumber>::Average>> {
AggregateChangeSetEx::<T>::avg_with(self, value_selector, <V::Number as AggregateNumber>::ZERO)
}
fn avg_with<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static, empty_value: V::Number) -> Rc<dyn IObservable<<V::Number as AggregateNumber>::Average>> {
super::avg_ex::avg(self.clone(), value_selector, empty_value)
}
fn count_aggregate(&self) -> Rc<dyn IObservable<usize>> {
super::count_ex::count(self.clone())
}
fn std_dev<V: StdDevValue>(&self, value_selector: impl Fn(&T) -> V + 'static, fallback_value: V) -> Rc<dyn IObservable<f64>> {
super::std_dev_ex::std_dev(self.clone(), value_selector, fallback_value)
}
fn sum_aggregate<V: AggregateValue>(&self, value_selector: impl Fn(&T) -> V + 'static) -> Rc<dyn IObservable<V::Number>> {
super::sum_ex::sum(self.clone(), value_selector)
}
}
pub trait InvalidateWhenEx<T> {
fn invalidate_when<U: 'static>(&self, invalidate: Rc<dyn IObservable<U>>) -> Rc<dyn IObservable<T>>;
}
impl<T: Clone + PartialEq + 'static> InvalidateWhenEx<T> for Rc<dyn IObservable<T>> {
fn invalidate_when<U: 'static>(&self, invalidate: Rc<dyn IObservable<U>>) -> Rc<dyn IObservable<T>> {
let source = self.clone();
invalidate
.select(|_: U| ())
.start_with([()])
.select(move |_: ()| source.clone())
.switch::<T>()
.distinct_until_changed()
}
}