Make node trait consume self

This commit is contained in:
Dennis 2022-08-19 18:58:17 +02:00 committed by Keavon Chambers
parent 12b33da083
commit bdad7aca47
10 changed files with 286 additions and 188 deletions

View File

@ -1,31 +1,45 @@
use core::marker::PhantomData;
use crate::Node;
pub struct FnNode<'n, T: Fn(I) -> O, I, O>(T, PhantomData<&'n (I, O)>);
impl<'n, T: Fn(I) -> O, O, I> Node<'n, I> for FnNode<'n, T, I, O> {
pub struct FnNode<T: Fn(I) -> O, I, O>(T, PhantomData<(I, O)>);
impl<T: Fn(I) -> O, O, I> Node<I> for FnNode<T, I, O> {
type Output = O;
fn eval(&'n self, input: I) -> Self::Output {
fn eval(self, input: I) -> Self::Output {
self.0(input)
}
}
impl<'n, T: Fn(I) -> O, O, I> Node<I> for &'n FnNode<T, I, O> {
type Output = O;
fn eval(self, input: I) -> Self::Output {
self.0(input)
}
}
impl<'n, T: Fn(I) -> O, I, O> FnNode<'n, T, I, O> {
impl<T: Fn(I) -> O, I, O> FnNode<T, I, O> {
pub fn new(f: T) -> Self {
FnNode(f, PhantomData)
}
}
pub struct FnNodeWithState<'n, T: Fn(I, &'n State) -> O, I, O, State: 'n>(T, State, PhantomData<&'n (O, I)>);
impl<'n, T: Fn(I, &'n State) -> O, I, O: 'n, State: 'n> Node<'n, I> for FnNodeWithState<'n, T, I, O, State> {
pub struct FnNodeWithState<'n, T: Fn(I, &'n State) -> O, I, O: 'n, State: 'n>(T, State, PhantomData<&'n (O, I)>);
impl<'n, T: Fn(I, &State) -> O, I, O: 'n, State: 'n> Node<I> for &'n FnNodeWithState<'n, T, I, O, State> {
type Output = O;
fn eval(&'n self, input: I) -> Self::Output {
fn eval(self, input: I) -> Self::Output {
self.0(input, &self.1)
}
}
impl<'n, T: Fn(I, &State) -> O, I, O: 'n, State: 'n> Node<I> for FnNodeWithState<'n, T, I, O, State> {
type Output = O;
fn eval(self, input: I) -> Self::Output {
self.0(input, &self.1)
}
}
impl<'n, T: Fn(I, &'n State) -> O, I, O: 'n, State: 'n> FnNodeWithState<'n, T, I, O, State> {
impl<'n, T: Fn(I, &State) -> O, I, O, State> FnNodeWithState<'n, T, I, O, State> {
pub fn new(f: T, state: State) -> Self {
FnNodeWithState(f, state, PhantomData)
}

View File

@ -14,18 +14,10 @@ pub mod raster;
pub mod structural;
pub mod value;
pub trait Node<'n, T> {
type Output; // TODO: replace with generic associated type
pub trait Node<T> {
type Output;
fn eval(&'n self, input: T) -> Self::Output;
}
impl<'n, N: Node<'n, T>, T> Node<'n, T> for &'n N {
type Output = N::Output;
fn eval(&'n self, input: T) -> Self::Output {
Node::eval(*self, input)
}
fn eval(self, input: T) -> Self::Output;
}
trait Input<I> {
@ -34,21 +26,21 @@ trait Input<I> {
#[cfg(feature = "async")]
#[async_trait]
pub trait AsyncNode<'n, T> {
type Output; // TODO: replace with generic associated type
pub trait AsyncNode<T> {
type Output;
async fn eval_async(&'n self, input: T) -> Self::Output;
async fn eval_async(self, input: T) -> Self::Output;
}
#[cfg(feature = "async")]
/*#[cfg(feature = "async")]
#[async_trait]
impl<'n, N: Node<'n, T> + Sync, T: Send + 'n> AsyncNode<'n, T> for N {
impl<'n, N: Node<T> + Send + Sync + 'n, T: Send + 'n> AsyncNode<T> for N {
type Output = N::Output;
async fn eval_async(&'n self, input: T) -> Self::Output {
async fn eval_async(self, input: T) -> Self::Output {
Node::eval(self, input)
}
}
}*/
pub trait Cache {
fn clear(&mut self);

View File

@ -3,111 +3,124 @@ use core::ops::Add;
use crate::Node;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AddNode;
impl<'n, L: Add<R, Output = O> + 'n, R, O: 'n> Node<'n, (L, R)> for AddNode {
impl<'n, L: Add<R, Output = O> + 'n, R, O: 'n> Node<(L, R)> for AddNode {
type Output = <L as Add<R>>::Output;
fn eval(&'n self, input: (L, R)) -> Self::Output {
fn eval(self, input: (L, R)) -> Self::Output {
input.0 + input.1
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CloneNode;
impl<'n, O: Clone> Node<'n, &'n O> for CloneNode {
impl<'n, O: Clone> Node<&'n O> for CloneNode {
type Output = O;
fn eval(&'n self, input: &'n O) -> Self::Output {
fn eval(self, input: &'n O) -> Self::Output {
input.clone()
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FstNode;
impl<'n, T: 'n, U> Node<'n, (T, U)> for FstNode {
impl<'n, T: 'n, U> Node<(T, U)> for FstNode {
type Output = T;
fn eval(&'n self, input: (T, U)) -> Self::Output {
fn eval(self, input: (T, U)) -> Self::Output {
let (a, _) = input;
a
}
}
impl<'n, T: 'n, U> Node<'n, &'n (T, U)> for FstNode {
impl<'n, T: 'n, U> Node<&'n (T, U)> for FstNode {
type Output = &'n T;
fn eval(&'n self, input: &'n (T, U)) -> Self::Output {
fn eval(self, input: &'n (T, U)) -> Self::Output {
let (a, _) = input;
a
}
}
/// Destructures a Tuple of two values and returns the first one
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SndNode;
impl<'n, T, U: 'n> Node<'n, (T, U)> for SndNode {
impl<'n, T, U: 'n> Node<(T, U)> for SndNode {
type Output = U;
fn eval(&'n self, input: (T, U)) -> Self::Output {
fn eval(self, input: (T, U)) -> Self::Output {
let (_, b) = input;
b
}
}
impl<'n, T, U: 'n> Node<'n, &'n (T, U)> for SndNode {
impl<'n, T, U: 'n> Node<&'n (T, U)> for SndNode {
type Output = &'n U;
fn eval(&'n self, input: &'n (T, U)) -> Self::Output {
fn eval(self, input: &'n (T, U)) -> Self::Output {
let (_, b) = input;
b
}
}
/// Destructures a Tuple of two values and returns them in reverse order
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SwapNode;
impl<'n, T: 'n, U: 'n> Node<'n, (T, U)> for SwapNode {
impl<'n, T: 'n, U: 'n> Node<(T, U)> for SwapNode {
type Output = (U, T);
fn eval(&'n self, input: (T, U)) -> Self::Output {
fn eval(self, input: (T, U)) -> Self::Output {
let (a, b) = input;
(b, a)
}
}
impl<'n, T, U: 'n> Node<'n, &'n (T, U)> for SwapNode {
impl<'n, T, U: 'n> Node<&'n (T, U)> for SwapNode {
type Output = (&'n U, &'n T);
fn eval(&'n self, input: &'n (T, U)) -> Self::Output {
fn eval(self, input: &'n (T, U)) -> Self::Output {
let (a, b) = input;
(b, a)
}
}
/// Return a tuple with two instances of the input argument
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DupNode;
impl<'n, T: Clone + 'n> Node<'n, T> for DupNode {
impl<'n, T: Clone + 'n> Node<T> for DupNode {
type Output = (T, T);
fn eval(&'n self, input: T) -> Self::Output {
fn eval(self, input: T) -> Self::Output {
(input.clone(), input) //TODO: use Copy/Clone implementation
}
}
/// Return the Input Argument
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct IdNode;
impl<'n, T: 'n> Node<'n, T> for IdNode {
impl<'n, T: 'n> Node<T> for IdNode {
type Output = T;
fn eval(&'n self, input: T) -> Self::Output {
fn eval(self, input: T) -> Self::Output {
input
}
}
pub struct MapResultNode<'n, MN: Node<'n, I>, I, E>(pub MN, pub PhantomData<&'n (I, E)>);
pub struct MapResultNode<MN, I, E>(pub MN, pub PhantomData<(I, E)>);
impl<'n, MN: Node<'n, I>, I, E> Node<'n, Result<I, E>> for MapResultNode<'n, MN, I, E> {
impl<MN: Node<I>, I, E> Node<Result<I, E>> for MapResultNode<MN, I, E> {
type Output = Result<MN::Output, E>;
fn eval(&'n self, input: Result<I, E>) -> Self::Output {
fn eval(self, input: Result<I, E>) -> Self::Output {
input.map(|x| self.0.eval(x))
}
}
impl<'n, MN: Node<I> + Copy, I, E> Node<Result<I, E>> for &'n MapResultNode<MN, I, E> {
type Output = Result<MN::Output, E>;
fn eval(self, input: Result<I, E>) -> Self::Output {
input.map(|x| (&self.0).eval(x))
}
}
impl<'n, MN: Node<'n, I>, I, E> MapResultNode<'n, MN, I, E> {
impl<MN, I, E> MapResultNode<MN, I, E> {
pub const fn new(mn: MN) -> Self {
Self(mn, PhantomData)
}
}
pub struct FlatMapResultNode<'n, MN: Node<'n, I>, I, E>(pub MN, pub PhantomData<&'n (I, E)>);
pub struct FlatMapResultNode<MN: Node<I>, I, E>(pub MN, pub PhantomData<(I, E)>);
impl<'n, MN: Node<'n, I, Output = Result<O, E>>, I, O: 'n, E: 'n> Node<'n, Result<I, E>> for FlatMapResultNode<'n, MN, I, E> {
impl<'n, MN: Node<I, Output = Result<O, E>>, I, O: 'n, E: 'n> Node<Result<I, E>> for FlatMapResultNode<MN, I, E> {
type Output = Result<O, E>;
fn eval(&'n self, input: Result<I, E>) -> Self::Output {
fn eval(self, input: Result<I, E>) -> Self::Output {
match input.map(|x| self.0.eval(x)) {
Ok(Ok(x)) => Ok(x),
Ok(Err(e)) => Err(e),
@ -116,7 +129,7 @@ impl<'n, MN: Node<'n, I, Output = Result<O, E>>, I, O: 'n, E: 'n> Node<'n, Resul
}
}
impl<'n, MN: Node<'n, I>, I, E> FlatMapResultNode<'n, MN, I, E> {
impl<MN: Node<I>, I, E> FlatMapResultNode<MN, I, E> {
pub const fn new(mn: MN) -> Self {
Self(mn, PhantomData)
}
@ -131,26 +144,26 @@ mod test {
pub fn dup_node() {
let value = ValueNode(4u32);
let dup = DupNode.after(value);
assert_eq!(dup.eval(()), (&4, &4));
assert_eq!(dup.eval(()), (4, 4));
}
#[test]
pub fn id_node() {
let value = IdNode.after(ValueNode(4u32));
assert_eq!(value.eval(()), &4);
assert_eq!(value.eval(()), 4);
}
#[test]
pub fn clone_node() {
let cloned = CloneNode.after(ValueNode(4u32));
let cloned = CloneNode.after(&ValueNode(4u32));
assert_eq!(cloned.eval(()), 4);
}
#[test]
pub fn fst_node() {
let fst = FstNode.after(ValueNode((4u32, "a")).clone());
let fst = FstNode.after(ValueNode((4u32, "a")));
assert_eq!(fst.eval(()), 4);
}
#[test]
pub fn snd_node() {
let fst = SndNode.after(ValueNode((4u32, "a")).clone());
let fst = SndNode.after(ValueNode((4u32, "a")));
assert_eq!(fst.eval(()), "a");
}
#[test]
@ -164,8 +177,8 @@ mod test {
}
#[test]
pub fn foo() {
fn int(_: (), state: &u32) -> &u32 {
state
fn int(_: (), state: &u32) -> u32 {
*state
}
fn swap(input: (u32, u32)) -> (u32, u32) {
(input.1, input.0)
@ -173,6 +186,7 @@ mod test {
let fnn = FnNode::new(&swap);
let fns = FnNodeWithState::new(int, 42u32);
assert_eq!(fnn.eval((1u32, 2u32)), (2, 1));
assert_eq!(fns.eval(()), &42);
let result: u32 = (&fns).eval(());
assert_eq!(result, 42);
}
}

View File

@ -1,36 +1,48 @@
use core::marker::PhantomData;
use crate::Node;
use self::color::Color;
pub mod color;
#[derive(Debug, Clone, Copy)]
pub struct GrayscaleNode;
impl<'n> Node<'n, Color> for GrayscaleNode {
impl Node<Color> for GrayscaleNode {
type Output = Color;
fn eval(&'n self, color: Color) -> Color {
fn eval(self, color: Color) -> Color {
let avg = (color.r() + color.g() + color.b()) / 3.0;
Color::from_rgbaf32(avg, avg, avg, color.a()).expect("Grayscale node created an invalid color")
Color::from_rgbaf32_unchecked(avg, avg, avg, color.a())
}
}
impl<'n> Node<Color> for &'n GrayscaleNode {
type Output = Color;
fn eval(self, color: Color) -> Color {
let avg = (color.r() + color.g() + color.b()) / 3.0;
Color::from_rgbaf32_unchecked(avg, avg, avg, color.a())
}
}
pub struct ForEachNode<'n, I: Iterator<Item = S>, MN: Node<'n, S>, S>(pub MN, PhantomData<&'n (I, S)>);
pub struct ForEachNode<MN>(pub MN);
impl<'n, I: Iterator<Item = S>, MN: Node<'n, S, Output = ()>, S> Node<'n, I> for ForEachNode<'n, I, MN, S> {
impl<'n, I: Iterator<Item = S>, MN: 'n, S> Node<I> for &'n ForEachNode<MN>
where
&'n MN: Node<S, Output = ()>,
{
type Output = ();
fn eval(&'n self, input: I) -> Self::Output {
input.for_each(|x| self.0.eval(x))
fn eval(self, input: I) -> Self::Output {
input.for_each(|x| (&self.0).eval(x))
}
}
pub struct MutWrapper<'n, N: Node<'n, T, Output = T>, T: Clone>(pub N, PhantomData<&'n T>);
pub struct MutWrapper<N>(pub N);
impl<'n, T: Clone, N: Node<'n, T, Output = T>> Node<'n, &'n mut T> for MutWrapper<'n, N, T> {
impl<'n, T: Clone, N> Node<&'n mut T> for &'n MutWrapper<N>
where
&'n N: Node<T, Output = T>,
{
type Output = ();
fn eval(&'n self, value: &'n mut T) {
*value = self.0.eval(value.clone());
fn eval(self, value: &'n mut T) {
*value = (&self.0).eval(value.clone());
}
}
@ -41,8 +53,9 @@ mod test {
#[test]
fn map_node() {
let array = &mut [Color::from_rgbaf32(1.0, 0.0, 0.0, 1.0).unwrap()];
let map = ForEachNode(MutWrapper(GrayscaleNode, PhantomData), PhantomData);
map.eval(array.iter_mut());
(&GrayscaleNode).eval(Color::from_rgbf32_unchecked(1., 0., 0.));
let map = ForEachNode(MutWrapper(GrayscaleNode));
(&map).eval(array.iter_mut());
assert_eq!(array[0], Color::from_rgbaf32(0.33333334, 0.33333334, 0.33333334, 1.0).unwrap());
}
}

View File

@ -14,11 +14,11 @@ pub struct Color {
}
impl Color {
pub const BLACK: Color = Color::from_unsafe(0., 0., 0.);
pub const WHITE: Color = Color::from_unsafe(1., 1., 1.);
pub const RED: Color = Color::from_unsafe(1., 0., 0.);
pub const GREEN: Color = Color::from_unsafe(0., 1., 0.);
pub const BLUE: Color = Color::from_unsafe(0., 0., 1.);
pub const BLACK: Color = Color::from_rgbf32_unchecked(0., 0., 0.);
pub const WHITE: Color = Color::from_rgbf32_unchecked(1., 1., 1.);
pub const RED: Color = Color::from_rgbf32_unchecked(1., 0., 0.);
pub const GREEN: Color = Color::from_rgbf32_unchecked(0., 1., 0.);
pub const BLUE: Color = Color::from_rgbf32_unchecked(0., 0., 1.);
/// Returns `Some(Color)` if `red`, `green`, `blue` and `alpha` have a valid value. Negative numbers (including `-0.0`), NaN, and infinity are not valid values and return `None`.
/// Alpha values greater than `1.0` are not valid.
@ -40,7 +40,12 @@ impl Color {
}
/// Return an opaque `Color` from given `f32` RGB channels.
pub const fn from_unsafe(red: f32, green: f32, blue: f32) -> Color {
pub const fn from_rgbaf32_unchecked(red: f32, green: f32, blue: f32, alpha: f32) -> Color {
Color { red, green, blue, alpha }
}
/// Return an opaque `Color` from given `f32` RGB channels.
pub const fn from_rgbf32_unchecked(red: f32, green: f32, blue: f32) -> Color {
Color { red, green, blue, alpha: 1. }
}

View File

@ -2,20 +2,20 @@ use core::marker::PhantomData;
use crate::Node;
pub struct ComposeNode<'n, Input, First: Node<'n, Input>, Second> {
pub struct ComposeNode<First, Second, Input> {
first: First,
second: Second,
_phantom: PhantomData<&'n Input>,
_phantom: PhantomData<Input>,
}
impl<'n, Input, Inter, First, Second> Node<'n, Input> for ComposeNode<'n, Input, First, Second>
impl<Input, Inter, First, Second> Node<Input> for ComposeNode<First, Second, Input>
where
First: Node<'n, Input, Output = Inter>,
Second: Node<'n, Inter>,
First: Node<Input, Output = Inter>,
Second: Node<Inter>,
{
type Output = <Second as Node<'n, Inter>>::Output;
type Output = <Second as Node<Inter>>::Output;
fn eval(&'n self, input: Input) -> Self::Output {
fn eval(self, input: Input) -> Self::Output {
// evaluate the first node with the given input
// and then pipe the result from the first computation
// into the second node
@ -23,52 +23,105 @@ where
self.second.eval(arg)
}
}
impl<'n, Input, First, Second> ComposeNode<'n, Input, First, Second>
impl<'n, Input, Inter, First, Second> Node<Input> for &'n ComposeNode<First, Second, Input>
where
First: Node<'n, Input>,
Second: Node<'n, First::Output>,
First: Node<Input, Output = Inter> + Copy,
Second: Node<Inter> + Copy,
{
type Output = Second::Output;
fn eval(self, input: Input) -> Self::Output {
// evaluate the first node with the given input
// and then pipe the result from the first computation
// into the second node
let arg: Inter = self.first.eval(input);
(&self.second).eval(arg)
}
}
impl<'n, Input, First: 'n, Second: 'n> ComposeNode<First, Second, Input>
where
First: Node<Input>,
Second: Node<First::Output>,
{
pub const fn new(first: First, second: Second) -> Self {
ComposeNode::<'n, Input, First, Second> { first, second, _phantom: PhantomData }
ComposeNode::<First, Second, Input> { first, second, _phantom: PhantomData }
}
}
pub trait After<Inter>: Sized {
fn after<'n, First, Input>(self, first: First) -> ComposeNode<'n, Input, First, Self>
fn after<First, Input>(self, first: First) -> ComposeNode<First, Self, Input>
where
First: Node<'n, Input, Output = Inter>,
Self: Node<'n, Inter>,
First: Node<Input, Output = Inter>,
Self: Node<Inter>,
{
ComposeNode::new(first, self)
ComposeNode::<First, Self, Input> {
first,
second: self,
_phantom: PhantomData,
}
}
impl<'n, Second: Node<'n, I>, I> After<I> for Second {}
}
impl<Second: Node<I>, I> After<I> for Second {}
pub trait AfterRef<Inter>: Sized {
fn after<'n, First: 'n, Input>(&'n self, first: First) -> ComposeNode<First, &'n Self, Input>
where
First: Node<Input, Output = Inter> + Copy,
&'n Self: Node<Inter>,
Self: 'n,
{
ComposeNode::<First, &'n Self, Input> {
first,
second: self,
_phantom: PhantomData,
}
}
}
impl<'n, Second: 'n, I> AfterRef<I> for Second where &'n Second: Node<I> {}
pub struct ConsNode<Root>(pub Root);
impl<'n, Root, Input> Node<'n, Input> for ConsNode<Root>
impl<Root, Input> Node<Input> for ConsNode<Root>
where
Root: Node<'n, ()>,
Root: Node<()>,
{
type Output = (Input, <Root as Node<'n, ()>>::Output);
type Output = (Input, <Root as Node<()>>::Output);
fn eval(&'n self, input: Input) -> Self::Output {
fn eval(self, input: Input) -> Self::Output {
let arg = self.0.eval(());
(input, arg)
}
}
impl<'n, Root: Node<()> + Copy, Input> Node<Input> for &'n ConsNode<Root> {
type Output = (Input, Root::Output);
fn eval(self, input: Input) -> Self::Output {
let arg = (&self.0).eval(());
(input, arg)
}
}
pub struct ConsPassInputNode<Root>(pub Root);
impl<'n, Root, L, R> Node<'n, (L, R)> for ConsPassInputNode<Root>
impl<Root, L, R> Node<(L, R)> for ConsPassInputNode<Root>
where
Root: Node<'n, R>,
Root: Node<R>,
{
type Output = (L, <Root as Node<'n, R>>::Output);
type Output = (L, <Root as Node<R>>::Output);
fn eval(&'n self, input: (L, R)) -> Self::Output {
fn eval(self, input: (L, R)) -> Self::Output {
let arg = self.0.eval(input.1);
(input.0, arg)
}
}
impl<'n, Root, L, R> Node<(L, R)> for &'n ConsPassInputNode<Root>
where
&'n Root: Node<R>,
{
type Output = (L, <&'n Root as Node<R>>::Output);
fn eval(self, input: (L, R)) -> Self::Output {
let arg = (&self.0).eval(input.1);
(input.0, arg)
}
}

View File

@ -2,23 +2,28 @@ use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::sync::atomic::AtomicBool;
use crate::ops::CloneNode;
use crate::structural::ComposeNode;
use crate::Node;
#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct IntNode<const N: u32>;
impl<'n, const N: u32> Node<'n, ()> for IntNode<N> {
impl<const N: u32> Node<()> for IntNode<N> {
type Output = u32;
fn eval(&self, _: ()) -> u32 {
fn eval(self, _: ()) -> u32 {
N
}
}
#[derive(Default)]
#[derive(Default, Debug)]
pub struct ValueNode<T>(pub T);
impl<'n, T: 'n> Node<'n, ()> for ValueNode<T> {
impl<'n, T: 'n> Node<()> for ValueNode<T> {
type Output = T;
fn eval(self, _: ()) -> Self::Output {
self.0
}
}
impl<'n, T: 'n> Node<()> for &'n ValueNode<T> {
type Output = &'n T;
fn eval(&'n self, _: ()) -> Self::Output {
fn eval(self, _: ()) -> Self::Output {
&self.0
}
}
@ -29,39 +34,60 @@ impl<T> ValueNode<T> {
}
}
impl<'n, T: Clone + 'n> ValueNode<T> {
pub const fn clone(self) -> ComposeNode<'n, (), ValueNode<T>, CloneNode> {
ComposeNode::new(self, CloneNode)
}
}
impl<T> From<T> for ValueNode<T> {
fn from(value: T) -> Self {
ValueNode::new(value)
}
}
impl<T: Clone> Clone for ValueNode<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: Clone + Copy> Copy for ValueNode<T> {}
#[derive(Default)]
pub struct DefaultNode<T>(PhantomData<T>);
impl<'n, T: Default + 'n> Node<'n, ()> for DefaultNode<T> {
impl<T: Default> Node<()> for DefaultNode<T> {
type Output = T;
fn eval(&self, _: ()) -> T {
fn eval(self, _: ()) -> T {
T::default()
}
}
impl<'n, T: Default + 'n> Node<()> for &'n DefaultNode<T> {
type Output = T;
fn eval(self, _: ()) -> T {
T::default()
}
}
#[repr(C)]
/// Return the unit value
#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct UnitNode;
impl<'n> Node<'n, ()> for UnitNode {
impl Node<()> for UnitNode {
type Output = ();
fn eval(&'n self, _: ()) -> Self::Output {}
fn eval(self, _: ()) -> Self::Output {}
}
impl<'n> Node<()> for &'n UnitNode {
type Output = ();
fn eval(self, _: ()) -> Self::Output {}
}
pub struct InputNode<T>(MaybeUninit<T>, AtomicBool);
impl<'n, T: 'n> Node<'n, ()> for InputNode<T> {
impl<'n, T: 'n> Node<()> for InputNode<T> {
type Output = T;
fn eval(self, _: ()) -> Self::Output {
if self.1.load(core::sync::atomic::Ordering::SeqCst) {
unsafe { self.0.assume_init() }
} else {
panic!("tried to access an input before setting it")
}
}
}
impl<'n, T: 'n> Node<()> for &'n InputNode<T> {
type Output = &'n T;
fn eval(&'n self, _: ()) -> Self::Output {
fn eval(self, _: ()) -> Self::Output {
if self.1.load(core::sync::atomic::Ordering::SeqCst) {
unsafe { self.0.assume_init_ref() }
} else {

View File

@ -1,4 +1,3 @@
#![feature(type_alias_impl_trait)]
//pub mod value;
pub use graphene_core::{generic, ops /*, structural*/};

View File

@ -3,34 +3,26 @@ use once_cell::sync::OnceCell;
use std::marker::PhantomData;
/// Caches the output of a given Node and acts as a proxy
pub struct CacheNode<'n, CachedNode: Node<'n, I>, I> {
pub struct CacheNode<CachedNode: Node<I>, I> {
node: CachedNode,
cache: OnceCell<CachedNode::Output>,
_phantom: PhantomData<&'n ()>,
}
impl<'n, CashedNode: Node<'n, I>, I> Node<'n, I> for CacheNode<'n, CashedNode, I>
where
CashedNode::Output: 'n,
{
impl<'n, CashedNode: Node<I> + Copy, I> Node<I> for &'n CacheNode<CashedNode, I> {
type Output = &'n CashedNode::Output;
fn eval(&'n self, input: I) -> Self::Output {
fn eval(self, input: I) -> Self::Output {
self.cache.get_or_init(|| self.node.eval(input))
}
}
impl<'n, CachedNode: Node<'n, I>, I> CacheNode<'n, CachedNode, I> {
impl<'n, CachedNode: Node<I>, I> CacheNode<CachedNode, I> {
pub fn clear(&'n mut self) {
self.cache = OnceCell::new();
}
pub fn new(node: CachedNode) -> CacheNode<'n, CachedNode, I> {
CacheNode {
node,
cache: OnceCell::new(),
_phantom: PhantomData,
pub fn new(node: CachedNode) -> CacheNode<CachedNode, I> {
CacheNode { node, cache: OnceCell::new() }
}
}
}
impl<'n, CachedNode: Node<'n, I>, I> Cache for CacheNode<'n, CachedNode, I> {
impl<CachedNode: Node<I>, I> Cache for CacheNode<CachedNode, I> {
fn clear(&mut self) {
self.cache = OnceCell::new();
}

View File

@ -2,30 +2,36 @@ use core::marker::PhantomData;
use graphene_core::ops::FlatMapResultNode;
use graphene_core::raster::color::Color;
use graphene_core::structural::{ComposeNode, ConsNode};
use graphene_core::{generic::FnNode, ops::MapResultNode, structural::After, value::ValueNode, Node};
use graphene_core::{
generic::FnNode,
ops::MapResultNode,
structural::{After, AfterRef},
value::ValueNode,
Node,
};
use image::Pixel;
use std::path::Path;
pub struct MapNode<'n, MN: Node<'n, S>, I: IntoIterator<Item = S>, S>(pub MN, PhantomData<&'n (S, I)>);
pub struct MapNode<MN: Node<S>, I: IntoIterator<Item = S>, S>(pub MN, PhantomData<(S, I)>);
impl<'n, I: IntoIterator<Item = S>, MN: Node<'n, S>, S> Node<'n, I> for MapNode<'n, MN, I, S> {
impl<I: IntoIterator<Item = S>, MN: Node<S> + Copy, S> Node<I> for MapNode<MN, I, S> {
type Output = Vec<MN::Output>;
fn eval(&'n self, input: I) -> Self::Output {
fn eval(self, input: I) -> Self::Output {
input.into_iter().map(|x| self.0.eval(x)).collect()
}
}
impl<'n, I: IntoIterator<Item = S>, MN: Node<'n, S>, S> MapNode<'n, MN, I, S> {
impl<I: IntoIterator<Item = S>, MN: Node<S>, S> MapNode<MN, I, S> {
pub const fn new(mn: MN) -> Self {
MapNode(mn, PhantomData)
}
}
pub struct MapImageNode<'n, MN: Node<'n, Color, Output = Color>>(pub MN, PhantomData<&'n ()>);
pub struct MapImageNode<MN: Node<Color, Output = Color> + Copy>(pub MN);
impl<'n, MN: Node<'n, Color, Output = Color>> Node<'n, Image> for MapImageNode<'n, MN> {
impl<'n, MN: Node<Color, Output = Color> + Copy> Node<Image> for &'n MapImageNode<MN> {
type Output = Image;
fn eval(&'n self, input: Image) -> Self::Output {
fn eval(self, input: Image) -> Self::Output {
Image {
width: input.width,
height: input.height,
@ -34,9 +40,9 @@ impl<'n, MN: Node<'n, Color, Output = Color>> Node<'n, Image> for MapImageNode<'
}
}
impl<'n, MN: Node<'n, Color, Output = Color>> MapImageNode<'n, MN> {
impl<MN: Node<Color, Output = Color> + Copy> MapImageNode<MN> {
pub const fn new(mn: MN) -> Self {
MapImageNode(mn, PhantomData)
MapImageNode(mn)
}
}
@ -66,20 +72,20 @@ impl FileSystem for StdFs {
type Reader = Box<dyn std::io::Read>;
pub struct FileNode<P: AsRef<Path>, FS: FileSystem>(PhantomData<(P, FS)>);
impl<'n, P: AsRef<Path>, FS: FileSystem> Node<'n, (P, FS)> for FileNode<P, FS> {
impl<P: AsRef<Path>, FS: FileSystem> Node<(P, FS)> for FileNode<P, FS> {
type Output = Result<Reader, Error>;
fn eval(&'n self, input: (P, FS)) -> Self::Output {
fn eval(self, input: (P, FS)) -> Self::Output {
let (path, fs) = input;
fs.open(path)
}
}
pub struct BufferNode;
impl<'n, Reader: std::io::Read> Node<'n, Reader> for BufferNode {
impl<Reader: std::io::Read> Node<Reader> for BufferNode {
type Output = Result<Vec<u8>, Error>;
fn eval(&'n self, mut reader: Reader) -> Self::Output {
fn eval(self, mut reader: Reader) -> Self::Output {
let mut buffer = Vec::new();
reader.read_to_end(&mut buffer)?;
Ok(buffer)
@ -109,23 +115,18 @@ impl<'a> IntoIterator for &'a Image {
}
}
pub fn file_node<'n, P: AsRef<Path> + 'n>() -> impl Node<'n, P, Output = Result<Vec<u8>, Error>> {
pub fn file_node<'n, P: AsRef<Path> + 'n>() -> impl Node<P, Output = Result<Vec<u8>, Error>> {
let fs = ValueNode(StdFs).clone();
let fs = ConsNode(fs);
let file: ComposeNode<P, _, FileNode<P, _>> = FileNode(PhantomData).after(fs);
let buffer = FlatMapResultNode::new(BufferNode).after(file);
buffer
}
type Ret<'n> = impl Node<'n, (), Output = u32>;
let file: ComposeNode<_, _, P> = FileNode(PhantomData).after(fs);
pub fn test_node<'n>() -> Ret<'n> {
ValueNode(432).clone()
FlatMapResultNode::new(BufferNode).after(file)
}
pub fn image_node<'n, P: AsRef<Path> + 'n>() -> impl Node<'n, P, Output = Result<Image, Error>> {
pub fn image_node<'n, P: AsRef<Path> + 'n>() -> impl Node<P, Output = Result<Image, Error>> {
let file = file_node();
let image_loader = FnNode::new(|data: Vec<u8>| image::load_from_memory(&data).map_err(Error::Image).map(|image| image.into_rgba32f()));
let image: ComposeNode<'_, P, _, _> = FlatMapResultNode::new(image_loader).after(file);
let image: ComposeNode<_, _, P> = FlatMapResultNode::new(image_loader).after(file);
let convert_image = FnNode::new(|image: image::ImageBuffer<_, _>| {
let data = image
.enumerate_pixels()
@ -140,11 +141,11 @@ pub fn image_node<'n, P: AsRef<Path> + 'n>() -> impl Node<'n, P, Output = Result
data,
}
});
let image = MapResultNode::new(convert_image).after(image);
image
MapResultNode::new(convert_image).after(image)
}
pub fn export_image_node<'n>() -> impl Node<'n, (Image, &'n str), Output = Result<(), Error>> {
pub fn export_image_node<'n>() -> impl Node<(Image, &'n str), Output = Result<(), Error>> {
FnNode::new(|input: (Image, &str)| {
let (image, path) = input;
let mut new_image = image::ImageBuffer::new(image.width, image.height);
@ -152,7 +153,7 @@ pub fn export_image_node<'n>() -> impl Node<'n, (Image, &'n str), Output = Resul
let color: Color = *color;
assert!(x < image.width);
assert!(y < image.height);
*pixel = image::Rgba([color.r(), color.g(), color.b(), color.a()])
*pixel = image::Rgba(color.to_rgba8())
}
new_image.save(path).map_err(Error::Image)
})
@ -174,24 +175,13 @@ mod test {
#[test]
fn load_image() {
/*let image = image_node();
let image = image_node::<&str>();
let gray = MapImageNode::new(GrayscaleNode);
let gray_scale_picture = MapResultNode::new(gray).after(image);
let gray_scale_picture = gray_scale_picture.eval("image");
*/
let test_node = test_node();
{
let foo = test_node.eval(());
std::mem::drop(foo);
}
let grayscale_picture = MapResultNode::new(&gray).after(image);
let export = export_image_node();
/*let export = FnNode::new(|input: (&str, &str)| {
let (input, output) = input;*/
//let picture = gray_scale_picture.eval("/home/dennis/screenshot.png").unwrap().clone();
//export.eval((picture, "screenshot.png"));
/*});
export.eval(("screenshot.png", "/home/dennis/screenshot.png"));*/
let picture = grayscale_picture.eval("/home/dennis/screenshot.png").expect("failed to load image");
export.eval((picture, "/tmp/screenshot.png")).unwrap();
}
}