use std::rc::Rc;
use crate::simulation::block::*;
use crate::simulation::block::generator::*;
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct BlockFn<I, O> {
gen: Rc<dyn Fn() -> BlockBox<I, O>>
}
impl<I, O> BlockFn<I, O> {
#[inline]
pub fn new<F, M>(f: F) -> Self
where F: Fn() -> M + 'static,
M: Block<Input = I, Output = O> + 'static
{
BlockFn {
gen: Rc::new(move || { f().into_boxed() })
}
}
#[inline]
pub fn next(&self) -> BlockBox<I, O> {
(self.gen)()
}
#[inline]
pub fn and_then<O2>(&self, other: &BlockFn<O, O2>) -> BlockFn<I, O2>
where I: 'static,
O: 'static,
O2: 'static
{
let gen = self.gen.clone();
let gen2 = other.gen.clone();
BlockFn::new(move || {
gen().and_then(gen2())
})
}
}
#[must_use = "computations are lazy and do nothing unless to be run"]
#[derive(Clone)]
pub struct GeneratorBlockFn<T> {
gen: Rc<dyn Fn() -> BlockBox<BlockFn<T, ()>, ()>>
}
impl<T> GeneratorBlockFn<T> {
#[inline]
pub fn new<F, M>(f: F) -> Self
where F: Fn() -> M + 'static,
M: GeneratorBlock<T> + 'static
{
GeneratorBlockFn {
gen: Rc::new(move || { f().into_boxed() })
}
}
#[inline]
pub fn next(&self) -> BlockBox<BlockFn<T, ()>, ()> {
(self.gen)()
}
}