#![doc = include_str!("../README.MD")]
#![warn(missing_docs)]
#![deny(warnings)]
#![allow(private_bounds)]
use std::{
collections::HashMap,
fmt::{Debug, Formatter},
marker::PhantomData,
ops::Deref,
sync::{atomic::AtomicBool, Arc, Mutex, RwLock, RwLockReadGuard},
};
use ccutils::key::Key;
use linked_hash_map::LinkedHashMap;
trait ComputationValueType {
type Type: 'static + Send + Sync;
}
trait ComputationInputInterface: ComputationValueType {
type InputReaderType: InputReader<Self::Type>;
fn id(&self) -> ccutils::key::Key;
fn prepare_value(&self) -> (Self::InputReaderType, Arc<Dependency>);
}
trait InputReader<T>: Sync + Send + 'static {
type InputGuard<'a>; fn read_input<'a>(&'a self) -> Self::InputGuard<'a>;
}
impl<T> InputReader<T> for RwLock<T>
where
T: Sync + Send + 'static,
{
type InputGuard<'a> = RwLockReadGuard<'a, T>;
fn read_input<'a>(&'a self) -> Self::InputGuard<'a> {
self.read().unwrap()
}
}
impl<C, T> InputReader<T> for Arc<C>
where
C: InputReader<T>,
{
type InputGuard<'a> = C::InputGuard<'a>;
fn read_input<'a>(&'a self) -> Self::InputGuard<'a> {
self.deref().read_input()
}
}
trait VecInputGuard<C, Marker>
where
VecComputationFArgsSelector<C, Marker>: VecComputationFArgsSelectorTrait,
{
fn as_input_value<'a>(&'a self) -> VecFnArg<'a, C, Marker>;
}
trait VecInputReader<C, Marker>: Send + Sync + 'static
where
C: Send + Sync + 'static,
VecComputationFArgsSelector<C, Marker>: VecComputationFArgsSelectorTrait,
{
fn read_vec_input(&self) -> Box<dyn VecInputGuard<C, Marker> + '_>;
}
struct VecComputationFArgsSelectorTraitBridge<'b, C> {
bridge: Box<dyn Deref<Target = C> + 'b>,
}
impl<'b, C> VecInputGuard<C, DefaultVariableMarker>
for VecComputationFArgsSelectorTraitBridge<'b, C>
where
for<'c> VecComputationFArgsSelector<C, DefaultVariableMarker>:
VecComputationFArgsSelectorTrait<FArgs<'c> = &'c C>,
{
fn as_input_value<'a>(&'a self) -> VecFnArg<'a, C, DefaultVariableMarker> {
let r: &C = self.bridge.deref();
r
}
}
impl<C, T> VecInputReader<C, DefaultVariableMarker> for T
where
T: InputReader<C>,
C: Send + Sync + 'static,
for<'a> VecComputationFArgsSelector<C, DefaultVariableMarker>:
VecComputationFArgsSelectorTrait<FArgs<'a> = &'a C>,
for<'a> <T as InputReader<C>>::InputGuard<'a>: Deref<Target = C>,
{
fn read_vec_input(&self) -> Box<dyn VecInputGuard<C, DefaultVariableMarker> + '_> {
Box::new(VecComputationFArgsSelectorTraitBridge::<C> {
bridge: Box::new(self.read_input()),
})
}
}
struct Dependency {
key: Key,
dependencies: RwLock<HashMap<Key, Arc<Dependency>>>,
dependents: RwLock<HashMap<Key, Arc<Dependency>>>,
outdated: AtomicBool,
}
impl Debug for Dependency {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("")
.field("key", &self.key)
.field("dependencies", &self.dependencies)
.field("dependends count", &self.dependents.read().unwrap().len())
.finish()
}
}
impl Dependency {
fn new() -> Arc<Self> {
Arc::new(Self {
key: Key::new(),
dependencies: Default::default(),
dependents: Default::default(),
outdated: AtomicBool::new(false),
})
}
fn from_key(key: Key) -> Arc<Self> {
Arc::new(Self {
key,
dependencies: Default::default(),
dependents: Default::default(),
outdated: AtomicBool::new(false),
})
}
fn notify_all(&self) {
self.outdated
.store(true, std::sync::atomic::Ordering::Relaxed);
for (_, dep) in self.dependencies.read().unwrap().iter() {
dep.notify_all();
}
}
fn insert_dependency(&self, d: Arc<Dependency>) {
self.dependencies.write().unwrap().insert(d.key.clone(), d);
}
fn insert_dependent(&self, d: Arc<Dependency>) {
self.dependents.write().unwrap().insert(d.key.clone(), d);
}
fn remove_dependency(&self, key: Key) {
if let Some(dep) = self.dependencies.write().unwrap().remove(&key) {
dep.dependents.write().unwrap().remove(&self.key);
}
}
}
trait ComputationBuilder<T> {
type FunctorArgument<'a>;
fn prepare<'b>(
&self,
dependency: &Arc<Dependency>,
formula: impl for<'a> Fn(Self::FunctorArgument<'a>) -> T + 'b + Send + Sync,
) -> impl Fn() -> T + 'b + Send + Sync;
}
trait ComputationVecBuilder<T, Marker> {
fn prepare(
&self,
dependency: &Arc<Dependency>,
) -> LinkedHashMap<Key, Box<dyn VecInputReader<T, Marker>>>;
}
macro_rules! computation_builder {
($($type_idx: tt),*) => {
paste::paste!{
impl<'b, T, $( [<VT $type_idx>], )*> ComputationBuilder<T>
for ($(&'b [<VT $type_idx>], )*)
where
$(
[<VT $type_idx>]: ComputationInputInterface,
for<'a> <<[<VT $type_idx>] as ComputationInputInterface>::InputReaderType as InputReader
<<[<VT $type_idx>] as ComputationValueType>::Type>>::InputGuard<'a>: Deref<Target = <[<VT $type_idx>] as ComputationValueType>::Type>,
)*
{
type FunctorArgument<'a> = ( $(&'a [<VT $type_idx>]::Type, )*);
fn prepare<'c>(
&self,
dependency: &Arc<Dependency>,
formula: impl for<'a> Fn(Self::FunctorArgument<'a>) -> T + 'c + Send + Sync,
) -> impl Fn() -> T + 'c + Send + Sync {
$(
let ([<v $type_idx>], [<dep $type_idx>]) = self.$type_idx.prepare_value();
[<dep $type_idx>].insert_dependency(dependency.clone());
dependency.insert_dependent([<dep $type_idx>]);
)*
move || {
$(
let [<v $type_idx>] = [<v $type_idx>].read_input();
)*
formula(($( [<v $type_idx>].deref(), )*))
}
}
}
impl<'b, T, Marker, $( [<VT $type_idx>], )*> ComputationVecBuilder<T, Marker>
for ($(&'b [<VT $type_idx>], )*)
where
$(
[<VT $type_idx>]: ComputationInputInterface<Type = T>,
<[<VT $type_idx>] as ComputationInputInterface>::InputReaderType: VecInputReader<T, Marker>,
)*
T: Sync + Send + 'static,
VecComputationFArgsSelector<T, Marker>: VecComputationFArgsSelectorTrait,
{
fn prepare(&self,
dependency: &Arc<Dependency>) -> LinkedHashMap<Key, Box<dyn VecInputReader<T, Marker>>>
{
let mut variables: LinkedHashMap<Key, Box<dyn VecInputReader<T, Marker>>> = Default::default();
$(
let ([<v $type_idx>], [<dep $type_idx>]) = self.$type_idx.prepare_value();
let id = [<dep $type_idx>].key.clone();
[<dep $type_idx>].insert_dependency(dependency.clone());
dependency.insert_dependent([<dep $type_idx>]);
let [<v $type_idx>]: Box<dyn VecInputReader<T, Marker>> = Box::new([<v $type_idx>]);
variables.insert(id, [<v $type_idx>]);
)*
variables
}
}
impl<$( [<VT $type_idx>], )*> ComputationValueType for ($( &[<VT $type_idx>], )*)
where
$(
[<VT $type_idx>]: ComputationInputInterface,
)*
{
type Type = ($([<VT $type_idx>]::Type,)*);
}
impl<$( [<T $type_idx>], )* $([<IRT $type_idx>], )*> InputReader<($([<T $type_idx>], )*)> for ($([<IRT $type_idx>], )*)
where
$(
[<IRT $type_idx>]: InputReader<[<T $type_idx>]>,
)*
{
type InputGuard<'a> = ($([<IRT $type_idx>]::InputGuard<'a>,)*);
fn read_input<'a>(&'a self) -> Self::InputGuard<'a> {
(
$(
self.$type_idx.read_input(),
)*
)
}
}
impl<$( [<T $type_idx>], )* $( [<VT $type_idx>], )*> ComputationInputInterface for ($( &[<VT $type_idx>], )*)
where
$(
[<VT $type_idx>]: ComputationInputInterface<Type = [<T $type_idx>]>,
[<T $type_idx>]: Send + Sync + 'static,
)*
{
type InputReaderType = ($([<VT $type_idx>]::InputReaderType,)*);
fn id(&self) -> Key {
let mut v = Vec::<Key>::new();
$(
v.push(self.$type_idx.id());
)*
Key::combination(v)
}
fn prepare_value(&self) -> (Self::InputReaderType, Arc<Dependency>) {
let dependency = Dependency::from_key(self.id());
$(
let ([<input_reader $type_idx>], [<dep $type_idx>]) = self.$type_idx.prepare_value();
[<dep $type_idx>].insert_dependency(dependency.clone());
dependency.insert_dependent([<dep $type_idx>]);
)*
(($([<input_reader $type_idx>], )*), dependency)
}
}
impl<$( [<T $type_idx>], )*> VecComputationFArgsSelectorTrait
for VecComputationFArgsSelector<($( [<T $type_idx>], )*), markers::GroupedVariables>
where
$(
[<T $type_idx>]: 'static,
)*
{
type FArgs<'a> = ($(&'a [<T $type_idx>],)*);
}
impl<'b, $( [<T $type_idx>], )* $( [<IG $type_idx>], )*> VecInputGuard<($( [<T $type_idx>], )*), markers::GroupedVariables>
for ($( [<IG $type_idx>], )*)
where
$(
[<T $type_idx>]: 'static,
[<IG $type_idx>]: Deref<Target = [<T $type_idx>]>,
)*
{
fn as_input_value<'a>(&'a self) -> VecFnArg<'a, ($( [<T $type_idx>], )*), markers::GroupedVariables> {
($(self.$type_idx.deref(), )*)
}
}
impl<$( [<T $type_idx>], )* $([<IRT $type_idx>], )*> VecInputReader<($( [<T $type_idx>], )*), markers::GroupedVariables> for ($([<IRT $type_idx>], )*)
where
$(
[<T $type_idx>]: Send + Sync + 'static,
[<IRT $type_idx>]: InputReader<[<T $type_idx>]>,
for<'a> <[<IRT $type_idx>] as InputReader<[<T $type_idx>]>>::InputGuard<'a>: Deref<Target = [<T $type_idx>]>,
)*
{
fn read_vec_input(&self) -> Box<dyn VecInputGuard<($( [<T $type_idx>], )*), markers::GroupedVariables> + '_> {
Box::new(
($(
self.$type_idx.read_input(),
)*)
)
}
}
}
};
}
macro_rules! computation_builder_reversed {
({} {$($reversed:tt),*}) => {
computation_builder!($($reversed),*);
};
({$first:tt $(, $rest:tt)*} {$($reversed:tt),*}) => {
computation_builder_reversed!({$($rest),*} {$first $(, $reversed)*}); };
}
macro_rules! computation_builders {
($first_type_idx: tt) => {
computation_builder!($first_type_idx);
};
($first_type_idx: tt, $($type_idx: tt),*) => {
computation_builder_reversed!({$($type_idx),*} {$first_type_idx});
computation_builders!($($type_idx),*);
}
}
computation_builders!(20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
impl<'b, T, Marker> ComputationVecBuilder<T, Marker> for ()
where
T: Sync + Send + 'static,
{
fn prepare(
&self,
_: &Arc<Dependency>,
) -> LinkedHashMap<Key, Box<dyn VecInputReader<T, Marker>>> {
Default::default()
}
}
impl<T, VT> ComputationBuilder<T> for Vec<&VT>
where
VT: ComputationInputInterface<Type = T>,
T: Sync + Send + 'static,
for<'a> <<VT as ComputationInputInterface>::InputReaderType as InputReader<T>>::InputGuard<'a>:
Deref<Target = T>,
{
type FunctorArgument<'a> = Vec<&'a VT::Type>;
fn prepare<'b>(
&self,
dependency: &Arc<Dependency>,
formula: impl for<'a> Fn(Self::FunctorArgument<'a>) -> T + 'b + Send + Sync,
) -> impl Fn() -> T + 'b + Send + Sync {
let variables = <Vec<&VT> as ComputationVecBuilder<T, DefaultVariableMarker>>::prepare(
self, dependency,
);
move || {
let unlocked_vars: Vec<_> = variables.iter().map(|(_, v)| v.read_vec_input()).collect();
let values: Vec<&T> = unlocked_vars
.iter()
.map(|uv| -> &T { uv.as_input_value() })
.collect();
formula(values)
}
}
}
impl<T, VT, Marker> ComputationVecBuilder<T, Marker> for Vec<&VT>
where
VT: ComputationInputInterface<Type = T>,
T: Sync + Send + 'static,
VecComputationFArgsSelector<T, Marker>: VecComputationFArgsSelectorTrait,
<VT as ComputationInputInterface>::InputReaderType: VecInputReader<T, Marker>,
{
fn prepare(
&self,
dependency: &Arc<Dependency>,
) -> LinkedHashMap<Key, Box<dyn VecInputReader<T, Marker>>> {
self.into_iter()
.map(|v| {
let (getter, v_dependency) = v.prepare_value();
let id = v_dependency.key.clone();
v_dependency.insert_dependency(dependency.clone());
dependency.insert_dependent(v_dependency);
let vm: Box<dyn VecInputReader<T, Marker>> = Box::new(getter);
(id, vm)
})
.collect()
}
}
struct ComputationData<T>
where
T: Send + Sync + 'static,
{
result: Arc<RwLock<T>>,
formula: Arc<Mutex<Box<dyn Fn() -> T + Sync + Send + 'static>>>,
dependency: Arc<Dependency>,
}
impl<T> Debug for ComputationData<T>
where
T: Debug + Sync + Send + 'static,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("").field("result", &self.result).finish()
}
}
impl<T> Clone for ComputationData<T>
where
T: Send + Sync + 'static,
{
fn clone(&self) -> Self {
Self {
result: self.result.clone(),
formula: self.formula.clone(),
dependency: self.dependency.clone(),
}
}
}
#[derive(Debug)]
pub struct Computation<T>
where
T: Send + Sync + 'static,
{
data: ComputationData<T>,
}
impl<T> ComputationValueType for Computation<T>
where
T: Send + Sync + 'static,
{
type Type = T;
}
impl<T> ComputationInputInterface for Computation<T>
where
T: Send + Sync + 'static,
{
type InputReaderType = ComputationData<T>;
fn id(&self) -> Key {
self.data.dependency.key.clone()
}
fn prepare_value(&self) -> (Self::InputReaderType, Arc<Dependency>) {
(self.data.clone(), self.data.dependency.clone())
}
}
impl<T> InputReader<T> for ComputationData<T>
where
T: Sync + Send + 'static,
{
type InputGuard<'a> = RwLockReadGuard<'a, T>;
fn read_input<'a>(&'a self) -> Self::InputGuard<'a> {
if self
.dependency
.outdated
.load(std::sync::atomic::Ordering::Relaxed)
{
self.dependency
.outdated
.store(false, std::sync::atomic::Ordering::Relaxed);
*self.result.write().unwrap() = (self.formula.lock().unwrap())();
}
self.result.read().unwrap()
}
}
impl<T> Computation<T>
where
T: Sync + Send + 'static,
{
pub fn new<TVars>(
formula: impl for<'a> Fn(TVars::FunctorArgument<'a>) -> T + 'static + Send + Sync,
tvars: TVars,
) -> Self
where
TVars: ComputationBuilder<T>,
{
let dependency = Dependency::new();
let formula = tvars.prepare(&dependency, formula);
let result = Arc::new(RwLock::new((formula)()));
Self {
data: ComputationData::<T> {
result,
formula: Arc::new(Mutex::new(Box::new(formula))),
dependency,
},
}
}
pub fn read_result<'a>(&'a self) -> impl Deref<Target = T> + 'a {
self.data.read_input()
}
}
pub trait VecComputationFArgsSelectorTrait {
type FArgs<'a>;
}
pub struct VecComputationFArgsSelector<C, Marker> {
first_casper: PhantomData<C>,
second_casper: PhantomData<Marker>,
}
impl<C> VecComputationFArgsSelectorTrait for VecComputationFArgsSelector<C, DefaultVariableMarker>
where
C: 'static,
{
type FArgs<'a> = &'a C;
}
pub mod markers {
#[derive(Debug)]
pub struct IndividualVariable {}
#[derive(Debug)]
pub struct GroupedVariables {}
}
type DefaultVariableMarker = markers::IndividualVariable;
type VecFnArg<'a, C, Marker> =
<VecComputationFArgsSelector<C, Marker> as VecComputationFArgsSelectorTrait>::FArgs<'a>;
type VecFnArgs<'a, C, Marker> = Vec<VecFnArg<'a, C, Marker>>;
struct VecComputationData<T, C, Marker>
where
T: Send + Sync + 'static,
C: Send + Sync + 'static,
VecComputationFArgsSelector<C, Marker>: VecComputationFArgsSelectorTrait,
{
result: Arc<RwLock<T>>,
variables: Arc<RwLock<LinkedHashMap<Key, Box<dyn VecInputReader<C, Marker>>>>>,
formula: Arc<Mutex<Box<dyn for<'a> Fn(VecFnArgs<'a, C, Marker>) -> T + Send + Sync>>>,
dependency: Arc<Dependency>,
}
impl<T, C, Marker> Debug for VecComputationData<T, C, Marker>
where
T: Send + Sync + 'static + Debug,
C: Send + Sync + 'static + Debug,
VecComputationFArgsSelector<C, Marker>: VecComputationFArgsSelectorTrait,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("")
.field("result", &self.result)
.field("dependency", &self.dependency)
.finish()
}
}
impl<T, C, Marker> Clone for VecComputationData<T, C, Marker>
where
T: Send + Sync + 'static,
C: Send + Sync + 'static,
VecComputationFArgsSelector<C, Marker>: VecComputationFArgsSelectorTrait,
{
fn clone(&self) -> Self {
Self {
result: self.result.clone(),
variables: self.variables.clone(),
formula: self.formula.clone(),
dependency: self.dependency.clone(),
}
}
}
impl<T, C, Marker> InputReader<T> for VecComputationData<T, C, Marker>
where
T: Sync + Send + 'static,
C: Send + Sync + 'static,
Marker: 'static,
VecComputationFArgsSelector<C, Marker>: VecComputationFArgsSelectorTrait,
{
type InputGuard<'a> = RwLockReadGuard<'a, T>;
fn read_input<'a>(&'a self) -> Self::InputGuard<'a> {
if self
.dependency
.outdated
.load(std::sync::atomic::Ordering::Relaxed)
{
self.dependency
.outdated
.store(false, std::sync::atomic::Ordering::Relaxed);
let variables = self.variables.read().unwrap();
let unlocked_vars: Vec<_> = variables.iter().map(|(_, v)| v.read_vec_input()).collect();
let values: VecFnArgs<'_, C, Marker> = unlocked_vars
.iter()
.map(|uv| -> VecFnArg<'_, C, Marker> { uv.as_input_value() })
.collect();
*self.result.write().unwrap() = (self.formula.lock().unwrap())(values);
}
self.result.read().unwrap()
}
}
#[derive(Debug)]
pub struct VecComputation<T, C = T, Marker = DefaultVariableMarker>
where
T: Send + Sync + 'static,
C: Send + Sync + 'static,
VecComputationFArgsSelector<C, Marker>: VecComputationFArgsSelectorTrait,
{
data: VecComputationData<T, C, Marker>,
casper: PhantomData<Marker>,
}
impl<T, C, Marker> ComputationValueType for VecComputation<T, C, Marker>
where
T: Send + Sync + 'static,
C: Send + Sync + 'static,
VecComputationFArgsSelector<C, Marker>: VecComputationFArgsSelectorTrait,
{
type Type = T;
}
impl<T, C, Marker> ComputationInputInterface for VecComputation<T, C, Marker>
where
T: Send + Sync + 'static,
C: Send + Sync + 'static,
VecComputationFArgsSelector<C, Marker>: VecComputationFArgsSelectorTrait + 'static,
{
type InputReaderType = VecComputationData<T, C, Marker>;
fn id(&self) -> Key {
self.data.dependency.key.clone()
}
fn prepare_value(&self) -> (Self::InputReaderType, Arc<Dependency>) {
(self.data.clone(), self.data.dependency.clone())
}
}
impl<T, C, Marker> VecComputation<T, C, Marker>
where
T: Send + Sync + 'static,
C: Send + Sync + 'static,
Marker: 'static,
VecComputationFArgsSelector<C, Marker>: VecComputationFArgsSelectorTrait,
{
pub fn new<TVars>(
formula: impl for<'a> Fn(VecFnArgs<'a, C, Marker>) -> T + 'static + Send + Sync,
tvars: TVars,
) -> Self
where
TVars: ComputationVecBuilder<C, Marker>,
{
let dependency = Dependency::new();
let variables = tvars.prepare(&dependency);
let result = Arc::new(RwLock::new({
let unlocked_vars: Vec<_> = variables.iter().map(|(_, v)| v.read_vec_input()).collect();
let values: VecFnArgs<'_, C, Marker> = unlocked_vars
.iter()
.map(|uv| -> VecFnArg<'_, C, Marker> { uv.as_input_value() })
.collect();
(formula)(values)
}));
let variables = Arc::new(RwLock::new(variables));
Self {
data: VecComputationData::<T, C, Marker> {
result,
variables,
formula: Arc::new(Mutex::new(Box::new(formula))),
dependency,
},
casper: Default::default(),
}
}
pub fn read_result<'a>(&'a self) -> impl Deref<Target = T> + 'a {
self.data.read_input()
}
pub fn push<CII>(&mut self, var: &CII)
where
CII: ComputationInputInterface<Type = C>,
<CII as ComputationInputInterface>::InputReaderType: VecInputReader<C, Marker>,
{
let (getter, dep) = var.prepare_value();
let id = dep.key.clone();
dep.insert_dependency(self.data.dependency.clone());
self.data.dependency.insert_dependent(dep);
self.data
.variables
.write()
.unwrap()
.insert(id, Box::new(getter));
self.data.dependency.notify_all();
}
pub fn remove(&mut self, var: &impl ComputationInputInterface) {
let id = var.id();
self.data.variables.write().unwrap().remove(&id);
self.data.dependency.remove_dependency(id);
self.data.dependency.notify_all();
}
}
impl<T, C> VecComputation<T, C>
where
T: Default + std::ops::Add<Output = T> + Sync + Send,
C: Into<T> + Clone + Sync + Send,
{
pub fn sum<TVars>(tvars: TVars) -> Self
where
TVars: ComputationVecBuilder<C, DefaultVariableMarker>,
{
Self::new(
|a| {
a.iter()
.fold(T::default(), |a, b| a + <C as Into<T>>::into((**b).clone()))
as T
},
tvars,
)
}
}
impl<T, C> VecComputation<T, C>
where
T: Default + for<'a> std::ops::Add<&'a T, Output = T> + Sync + Send,
for<'a> &'a C: Into<&'a T>,
C: Sync + Send,
{
pub fn sum_ref<TVars>(tvars: TVars) -> Self
where
TVars: ComputationVecBuilder<C, DefaultVariableMarker>,
{
Self::new(
|a| {
a.iter()
.fold(T::default(), |a, b| a + <&C as Into<&T>>::into(*b)) as T
},
tvars,
)
}
}
impl<T, C> VecComputation<T, C>
where
T: Default
+ std::ops::Add<Output = T>
+ TryFrom<usize>
+ std::ops::Div<Output = T>
+ Sync
+ Send,
C: Into<T> + Clone + Sync + Send,
<T as TryFrom<usize>>::Error: Debug,
{
pub fn average<TVars>(tvars: TVars) -> Self
where
TVars: ComputationVecBuilder<C, DefaultVariableMarker>,
{
Self::new(
|a| {
a.iter()
.fold(T::default(), |a, b| a + <C as Into<T>>::into((**b).clone()))
/ (<usize as TryInto<T>>::try_into(a.len()).expect("usize overflow"))
},
tvars,
)
}
}
#[derive(Debug)]
pub struct Variable<T>
where
T: Send + Sync,
{
t: Arc<RwLock<T>>,
dependency: Arc<Dependency>,
}
impl<T> Default for Variable<T>
where
T: Default + Send + Sync,
{
fn default() -> Self {
Self {
t: Arc::<RwLock<T>>::default(),
dependency: Dependency::new(),
}
}
}
impl<T> From<T> for Variable<T>
where
T: Send + Sync,
{
fn from(value: T) -> Self {
Self::new(value)
}
}
impl<T> ComputationValueType for Variable<T>
where
T: Send + Sync + 'static,
{
type Type = T;
}
impl<T> ComputationInputInterface for Variable<T>
where
T: Send + Sync + 'static,
{
type InputReaderType = Arc<RwLock<T>>;
fn id(&self) -> Key {
self.dependency.key.clone()
}
fn prepare_value(&self) -> (Self::InputReaderType, Arc<Dependency>) {
(self.t.clone(), self.dependency.clone())
}
}
impl<T> Variable<T>
where
T: Send + Sync,
{
pub fn new(t: T) -> Self {
Self {
t: Arc::new(RwLock::new(t)),
dependency: Dependency::new(),
}
}
pub fn set(&self, t: T) {
*self.t.write().unwrap() = t;
self.dependency.notify_all();
}
pub fn read_value(&self) -> RwLockReadGuard<'_, T> {
self.t.read().unwrap()
}
fn read_result(&self) -> RwLockReadGuard<'_, T> {
self.t.read().unwrap()
}
pub fn ro_value(&self) -> ccutils::sync::RoLock<T> {
ccutils::sync::RoLock::new(&self.t)
}
pub fn update(&self, f: impl Fn(&mut T)) {
f(&mut self.t.write().unwrap());
self.dependency.notify_all();
}
}
macro_rules! generate_traits_for_computation_getters {
($name:tt $(, extra: [$($extra_t: tt),+])? $(, blob: [$where_left:ty : $where_right: tt])?) => {
impl<T $($(, $extra_t)+)?> PartialEq for $name<T $($(, $extra_t)+)?>
where
T: PartialEq + Send + Sync,
$($($extra_t: Send + Sync + 'static,)+)?
$($where_left: $where_right)?
{
fn eq(&self, other: &Self) -> bool {
self.read_result().eq(&other.read_result())
}
}
impl<T $($(, $extra_t)+)?> PartialOrd for $name<T $($(, $extra_t)+)?>
where
T: PartialOrd + Send + Sync,
$($($extra_t: Send + Sync + 'static,)+)?
$($where_left: $where_right)?
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.read_result().partial_cmp(&other.read_result())
}
}
impl<T $($(, $extra_t)+)?> PartialEq<T> for $name<T $($(, $extra_t)+)?>
where
T: PartialEq + Send + Sync,
$($($extra_t: Send + Sync + 'static,)+)?
$($where_left: $where_right)?
{
fn eq(&self, other: &T) -> bool {
self.read_result().eq(other)
}
}
impl<T $($(, $extra_t)+)?> PartialOrd<T> for $name<T $($(, $extra_t)+)?>
where
T: PartialOrd + Send + Sync,
$($($extra_t: Send + Sync + 'static,)+)?
$($where_left: $where_right)?
{
fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
self.read_result().partial_cmp(other)
}
}
};
}
generate_traits_for_computation_getters!(Computation);
generate_traits_for_computation_getters!(VecComputation, extra: [C, Marker], blob: [VecComputationFArgsSelector::<C, Marker>: VecComputationFArgsSelectorTrait]);
generate_traits_for_computation_getters!(Variable);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn static_computation() {
let v1 = Variable::<u32>::new(1);
let v2 = Variable::<u32>::new(2);
let v3 = Variable::<u32>::new(3);
let c1 = Computation::<u32>::new(|(a, b, c)| a + b + c, (&v1, &v2, &v3));
assert_eq!(c1, 6);
v1.set(4);
assert_eq!(c1, 9);
v3.update(|x| *x -= 3);
assert_eq!(c1, 6);
}
#[test]
fn heterogenous_computation() {
let v1 = Variable::<u16>::new(1);
let v2 = Variable::<u32>::new(2);
let v3 = Variable::<f32>::new(3.0);
let c1 = Computation::<f64>::new(
|(a, b, c)| *a as f64 + *b as f64 + *c as f64,
(&v1, &v2, &v3),
);
assert_eq!(c1, 6.0);
v1.set(4);
assert_eq!(c1, 9.0);
v3.update(|x| *x -= 3.0);
assert_eq!(c1, 6.0);
}
#[test]
fn intermediary_computation() {
let v1 = Variable::<u16>::new(1);
let v2 = Variable::<u32>::new(2);
let v3 = Variable::<f32>::new(3.0);
let c1 = Computation::<f64>::new(
|(a, b, c)| *a as f64 + *b as f64 + *c as f64,
(&v1, &v2, &v3),
);
assert_eq!(c1, 6.0);
let v4 = Variable::<f64>::new(5.0);
let c2 = Computation::<f64>::new(|(a, b)| a + b, (&c1, &v4));
assert_eq!(c2, 11.0);
v1.set(4);
assert_eq!(c1, 9.0);
assert_eq!(c2, 14.0);
v3.update(|x| *x -= 3.0);
assert_eq!(c1, 6.0);
assert_eq!(c2, 11.0);
v4.set(-1.0);
assert_eq!(c1, 6.0);
assert_eq!(c2, 5.0);
v1.set(0);
assert_eq!(c2, 1.0);
}
#[test]
fn vec_computation() {
let v1 = Variable::<u32>::new(1);
let v2 = Variable::<u32>::new(2);
let v3 = Variable::<u32>::new(3);
let mut c1 = VecComputation::<u32>::average(vec![&v1, &v2, &v3]);
assert_eq!(c1, 2);
let v4 = Variable::<u32>::new(10);
c1.push(&v4);
assert_eq!(c1, 4);
c1.remove(&v1);
c1.remove(&v3);
assert_eq!(c1, 6);
v1.set(4);
v3.set(2);
assert_eq!(c1, 6);
v4.set(2);
assert_eq!(c1, 2);
v2.set(0);
assert_eq!(c1, 1);
let c2 = VecComputation::<u32>::sum(vec![&v1, &v2, &v3]);
assert_eq!(c2, 6);
}
#[test]
fn vec_intermediary_computation() {
let v1 = Variable::<u32>::new(1);
let v2 = Variable::<u32>::new(2);
let v3 = Variable::<u32>::new(3);
let mut c1 = VecComputation::<u32>::average(vec![&v1, &v2, &v3]);
assert_eq!(c1, 2);
let v5 = Variable::<f32>::new(4.0);
let c2 = Computation::<f32>::new(|(a, b)| *a as f32 + b, (&c1, &v5));
assert_eq!(c2, 6.0);
let v6 = Variable::<f32>::new(2.0);
let mut c3 = VecComputation::<f32>::sum((&c2, &v6));
let v4 = Variable::<u32>::new(10);
c1.push(&v4);
assert_eq!(c1, 4);
assert_eq!(c2, 8.0);
assert_eq!(c3, 10.0);
c1.remove(&v1);
c1.remove(&v3);
assert_eq!(c1, 6);
assert_eq!(c2, 10.0);
assert_eq!(c3, 12.0);
v1.set(4);
v3.set(2);
assert_eq!(c1, 6);
assert_eq!(c2, 10.0);
assert_eq!(c3, 12.0);
v4.set(2);
assert_eq!(c1, 2);
assert_eq!(c2, 6.0);
assert_eq!(c3, 8.0);
v2.set(0);
assert_eq!(c1, 1);
assert_eq!(c2, 5.0);
assert_eq!(c3, 7.0);
let v7 = Variable::<f32>::new(1.0);
c3.push(&v7);
assert_eq!(c1, 1);
assert_eq!(c2, 5.0);
assert_eq!(c3, 8.0);
c3.remove(&v6);
assert_eq!(c1, 1);
assert_eq!(c2, 5.0);
assert_eq!(c3, 6.0);
c3.remove(&c2);
assert_eq!(c1, 1);
assert_eq!(c2, 5.0);
assert_eq!(c3, 1.0);
}
#[test]
fn test_traits() {
let v1: Variable<i32> = 0.into();
let v2: Variable<i32> = 1.into();
let c1 = Computation::new(|(v1, v2)| *v1 + *v2, (&v1, &v2));
let c2 = Computation::new(|(v1, v2)| *v1 - *v2, (&v1, &v2));
let c3 = VecComputation::new(|v| *v[0] + *v[1], (&v1, &v2));
let c4 = VecComputation::new(|v| *v[0] - *v[1], vec![&v1, &v2]);
let c5 = VecComputation::new(|v| *v[0] - *v[1], (&v1, &v2));
assert_eq!(c1, 1);
assert_eq!(c2, -1);
assert_eq!(c3, 1);
assert_eq!(c4, -1);
assert_eq!(c5, -1);
assert!(v1 != v2);
assert!(v1 < v2);
assert!(c1 != c2);
assert!(c1 > c2);
assert!(c3 != c4);
assert!(c3 > c4);
assert!(c3 != c5);
assert!(c3 > c5);
assert!(c4 == c5);
}
#[test]
fn test_vec_order() {
let v1: Variable<i32> = 0.into();
let v2: Variable<i32> = 1.into();
let v3: Variable<i32> = 2.into();
let v4: Variable<i32> = 3.into();
let v5: Variable<i32> = 4.into();
let v6: Variable<i32> = 5.into();
let mut c1 = VecComputation::new(|v| v.windows(2).all(|w| w[0] < w[1]), (&v1, &v2));
assert_eq!(c1, true);
c1.push(&v3);
c1.push(&v4);
assert_eq!(c1, true);
c1.remove(&v4);
assert_eq!(c1, true);
c1.push(&v5);
assert_eq!(c1, true);
c1.push(&v6);
assert_eq!(c1, true);
c1.remove(&v3);
assert_eq!(c1, true);
c1.remove(&v6);
assert_eq!(c1, true);
c1.push(&v4);
assert_eq!(c1, false);
c1.push(&v6);
assert_eq!(c1, false);
c1.remove(&v4);
assert_eq!(c1, true);
}
#[test]
fn test_tuples() {
let v1: Variable<i32> = 0.into();
let v2: Variable<i32> = 1.into();
let v3: Variable<i32> = 2.into();
let mut c1 = VecComputation::<i32, (i32, i32, i32), markers::GroupedVariables>::new(
|v: Vec<(&i32, &i32, &i32)>| v.into_iter().fold(0, |a, (b, c, d)| a + b + c + d),
(&(&v1, &v2, &v3),),
);
assert_eq!(c1, 3);
let v4: Variable<i32> = 3.into();
let v5: Variable<i32> = 4.into();
let v6: Variable<i32> = 5.into();
c1.push(&(&v4, &v5, &v6));
assert_eq!(c1, 15);
}
}