#[cfg(feature = "not-send-futures")]
use std::rc::Rc;
#[cfg(not(feature = "not-send-futures"))]
use std::sync::Arc;
use crate::{EvolveFunction, InitialStateFunction, Sum, View3, View4, View5, View6};
pub struct View<'a, S: 'a, E: 'a> {
pub evolve: EvolveFunction<'a, S, E>,
pub initial_state: InitialStateFunction<'a, S>,
}
impl<'a, S, E> View<'a, S, E> {
#[cfg(not(feature = "not-send-futures"))]
pub fn map_state<S2, F1, F2>(self, f1: F1, f2: F2) -> View<'a, S2, E>
where
F1: Fn(&S2) -> S + Send + Sync + 'a,
F2: Fn(&S) -> S2 + Send + Sync + 'a,
{
let f1 = Arc::new(f1);
let f2 = Arc::new(f2);
let new_evolve = {
let f2 = Arc::clone(&f2);
Box::new(move |s2: &S2, e: &E| {
let s = f1(s2);
f2(&(self.evolve)(&s, e))
})
};
let new_initial_state = { Box::new(move || f2(&(self.initial_state)())) };
View {
evolve: new_evolve,
initial_state: new_initial_state,
}
}
#[cfg(feature = "not-send-futures")]
pub fn map_state<S2, F1, F2>(self, f1: F1, f2: F2) -> View<'a, S2, E>
where
F1: Fn(&S2) -> S + 'a,
F2: Fn(&S) -> S2 + 'a,
{
let f1 = Rc::new(f1);
let f2 = Rc::new(f2);
let new_evolve = {
let f2 = Rc::clone(&f2);
Box::new(move |s2: &S2, e: &E| {
let s = f1(s2);
f2(&(self.evolve)(&s, e))
})
};
let new_initial_state = { Box::new(move || f2(&(self.initial_state)())) };
View {
evolve: new_evolve,
initial_state: new_initial_state,
}
}
#[cfg(not(feature = "not-send-futures"))]
pub fn map_event<E2, F>(self, f: F) -> View<'a, S, E2>
where
F: Fn(&E2) -> E + Send + Sync + 'a,
{
let new_evolve = Box::new(move |s: &S, e2: &E2| {
let e = f(e2);
(self.evolve)(s, &e)
});
let new_initial_state = Box::new(move || (self.initial_state)());
View {
evolve: new_evolve,
initial_state: new_initial_state,
}
}
#[cfg(feature = "not-send-futures")]
pub fn map_event<E2, F>(self, f: F) -> View<'a, S, E2>
where
F: Fn(&E2) -> E + 'a,
{
let new_evolve = Box::new(move |s: &S, e2: &E2| {
let e = f(e2);
(self.evolve)(s, &e)
});
let new_initial_state = Box::new(move || (self.initial_state)());
View {
evolve: new_evolve,
initial_state: new_initial_state,
}
}
#[deprecated(
since = "0.8.0",
note = "Use the `merge` function instead. This ensures all your views can subscribe to all `Event`/`E` in the system."
)]
pub fn combine<S2, E2>(self, view2: View<'a, S2, E2>) -> View<'a, (S, S2), Sum<E, E2>>
where
S: Clone,
S2: Clone,
{
let new_evolve = Box::new(move |s: &(S, S2), e: &Sum<E, E2>| match e {
Sum::First(e) => {
let s1 = &s.0;
let new_state = (self.evolve)(s1, e);
(new_state, s.1.to_owned())
}
Sum::Second(e) => {
let s2 = &s.1;
let new_state = (view2.evolve)(s2, e);
(s.0.to_owned(), new_state)
}
});
let new_initial_state = Box::new(move || {
let s1 = (self.initial_state)();
let s2 = (view2.initial_state)();
(s1, s2)
});
View {
evolve: new_evolve,
initial_state: new_initial_state,
}
}
pub fn merge<S2>(self, view2: View<'a, S2, E>) -> View<'a, (S, S2), E>
where
S: Clone,
S2: Clone,
{
let new_evolve = Box::new(move |s: &(S, S2), e: &E| {
let s1 = &s.0;
let s2 = &s.1;
let new_state = (self.evolve)(s1, e);
let new_state2 = (view2.evolve)(s2, e);
(new_state, new_state2)
});
let new_initial_state = Box::new(move || {
let s1 = (self.initial_state)();
let s2 = (view2.initial_state)();
(s1, s2)
});
View {
evolve: new_evolve,
initial_state: new_initial_state,
}
}
pub fn merge3<S2, S3>(
self,
view2: View<'a, S2, E>,
view3: View<'a, S3, E>,
) -> View3<'a, S, S2, S3, E>
where
S: Clone,
S2: Clone,
S3: Clone,
{
self.merge(view2).merge(view3).map_state(
|s: &(S, S2, S3)| ((s.0.clone(), s.1.clone()), s.2.clone()),
|s: &((S, S2), S3)| (s.0 .0.clone(), s.0 .1.clone(), s.1.clone()),
)
}
pub fn merge4<S2, S3, S4>(
self,
view2: View<'a, S2, E>,
view3: View<'a, S3, E>,
view4: View<'a, S4, E>,
) -> View4<'a, S, S2, S3, S4, E>
where
S: Clone,
S2: Clone,
S3: Clone,
S4: Clone,
{
self.merge(view2).merge(view3).merge(view4).map_state(
|s: &(S, S2, S3, S4)| (((s.0.clone(), s.1.clone()), s.2.clone()), s.3.clone()),
|s: &(((S, S2), S3), S4)| {
(
s.0 .0 .0.clone(),
s.0 .0 .1.clone(),
s.0 .1.clone(),
s.1.clone(),
)
},
)
}
#[allow(clippy::type_complexity)]
pub fn merge5<S2, S3, S4, S5>(
self,
view2: View<'a, S2, E>,
view3: View<'a, S3, E>,
view4: View<'a, S4, E>,
view5: View<'a, S5, E>,
) -> View5<'a, S, S2, S3, S4, S5, E>
where
S: Clone,
S2: Clone,
S3: Clone,
S4: Clone,
S5: Clone,
{
self.merge(view2)
.merge(view3)
.merge(view4)
.merge(view5)
.map_state(
|s: &(S, S2, S3, S4, S5)| {
(
(((s.0.clone(), s.1.clone()), s.2.clone()), s.3.clone()),
s.4.clone(),
)
},
|s: &((((S, S2), S3), S4), S5)| {
(
s.0 .0 .0 .0.clone(),
s.0 .0 .0 .1.clone(),
s.0 .0 .1.clone(),
s.0 .1.clone(),
s.1.clone(),
)
},
)
}
#[allow(clippy::type_complexity)]
pub fn merge6<S2, S3, S4, S5, S6>(
self,
view2: View<'a, S2, E>,
view3: View<'a, S3, E>,
view4: View<'a, S4, E>,
view5: View<'a, S5, E>,
view6: View<'a, S6, E>,
) -> View6<'a, S, S2, S3, S4, S5, S6, E>
where
S: Clone,
S2: Clone,
S3: Clone,
S4: Clone,
S5: Clone,
S6: Clone,
{
self.merge(view2)
.merge(view3)
.merge(view4)
.merge(view5)
.merge(view6)
.map_state(
|s: &(S, S2, S3, S4, S5, S6)| {
(
(
(((s.0.clone(), s.1.clone()), s.2.clone()), s.3.clone()),
s.4.clone(),
),
s.5.clone(),
)
},
|s: &(((((S, S2), S3), S4), S5), S6)| {
(
s.0 .0 .0 .0 .0.clone(),
s.0 .0 .0 .0 .1.clone(),
s.0 .0 .0 .1.clone(),
s.0 .0 .1.clone(),
s.0 .1.clone(),
s.1.clone(),
)
},
)
}
}
pub trait ViewStateComputation<E, S> {
fn compute_new_state(&self, current_state: Option<S>, events: &[&E]) -> S;
}
impl<S, E> ViewStateComputation<E, S> for View<'_, S, E> {
fn compute_new_state(&self, current_state: Option<S>, events: &[&E]) -> S {
let effective_current_state = current_state.unwrap_or_else(|| (self.initial_state)());
events.iter().fold(effective_current_state, |state, event| {
(self.evolve)(&state, event)
})
}
}