|
use crate::Node; |
|
use std::marker::PhantomData; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Copy)] |
|
pub struct ComposeNode<First, Second, I> { |
|
first: First, |
|
second: Second, |
|
phantom: PhantomData<I>, |
|
} |
|
|
|
impl<'i, Input: 'i, First, Second> Node<'i, Input> for ComposeNode<First, Second, Input> |
|
where |
|
First: Node<'i, Input>, |
|
Second: Node<'i, <First as Node<'i, Input>>::Output> + 'i, |
|
{ |
|
type Output = <Second as Node<'i, <First as Node<'i, Input>>::Output>>::Output; |
|
fn eval(&'i self, input: Input) -> Self::Output { |
|
let arg = self.first.eval(input); |
|
let second = &self.second; |
|
second.eval(arg) |
|
} |
|
} |
|
|
|
impl<First, Second, Input> ComposeNode<First, Second, Input> { |
|
pub const fn new(first: First, second: Second) -> Self { |
|
ComposeNode::<First, Second, Input> { first, second, phantom: PhantomData } |
|
} |
|
} |
|
|
|
#[derive(Clone)] |
|
pub struct AsyncComposeNode<First, Second, I> { |
|
first: First, |
|
second: Second, |
|
phantom: PhantomData<I>, |
|
} |
|
|
|
impl<'i, Input: 'static, First, Second> Node<'i, Input> for AsyncComposeNode<First, Second, Input> |
|
where |
|
First: Node<'i, Input>, |
|
First::Output: Future, |
|
Second: Node<'i, <<First as Node<'i, Input>>::Output as Future>::Output> + 'i, |
|
{ |
|
type Output = std::pin::Pin<Box<dyn Future<Output = <Second as Node<'i, <<First as Node<'i, Input>>::Output as Future>::Output>>::Output> + 'i>>; |
|
fn eval(&'i self, input: Input) -> Self::Output { |
|
Box::pin(async move { |
|
let arg = self.first.eval(input).await; |
|
self.second.eval(arg) |
|
}) |
|
} |
|
} |
|
|
|
impl<'i, First, Second, Input: 'i> AsyncComposeNode<First, Second, Input> |
|
where |
|
First: Node<'i, Input>, |
|
First::Output: Future, |
|
Second: Node<'i, <<First as Node<'i, Input>>::Output as Future>::Output> + 'i, |
|
{ |
|
pub const fn new(first: First, second: Second) -> Self { |
|
AsyncComposeNode::<First, Second, Input> { first, second, phantom: PhantomData } |
|
} |
|
} |
|
|
|
pub trait Then<'i, Input: 'i>: Sized { |
|
fn then<Second>(self, second: Second) -> ComposeNode<Self, Second, Input> |
|
where |
|
Self: Node<'i, Input>, |
|
Second: Node<'i, <Self as Node<'i, Input>>::Output>, |
|
{ |
|
ComposeNode::new(self, second) |
|
} |
|
} |
|
|
|
impl<'i, First: Node<'i, Input>, Input: 'i> Then<'i, Input> for First {} |
|
|
|
pub trait AndThen<'i, Input: 'i>: Sized { |
|
fn and_then<Second>(self, second: Second) -> AsyncComposeNode<Self, Second, Input> |
|
where |
|
Self: Node<'i, Input>, |
|
Self::Output: Future, |
|
Second: Node<'i, <<Self as Node<'i, Input>>::Output as Future>::Output> + 'i, |
|
{ |
|
AsyncComposeNode::new(self, second) |
|
} |
|
} |
|
|
|
impl<'i, First: Node<'i, Input>, Input: 'i> AndThen<'i, Input> for First {} |
|
|
|
pub struct ConsNode<I: From<()>, Root>(pub Root, PhantomData<I>); |
|
|
|
impl<'i, Root, Input: 'i, I: 'i + From<()>> Node<'i, Input> for ConsNode<I, Root> |
|
where |
|
Root: Node<'i, I>, |
|
{ |
|
type Output = (Input, Root::Output); |
|
fn eval(&'i self, input: Input) -> Self::Output { |
|
let arg = self.0.eval(I::from(())); |
|
(input, arg) |
|
} |
|
} |
|
impl<'i, Root: Node<'i, I>, I: 'i + From<()>> ConsNode<I, Root> { |
|
pub fn new(root: Root) -> Self { |
|
ConsNode(root, PhantomData) |
|
} |
|
} |
|
|
|
#[cfg(test)] |
|
mod test { |
|
use super::*; |
|
use crate::generic::FnNode; |
|
use crate::value::ValueNode; |
|
|
|
#[test] |
|
fn compose() { |
|
let value = ValueNode::new(4u32); |
|
let compose = value.then(FnNode::new(|x| x)); |
|
assert_eq!(compose.eval(()), &4u32); |
|
let type_erased = &compose as &dyn Node<'_, (), Output = &'_ u32>; |
|
assert_eq!(type_erased.eval(()), &4u32); |
|
} |
|
|
|
#[test] |
|
fn test_ref_eval() { |
|
let value = ValueNode::new(5); |
|
|
|
assert_eq!(value.eval(()), &5); |
|
let id = FnNode::new(|x| x); |
|
|
|
let compose = ComposeNode::new(&value, &id); |
|
|
|
assert_eq!(compose.eval(()), &5); |
|
} |
|
} |
|
|