use std::marker::PhantomData;
use crate::simulation;
use crate::simulation::Point;
use crate::simulation::event::*;
use crate::simulation::observable::disposable::*;
#[inline]
pub fn return_composite<T>(val: T) -> Return<T> {
Return { val: val }
}
#[inline]
pub fn delay_composite<F, M>(f: F) -> Delay<F, M>
where F: FnOnce() -> M,
M: Composite
{
Delay { f: f, _phantom: PhantomData }
}
#[inline]
pub fn cons_composite<F, T>(f: F) -> Cons<F, T>
where F: FnOnce(DisposableBox, &Point) -> simulation::Result<(T, DisposableBox)>
{
Cons { f: f, _phantom: PhantomData }
}
#[inline]
pub fn disposable_composite<D>(action: D) -> DisposableComposite<D>
where D: Disposable + 'static
{
DisposableComposite { action: action }
}
#[inline]
pub fn composite_sequence<I, M>(comps: I) -> Sequence<I::IntoIter, M>
where I: IntoIterator<Item = M>,
M: Composite
{
Sequence { comps: comps.into_iter(), _phantom: PhantomData }
}
#[inline]
pub fn composite_sequence_<I, M>(comps: I) -> Sequence_<I::IntoIter, M>
where I: IntoIterator<Item = M>,
M: Composite
{
Sequence_ { comps: comps.into_iter(), _phantom: PhantomData }
}
#[inline]
pub fn trace_composite<M>(msg: String, comp: M) -> Trace<M>
where M: Composite
{
Trace { comp: comp, msg: msg}
}
pub trait Composite {
type Item;
#[doc(hidden)]
fn call_composite(self, disposable: DisposableBox, p: &Point) -> simulation::Result<(Self::Item, DisposableBox)>;
#[inline]
fn and_then<U, F>(self, f: F) -> AndThen<Self, U, F>
where Self: Sized,
U: Composite,
F: FnOnce(Self::Item) -> U,
{
AndThen { comp: self, f: f, _phantom: PhantomData }
}
#[inline]
fn map<B, F>(self, f: F) -> Map<Self, B, F>
where Self: Sized,
F: FnOnce(Self::Item) -> B,
{
Map { comp: self, f: f, _phantom: PhantomData }
}
#[inline]
fn zip<U>(self, other: U) -> Zip<Self, U>
where Self: Sized,
U: Composite
{
Zip { comp: self, other: other }
}
#[inline]
fn ap<U, B>(self, other: U) -> Ap<Self, U, B>
where Self: Sized,
Self::Item: FnOnce(U::Item) -> B,
U: Composite
{
Ap { comp: self, other: other, _phantom: PhantomData }
}
#[inline]
fn into_boxed(self) -> CompositeBox<Self::Item>
where Self: Sized + 'static
{
CompositeBox::new(move |disposable, p: &Point| { self.call_composite(disposable, p) })
}
#[inline]
fn run<D>(self, disposable: D) -> Run<Self, D>
where Self: Sized,
D: Disposable + 'static
{
Run { comp: self, disposable: disposable }
}
#[inline]
fn run_(self) -> Run_<Self>
where Self: Sized
{
Run_ { comp: self }
}
}
pub trait IntoComposite {
type Composite: Composite<Item = Self::Item>;
type Item;
fn into_composite(self) -> Self::Composite;
}
impl<M: Composite> IntoComposite for M {
type Composite = M;
type Item = M::Item;
#[inline]
fn into_composite(self) -> Self::Composite {
self
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
pub struct CompositeBox<T> {
f: Box<dyn CompositeFnBox<T>>
}
impl<T> CompositeBox<T> {
#[doc(hidden)]
#[inline]
fn new<F>(f: F) -> Self
where F: FnOnce(DisposableBox, &Point) -> simulation::Result<(T, DisposableBox)> + 'static
{
CompositeBox {
f: Box::new(f)
}
}
#[doc(hidden)]
#[inline]
pub fn call_box(self, arg: (DisposableBox, &Point,)) -> simulation::Result<(T, DisposableBox)> {
let CompositeBox { f } = self;
f.call_box(arg)
}
}
impl<T> Composite for CompositeBox<T> {
type Item = T;
#[inline]
fn call_composite(self, disposable: DisposableBox, p: &Point) -> simulation::Result<(Self::Item, DisposableBox)> {
self.call_box((disposable, p,))
}
#[inline]
fn into_boxed(self) -> CompositeBox<Self::Item>
where Self: Sized + 'static
{
self
}
}
trait CompositeFnBox<T> {
fn call_box(self: Box<Self>, args: (DisposableBox, &Point,)) -> simulation::Result<(T, DisposableBox)>;
}
impl<T, F> CompositeFnBox<T> for F
where F: for<'a> FnOnce(DisposableBox, &'a Point) -> simulation::Result<(T, DisposableBox)>
{
fn call_box(self: Box<Self>, args: (DisposableBox, &Point,)) -> simulation::Result<(T, DisposableBox)> {
let this: Self = *self;
this(args.0, args.1)
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Return<T> {
val: T
}
impl<T> Composite for Return<T> {
type Item = T;
#[doc(hidden)]
#[inline]
fn call_composite(self, disposable: DisposableBox, _: &Point) -> simulation::Result<(T, DisposableBox)> {
let Return { val } = self;
Result::Ok((val, disposable))
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Delay<F, M> {
f: F,
_phantom: PhantomData<M>
}
impl<F, M> Composite for Delay<F, M>
where F: FnOnce() -> M,
M: Composite
{
type Item = M::Item;
#[doc(hidden)]
#[inline]
fn call_composite(self, disposable: DisposableBox, p: &Point) -> simulation::Result<(M::Item, DisposableBox)> {
let Delay { f, _phantom } = self;
f().call_composite(disposable, p)
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Cons<F, T> {
f: F,
_phantom: PhantomData<T>
}
impl<F, T> Composite for Cons<F, T>
where F: FnOnce(DisposableBox, &Point) -> simulation::Result<(T, DisposableBox)>
{
type Item = T;
#[doc(hidden)]
#[inline]
fn call_composite(self, disposable: DisposableBox, p: &Point) -> simulation::Result<(T, DisposableBox)> {
let Cons { f, _phantom } = self;
f(disposable, p)
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct AndThen<M, U, F> {
comp: M,
f: F,
_phantom: PhantomData<U>
}
impl<M, U, F> Composite for AndThen<M, U, F>
where M: Composite,
U: Composite,
F: FnOnce(M::Item) -> U,
{
type Item = U::Item;
#[doc(hidden)]
#[inline]
fn call_composite(self, disposable: DisposableBox, p: &Point) -> simulation::Result<(U::Item, DisposableBox)> {
let AndThen { comp, f, _phantom } = self;
match comp.call_composite(disposable, p) {
Result::Ok((a, disposable)) => {
let m = f(a);
m.call_composite(disposable, p)
},
Result::Err(e) => {
Result::Err(e)
}
}
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Map<M, B, F> {
comp: M,
f: F,
_phantom: PhantomData<B>
}
impl<M, B, F> Composite for Map<M, B, F>
where M: Composite,
F: FnOnce(M::Item) -> B,
{
type Item = B;
#[doc(hidden)]
#[inline]
fn call_composite(self, disposable: DisposableBox, p: &Point) -> simulation::Result<(B, DisposableBox)> {
let Map { comp, f, _phantom } = self;
match comp.call_composite(disposable, p) {
Result::Ok((a, disposable)) => Result::Ok((f(a), disposable)),
Result::Err(e) => Result::Err(e)
}
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Zip<M, U> {
comp: M,
other: U,
}
impl<M, U> Composite for Zip<M, U>
where M: Composite,
U: Composite
{
type Item = (M::Item, U::Item);
#[doc(hidden)]
#[inline]
fn call_composite(self, disposable: DisposableBox, p: &Point) -> simulation::Result<((M::Item, U::Item), DisposableBox)> {
let Zip { comp, other } = self;
comp.and_then(move |a| {
other.map(move |b| (a, b))
}).call_composite(disposable, p)
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Ap<M, U, B> {
comp: M,
other: U,
_phantom: PhantomData<B>
}
impl<M, U, B> Composite for Ap<M, U, B>
where M: Composite,
U: Composite,
M::Item: FnOnce(U::Item) -> B,
{
type Item = B;
#[doc(hidden)]
#[inline]
fn call_composite(self, disposable: DisposableBox, p: &Point) -> simulation::Result<(B, DisposableBox)> {
let Ap { comp, other, _phantom } = self;
comp.and_then(move |f| {
other.map(move |a| { f(a) })
}).call_composite(disposable, p)
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Sequence<I, M> {
comps: I,
_phantom: PhantomData<M>
}
impl<I, M> Composite for Sequence<I, M>
where I: Iterator<Item = M>,
M: Composite
{
type Item = Vec<M::Item>;
#[doc(hidden)]
fn call_composite(self, disposable: DisposableBox, p: &Point) -> simulation::Result<(Self::Item, DisposableBox)> {
let Sequence { comps, _phantom } = self;
let mut v = {
match comps.size_hint() {
(_, Some(n)) => Vec::with_capacity(n),
(_, None) => Vec::new()
}
};
let mut disposable = disposable;
for m in comps {
match m.call_composite(disposable, p) {
Result::Ok((a, x)) => {
v.push(a);
disposable = x;
},
Result::Err(e) => {
return Result::Err(e)
}
}
}
Result::Ok((v, disposable))
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Sequence_<I, M> {
comps: I,
_phantom: PhantomData<M>
}
impl<I, M> Composite for Sequence_<I, M>
where I: Iterator<Item = M>,
M: Composite
{
type Item = ();
#[doc(hidden)]
fn call_composite(self, disposable: DisposableBox, p: &Point) -> simulation::Result<(Self::Item, DisposableBox)> {
let Sequence_ { comps, _phantom } = self;
let mut disposable = disposable;
for m in comps {
match m.call_composite(disposable, p) {
Result::Ok((_, x)) => { disposable = x; },
Result::Err(e) => return Result::Err(e)
}
}
Result::Ok(((), disposable))
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Run<M, D> {
comp: M,
disposable: D
}
impl<M, D> Event for Run<M, D>
where M: Composite,
D: Disposable + 'static
{
type Item = (M::Item, DisposableBox);
#[doc(hidden)]
fn call_event(self, p: &Point) -> simulation::Result<Self::Item> {
let Run { comp, disposable } = self;
let disposable = disposable.into_boxed();
comp.call_composite(disposable, p)
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Run_<M> {
comp: M
}
impl<M> Event for Run_<M>
where M: Composite
{
type Item = M::Item;
#[doc(hidden)]
fn call_event(self, p: &Point) -> simulation::Result<Self::Item> {
let Run_ { comp } = self;
let disposable = empty_disposable().into_boxed();
let (a, _) = comp.call_composite(disposable, p)?;
Result::Ok(a)
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct DisposableComposite<D> {
action: D
}
impl<D> Composite for DisposableComposite<D>
where D: Disposable + 'static
{
type Item = ();
#[doc(hidden)]
fn call_composite(self, disposable: DisposableBox, _p: &Point) -> simulation::Result<(Self::Item, DisposableBox)> {
let DisposableComposite { action } = self;
let disposable = disposable.merge(action).into_boxed();
Result::Ok(((), disposable))
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct Trace<M> {
comp: M,
msg: String
}
impl<M> Composite for Trace<M>
where M: Composite
{
type Item = M::Item;
#[doc(hidden)]
#[inline]
fn call_composite(self, disposable: DisposableBox, p: &Point) -> simulation::Result<(Self::Item, DisposableBox)> {
let Trace { comp, msg } = self;
p.trace(&msg);
comp.call_composite(disposable, p)
}
}