Incremental compilation and stable node IDs (#977)

* Generate stable node ids

* checkpoint

* Implement borrow tree

* Add eval function on borrow tree

* Refactor Node trait to fix lifetime issues

* Compiler infinite loop

* Impl compose pair

* Transition to double lifetime on trait

* Change node trait to use a generic arg for the input

* Start adapting node_macro

* Migrate more nodes to new macro

* Fix raster tests

* Port vector nodes

* Make Node trait object safe

* Fix FlatMapResultNode

* Translate most of gstd

* Fix DowncastBothNode

* Refactor node trait once again to allow for HRTB for type erased nodes

* Start working on type erased nodes

* Try getting DowncastBothNode to work

* Introduce Upcasting node + work on BorrowTree

* Make enough 'static to get the code to compile

* Transition DynamicExecutor to use borrow tree

* Make Compose Node use HRTB's

* Fix MapResultNode

* Disable blur test

* Add workaround for Composing type erased nodes

* Convert more nodes in the node_registry

* Convert more of the node_registry

* Add update tree fn and hook up to frontend

* Fix blur node

* Implement CacheNode

* Make frontend use graph compiler

* Fix document_node_types type declaration for most nodes

* Remove unused imports

* Move comment down

* Reuse nodes via borrow tree

* Deprecate trait based value in favor of TaggedValue

* Remove unsafe code in buffer creation

* Fix blur node

* Fix stable node id generation

* Fix types for Image adjustment document nodes

* Fix Imaginate Node

* Remove unused imports

* Remove log

* Fix off by one error

* Remove macro generated imaginate node entry

* Create parameterized add node

* Fix test case

* Remove link from layer_panel.rs

* Fix formatting
This commit is contained in:
Dennis Kobert
2023-02-07 20:06:24 +01:00
committed by Keavon Chambers
parent 77e69f4e5b
commit 620540d7cd
36 changed files with 1548 additions and 1869 deletions

View File

@@ -2,17 +2,10 @@ use core::marker::PhantomData;
use crate::Node;
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(self, input: I) -> Self::Output {
self.0(input)
}
}
impl<'n, T: Fn(I) -> O, O, I> Node<I> for &'n FnNode<T, I, O> {
impl<'i, T: Fn(I) -> O + 'i, O: 'i, I: 'i> Node<'i, I> for FnNode<T, I, O> {
type Output = O;
fn eval(self, input: I) -> Self::Output {
fn eval<'s: 'i>(&'s self, input: I) -> Self::Output {
self.0(input)
}
}
@@ -23,23 +16,14 @@ impl<T: Fn(I) -> O, I, O> FnNode<T, I, O> {
}
}
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> {
pub struct FnNodeWithState<'i, T: Fn(I, &'i State) -> O, I, O, State: 'i>(T, State, PhantomData<(&'i O, I)>);
impl<'i, I: 'i, O: 'i, State, T: Fn(I, &'i State) -> O + 'i> Node<'i, I> for FnNodeWithState<'i, T, I, O, State> {
type Output = O;
fn eval(self, input: I) -> Self::Output {
self.0(input, &self.1)
fn eval<'s: 'i>(&'s 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, &State) -> O, I, O, State> FnNodeWithState<'n, T, I, O, State> {
impl<'i, 's: 'i, I, O, State, T: Fn(I, &'i State) -> O> FnNodeWithState<'i, T, I, O, State> {
pub fn new(f: T, state: State) -> Self {
FnNodeWithState(f, state, PhantomData)
}

View File

@@ -7,11 +7,6 @@ extern crate alloc;
#[cfg(feature = "log")]
extern crate log;
#[cfg(feature = "async")]
use alloc::boxed::Box;
#[cfg(feature = "async")]
use async_trait::async_trait;
pub mod generic;
pub mod ops;
pub mod structural;
@@ -26,100 +21,32 @@ pub mod raster;
#[cfg(feature = "alloc")]
pub mod vector;
pub trait Node<T> {
type Output;
fn eval(self, input: T) -> Self::Output;
// pub trait Node: for<'n> NodeIO<'n> {
pub trait Node<'i, Input: 'i>: 'i {
type Output: 'i;
fn eval<'s: 'i>(&'s self, input: Input) -> Self::Output;
}
trait Input<I> {
unsafe fn input(&self, input: I);
}
/*impl<'i, I: 'i, O: 'i> Node<'i, I> for &'i dyn for<'n> Node<'n, I, Output = O> {
type Output = O;
pub trait RefNode<T> {
type Output;
fn eval_ref(&self, input: T) -> Self::Output;
}
impl<'n, N: 'n, I> RefNode<I> for &'n N
where
&'n N: Node<I>,
Self: 'n,
{
type Output = <&'n N as Node<I>>::Output;
fn eval_ref(&self, input: I) -> Self::Output {
self.eval(input)
}
}
pub trait AsRefNode<'n, T>
where
&'n Self: Node<T>,
Self: 'n,
{
type Output;
fn eval_box(&'n self, input: T) -> <Self>::Output;
}
impl<'n, N: 'n, I> AsRefNode<'n, I> for N
where
&'n N: Node<I>,
N: Node<I>,
Self: 'n,
{
type Output = <&'n N as Node<I>>::Output;
fn eval_box(&'n self, input: I) -> <Self>::Output {
self.eval(input)
}
}
impl<'n, T> Node<T> for &'n (dyn AsRefNode<'n, T, Output = T> + 'n) {
type Output = T;
fn eval(self, input: T) -> Self::Output {
self.eval_box(input)
}
}
#[cfg(feature = "async")]
#[async_trait]
pub trait AsyncNode<T> {
type Output;
async fn eval_async(self, input: T) -> Self::Output;
}
/*#[cfg(feature = "async")]
#[async_trait]
impl<'n, N: Node<T> + Send + Sync + 'n, T: Send + 'n> AsyncNode<T> for N {
type Output = N::Output;
async fn eval_async(self, input: T) -> Self::Output {
Node::eval(self, input)
fn eval<'s: 'i>(&'s self, input: I) -> Self::Output {
(**self).eval(input)
}
}*/
impl<'i, 'n: 'i, I: 'i, O: 'i> Node<'i, I> for &'n dyn for<'a> Node<'a, I, Output = O> {
type Output = O;
pub trait Cache {
fn clear(&mut self);
}
#[cfg(feature = "async")]
impl<N, I> Node<I> for Box<N>
where
N: Node<I>,
{
type Output = <N as Node<I>>::Output;
fn eval(self, input: I) -> Self::Output {
(*self).eval(input)
fn eval<'s: 'i>(&'s self, input: I) -> Self::Output {
(**self).eval(input)
}
}
#[cfg(feature = "async")]
impl<'n, N, I> Node<I> for &'n Box<N>
where
&'n N: Node<I>,
{
type Output = <&'n N as Node<I>>::Output;
fn eval(self, input: I) -> Self::Output {
self.as_ref().eval(input)
use core::pin::Pin;
#[cfg(feature = "alloc")]
impl<'i, I: 'i, O: 'i> Node<'i, I> for Pin<Box<dyn for<'a> Node<'a, I, Output = O> + 'i>> {
type Output = O;
fn eval<'s: 'i>(&'s self, input: I) -> Self::Output {
(**self).eval(input)
}
}

View File

@@ -1,41 +1,36 @@
use core::marker::PhantomData;
use core::ops::Add;
use crate::{Node, RefNode};
use crate::Node;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct AddNode;
impl<'n, L: Add<R, Output = O> + 'n, R, O: 'n> Node<(L, R)> for AddNode {
impl<'i, L: Add<R, Output = O> + 'i, R: 'i, O: 'i> Node<'i, (L, R)> for AddNode {
type Output = <L as Add<R>>::Output;
fn eval(self, input: (L, R)) -> Self::Output {
input.0 + input.1
}
}
impl<'n, L: Add<R, Output = O> + 'n, R, O: 'n> Node<(L, R)> for &'n AddNode {
type Output = <L as Add<R>>::Output;
fn eval(self, input: (L, R)) -> Self::Output {
input.0 + input.1
}
}
impl<'n, L: Add<R, Output = O> + 'n + Copy, R: Copy, O: 'n> Node<&'n (L, R)> for AddNode {
type Output = <L as Add<R>>::Output;
fn eval(self, input: &'n (L, R)) -> Self::Output {
input.0 + input.1
}
}
impl<'n, L: Add<R, Output = O> + 'n + Copy, R: Copy, O: 'n> Node<&'n (L, R)> for &'n AddNode {
type Output = <L as Add<R>>::Output;
fn eval(self, input: &'n (L, R)) -> Self::Output {
fn eval<'s: 'i>(&'s self, input: (L, R)) -> Self::Output {
input.0 + input.1
}
}
impl AddNode {
pub fn new() -> Self {
pub const fn new() -> Self {
Self
}
}
pub struct AddParameterNode<Second> {
second: Second,
}
#[node_macro::node_fn(AddParameterNode)]
fn flat_map<U, T>(first: U, second: T) -> <U as Add<T>>::Output
where
U: Add<T>,
{
first + second
}
/*
#[cfg(feature = "std")]
pub mod dynamic {
use super::*;
@@ -65,9 +60,9 @@ pub mod dynamic {
};
}
impl<'n> Node<(Dynamic<'n>, Dynamic<'n>)> for DynamicAddNode {
type Output = Dynamic<'n>;
fn eval(self, (left, right): (Dynamic, Dynamic)) -> Self::Output {
impl<'i> Node<(Dynamic<'i>, Dynamic<'i>)> for DynamicAddNode {
type Output = Dynamic<'i>;
fn eval<'s: 'i>(self, (left, right): (Dynamic, Dynamic)) -> Self::Output {
resolve_dynamic_types! { AddNode =>
(left: usize, right: usize)
(left: u8, right: u8)
@@ -85,106 +80,87 @@ pub mod dynamic {
(left: f64, right: f64) }
}
}
}
}*/
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CloneNode;
impl<'n, O: Clone> Node<&'n O> for CloneNode {
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct CloneNode<O>(PhantomData<O>);
impl<'i, O: Clone + 'i> Node<'i, &'i O> for CloneNode<O> {
type Output = O;
fn eval(self, input: &'n O) -> Self::Output {
fn eval<'s: 'i>(&'s self, input: &'i O) -> Self::Output {
input.clone()
}
}
impl<'n, O: Clone> Node<&'n O> for &CloneNode {
type Output = O;
fn eval(self, input: &'n O) -> Self::Output {
input.clone()
impl<O> CloneNode<O> {
pub const fn new() -> Self {
Self(PhantomData)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct FstNode;
impl<'n, T: 'n, U> Node<(T, U)> for FstNode {
type Output = T;
fn eval(self, input: (T, U)) -> Self::Output {
let (a, _) = input;
a
impl<'i, L: 'i, R: 'i> Node<'i, (L, R)> for FstNode {
type Output = L;
fn eval<'s: 'i>(&'s self, input: (L, R)) -> Self::Output {
input.0
}
}
impl<'n, T: 'n, U> Node<&'n (T, U)> for FstNode {
type Output = &'n T;
fn eval(self, input: &'n (T, U)) -> Self::Output {
let (a, _) = input;
a
impl FstNode {
pub fn new() -> Self {
Self
}
}
/// Destructures a Tuple of two values and returns the first one
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct SndNode;
impl<'n, T, U: 'n> Node<(T, U)> for SndNode {
type Output = U;
fn eval(self, input: (T, U)) -> Self::Output {
let (_, b) = input;
b
impl<'i, L: 'i, R: 'i> Node<'i, (L, R)> for SndNode {
type Output = R;
fn eval<'s: 'i>(&'s self, input: (L, R)) -> Self::Output {
input.1
}
}
impl<'n, T, U: 'n> Node<&'n (T, U)> for SndNode {
type Output = &'n U;
fn eval(self, input: &'n (T, U)) -> Self::Output {
let (_, b) = input;
b
impl SndNode {
pub fn new() -> Self {
Self
}
}
/// Destructures a Tuple of two values and returns them in reverse order
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct SwapNode;
impl<'n, T: 'n, U: 'n> Node<(T, U)> for SwapNode {
type Output = (U, T);
fn eval(self, input: (T, U)) -> Self::Output {
let (a, b) = input;
(b, a)
impl<'i, L: 'i, R: 'i> Node<'i, (L, R)> for SwapNode {
type Output = (R, L);
fn eval<'s: 'i>(&'s self, input: (L, R)) -> Self::Output {
(input.1, input.0)
}
}
impl<'n, T, U: 'n> Node<&'n (T, U)> for SwapNode {
type Output = (&'n U, &'n T);
fn eval(self, input: &'n (T, U)) -> Self::Output {
let (a, b) = input;
(b, a)
impl SwapNode {
pub fn new() -> Self {
Self
}
}
/// Return a tuple with two instances of the input argument
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct DupNode;
impl<'n, T: Clone + 'n> Node<T> for DupNode {
type Output = (T, T);
fn eval(self, input: T) -> Self::Output {
impl<'i, O: Clone + 'i> Node<'i, O> for DupNode {
type Output = (O, O);
fn eval<'s: 'i>(&'s self, input: O) -> Self::Output {
(input.clone(), input)
}
}
impl DupNode {
pub fn new() -> Self {
Self
}
}
/// Return the Input Argument
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct IdNode;
impl<T> Node<T> for IdNode {
type Output = T;
fn eval(self, input: T) -> Self::Output {
input
}
}
impl<'n, T> Node<T> for &'n IdNode {
type Output = T;
fn eval(self, input: T) -> Self::Output {
input
}
}
impl<T> RefNode<T> for IdNode {
type Output = T;
fn eval_ref(&self, input: T) -> Self::Output {
impl<'i, O: 'i> Node<'i, O> for IdNode {
type Output = O;
fn eval<'s: 'i>(&'s self, input: O) -> Self::Output {
input
}
}
@@ -197,75 +173,60 @@ impl IdNode {
/// Ascribe the node types
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct TypeNode<N, I, O>(pub N, pub PhantomData<(I, O)>);
impl<N: Node<I>, I> Node<I> for TypeNode<N, I, N::Output> {
type Output = N::Output;
fn eval(self, input: I) -> Self::Output {
pub struct TypeNode<N: for<'a> Node<'a, I>, I, O>(pub N, pub PhantomData<(I, O)>);
impl<'i, N, I: 'i, O: 'i> Node<'i, I> for TypeNode<N, I, O>
where
N: for<'n> Node<'n, I, Output = O>,
{
type Output = O;
fn eval<'s: 'i>(&'s self, input: I) -> Self::Output {
self.0.eval(input)
}
}
impl<N: Node<I> + Copy, I> Node<I> for &TypeNode<N, I, N::Output> {
type Output = N::Output;
fn eval(self, input: I) -> Self::Output {
self.0.eval(input)
}
} /*
impl<N: RefNode<I>, I> Node<I> for &TypeNode<N, I, N::Output> {
type Output = N::Output;
fn eval(self, input: I) -> Self::Output {
self.0.eval_ref(input)
}
}*/
impl<N: Node<I>, I> TypeNode<N, I, N::Output> {
impl<'i, N: for<'a> Node<'a, I>, I: 'i> TypeNode<N, I, <N as Node<'i, I>>::Output> {
pub fn new(node: N) -> Self {
Self(node, PhantomData)
}
}
impl<N: Node<I> + Clone, I> Clone for TypeNode<N, I, N::Output> {
impl<'i, N: for<'a> Node<'a, I> + Clone, I: 'i> Clone for TypeNode<N, I, <N as Node<'i, I>>::Output> {
fn clone(&self) -> Self {
Self(self.0.clone(), self.1)
}
}
impl<N: Node<I> + Copy, I> Copy for TypeNode<N, I, N::Output> {}
impl<'i, N: for<'a> Node<'a, I> + Copy, I: 'i> Copy for TypeNode<N, I, <N as Node<'i, I>>::Output> {}
pub struct MapResultNode<MN, I, E>(pub MN, pub PhantomData<(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(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))
}
/// input.map(|x| self.0.eval(x))
pub struct MapResultNode<I, E, Mn> {
node: Mn,
_i: PhantomData<I>,
_e: PhantomData<E>,
}
impl<MN, I, E> MapResultNode<MN, I, E> {
pub const fn new(mn: MN) -> Self {
Self(mn, PhantomData)
}
#[node_macro::node_fn(MapResultNode<_I, _E>)]
fn flat_map<_I, _E, N>(input: Result<_I, _E>, node: &'any_input N) -> Result<<N as Node<'input, _I>>::Output, _E>
where
N: for<'a> Node<'a, _I>,
{
input.map(|x| node.eval(x))
}
pub struct FlatMapResultNode<MN: Node<I>, I, E>(pub MN, pub PhantomData<(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(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),
Err(e) => Err(e),
}
}
pub struct FlatMapResultNode<I, O, E, Mn> {
node: Mn,
_i: PhantomData<I>,
_o: PhantomData<O>,
_e: PhantomData<E>,
}
impl<MN: Node<I>, I, E> FlatMapResultNode<MN, I, E> {
pub const fn new(mn: MN) -> Self {
Self(mn, PhantomData)
#[node_macro::node_fn(FlatMapResultNode<_I, _O, _E>)]
fn flat_map<_I, _O, _E, N>(input: Result<_I, _E>, node: &'any_input N) -> Result<_O, _E>
where
N: for<'a> Node<'a, _I, Output = Result<_O, _E>>,
{
match input.map(|x| node.eval(x)) {
Ok(Ok(x)) => Ok(x),
Ok(Err(e)) => Err(e),
Err(e) => Err(e),
}
}
@@ -277,36 +238,69 @@ mod test {
#[test]
pub fn dup_node() {
let value = ValueNode(4u32);
let dup = value.then(DupNode);
assert_eq!(dup.eval(()), (4, 4));
let dup = ComposeNode::new(value, DupNode::new());
assert_eq!(dup.eval(()), (&4, &4));
}
#[test]
pub fn id_node() {
let value = ValueNode(4u32).then(IdNode);
assert_eq!(value.eval(()), 4);
let value = ValueNode(4u32).then(IdNode::new());
assert_eq!(value.eval(()), &4);
}
#[test]
pub fn clone_node() {
let cloned = (&ValueNode(4u32)).then(CloneNode);
let cloned = ValueNode(4u32).then(CloneNode::new());
assert_eq!(cloned.eval(()), 4);
let type_erased = &CloneNode::new() as &dyn for<'a> Node<'a, &'a u32, Output = u32>;
assert_eq!(type_erased.eval(&4), 4);
let type_erased = &cloned as &dyn for<'a> Node<'a, (), Output = u32>;
assert_eq!(type_erased.eval(()), 4);
}
#[test]
pub fn fst_node() {
let fst = ValueNode((4u32, "a")).then(FstNode);
let fst = ValueNode((4u32, "a")).then(CloneNode::new()).then(FstNode::new());
assert_eq!(fst.eval(()), 4);
}
#[test]
pub fn snd_node() {
let fst = ValueNode((4u32, "a")).then(SndNode);
let fst = ValueNode((4u32, "a")).then(CloneNode::new()).then(SndNode::new());
assert_eq!(fst.eval(()), "a");
}
#[test]
pub fn object_safe() {
let fst = ValueNode((4u32, "a")).then(CloneNode::new()).then(SndNode::new());
let foo = &fst as &dyn Node<(), Output = &str>;
assert_eq!(foo.eval(()), "a");
}
#[test]
pub fn map_result() {
let value: ClonedNode<Result<&u32, ()>> = ClonedNode(Ok(&4u32));
assert_eq!(value.eval(()), Ok(&4u32));
static clone: &CloneNode<u32> = &CloneNode::new();
//let type_erased_clone = clone as &dyn for<'a> Node<'a, &'a u32, Output = u32>;
let map_result = MapResultNode::new(ValueNode::new(FnNode::new(|x: &u32| x.clone())));
//et type_erased = &map_result as &dyn for<'a> Node<'a, Result<&'a u32, ()>, Output = Result<u32, ()>>;
assert_eq!(map_result.eval(Ok(&4u32)), Ok(4u32));
let fst = value.then(map_result);
//let type_erased = &fst as &dyn for<'a> Node<'a, (), Output = Result<u32, ()>>;
assert_eq!(fst.eval(()), Ok(4u32));
}
#[test]
pub fn flat_map_result() {
let fst = ValueNode(Ok(&4u32)).then(CloneNode::new()); //.then(FlatMapResultNode::new(FnNode::new(|x| Ok(x))));
let fn_node: FnNode<_, &u32, Result<&u32, _>> = FnNode::new(|_| Err(8u32));
assert_eq!(fn_node.eval(&4u32), Err(8u32));
let flat_map = FlatMapResultNode::new(ValueNode::new(fn_node));
let fst = fst.then(flat_map);
assert_eq!(fst.eval(()), Err(8u32));
}
#[test]
pub fn add_node() {
let a = ValueNode(42u32);
let b = ValueNode(6u32);
let cons_a = ConsNode(a, PhantomData);
let cons_a = ConsNode::new(a);
let tuple = b.then(cons_a);
let sum = b.then(cons_a).then(AddNode);
let sum = tuple.then(AddNode::new());
assert_eq!(sum.eval(()), 48);
}
@@ -321,7 +315,7 @@ mod test {
let fnn = FnNode::new(&swap);
let fns = FnNodeWithState::new(int, 42u32);
assert_eq!(fnn.eval((1u32, 2u32)), (2, 1));
let result: u32 = (&fns).eval(());
let result: u32 = fns.eval(());
assert_eq!(result, 42);
}
}

View File

@@ -1,4 +1,4 @@
use core::fmt::Debug;
use core::{fmt::Debug, marker::PhantomData};
use crate::Node;
@@ -14,78 +14,62 @@ fn grayscale_color_node(input: Color) -> Color {
Color::from_rgbaf32_unchecked(avg, avg, avg, input.a())
}
#[derive(Debug)]
pub struct MapNode<Iter: Iterator, MapFn: Node<Iter::Item>> {
#[derive(Debug, Default)]
pub struct MapNode<MapFn> {
map_fn: MapFn,
_phantom: core::marker::PhantomData<Iter>,
}
impl<Iter: Iterator, MapFn: Node<Iter::Item> + Clone> Clone for MapNode<Iter, MapFn> {
#[node_macro::node_fn(MapNode)]
fn map_node<_Iter: Iterator, MapFnNode>(input: _Iter, map_fn: &'any_input MapFnNode) -> MapFnIterator<'input, 'input, _Iter, MapFnNode>
where
MapFnNode: for<'any_input> Node<'any_input, _Iter::Item>,
{
MapFnIterator::new(input, map_fn)
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct MapFnIterator<'i, 's, Iter, MapFn> {
iter: Iter,
map_fn: &'s MapFn,
_phantom: core::marker::PhantomData<&'i &'s ()>,
}
impl<'i, 's: 'i, Iter: Debug, MapFn> Debug for MapFnIterator<'i, 's, Iter, MapFn> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("MapFnIterator").field("iter", &self.iter).field("map_fn", &"MapFn").finish()
}
}
impl<'i, 's: 'i, Iter: Clone, MapFn> Clone for MapFnIterator<'i, 's, Iter, MapFn> {
fn clone(&self) -> Self {
Self {
map_fn: self.map_fn.clone(),
_phantom: self._phantom,
iter: self.iter.clone(),
map_fn: self.map_fn,
_phantom: core::marker::PhantomData,
}
}
}
impl<Iter: Iterator, MapFn: Node<Iter::Item> + Copy> Copy for MapNode<Iter, MapFn> {}
impl<'i, 's: 'i, Iter: Copy, MapFn> Copy for MapFnIterator<'i, 's, Iter, MapFn> {}
impl<Iter: Iterator, MapFn: Node<Iter::Item>> MapNode<Iter, MapFn> {
pub fn new(map_fn: MapFn) -> Self {
impl<'i, 's: 'i, Iter, MapFn> MapFnIterator<'i, 's, Iter, MapFn> {
pub fn new(iter: Iter, map_fn: &'s MapFn) -> Self {
Self {
iter,
map_fn,
_phantom: core::marker::PhantomData,
}
}
}
impl<Iter: Iterator<Item = Item>, MapFn: Node<Item, Output = Out>, Item, Out> Node<Iter> for MapNode<Iter, MapFn> {
type Output = MapFnIterator<Iter, MapFn>;
#[inline]
fn eval(self, input: Iter) -> Self::Output {
MapFnIterator::new(input, self.map_fn)
}
}
impl<Iter: Iterator<Item = Item>, MapFn: Node<Item, Output = Out> + Copy, Item, Out> Node<Iter> for &MapNode<Iter, MapFn> {
type Output = MapFnIterator<Iter, MapFn>;
#[inline]
fn eval(self, input: Iter) -> Self::Output {
MapFnIterator::new(input, self.map_fn)
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Clone)]
pub struct MapFnIterator<Iter, MapFn> {
iter: Iter,
map_fn: MapFn,
}
impl<Iter: Debug, MapFn> Debug for MapFnIterator<Iter, MapFn> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("MapFnIterator").field("iter", &self.iter).field("map_fn", &"MapFn").finish()
}
}
impl<Iter: Copy, MapFn: Copy> Copy for MapFnIterator<Iter, MapFn> {}
impl<Iter, MapFn> MapFnIterator<Iter, MapFn> {
pub fn new(iter: Iter, map_fn: MapFn) -> Self {
Self { iter, map_fn }
}
}
impl<B, I: Iterator, F> Iterator for MapFnIterator<I, F>
impl<'i, 's: 'i, I: Iterator + 's, F> Iterator for MapFnIterator<'i, 's, I, F>
where
F: Node<I::Item, Output = B> + Copy,
F: Node<'i, I::Item> + 'i,
Self: 'i,
{
type Item = B;
type Item = F::Output;
#[inline]
fn next(&mut self) -> Option<B> {
fn next(&mut self) -> Option<F::Output> {
self.iter.next().map(|x| self.map_fn.eval(x))
}
@@ -95,19 +79,14 @@ where
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct WeightedAvgNode<Iter> {
_phantom: core::marker::PhantomData<Iter>,
}
#[derive(Debug, Clone, Copy)]
pub struct WeightedAvgNode {}
impl<Iter> WeightedAvgNode<Iter> {
pub fn new() -> Self {
Self { _phantom: core::marker::PhantomData }
}
}
#[inline]
fn weighted_avg_node<Iter: Iterator<Item = (Color, f32)> + Clone>(input: Iter) -> Color {
#[node_macro::node_fn(WeightedAvgNode)]
fn weighted_avg_node<_Iter: Iterator<Item = (Color, f32)>>(input: _Iter) -> Color
where
_Iter: Clone,
{
let total_weight: f32 = input.clone().map(|(_, weight)| weight).sum();
let total_r: f32 = input.clone().map(|(color, weight)| color.r() * weight).sum();
let total_g: f32 = input.clone().map(|(color, weight)| color.g() * weight).sum();
@@ -116,28 +95,10 @@ fn weighted_avg_node<Iter: Iterator<Item = (Color, f32)> + Clone>(input: Iter) -
Color::from_rgbaf32_unchecked(total_r / total_weight, total_g / total_weight, total_b / total_weight, total_a / total_weight)
}
impl<Iter: Iterator<Item = (Color, f32)> + Clone> Node<Iter> for WeightedAvgNode<Iter> {
type Output = Color;
#[inline]
fn eval(self, input: Iter) -> Self::Output {
weighted_avg_node(input)
}
}
impl<Iter: Iterator<Item = (Color, f32)> + Clone> Node<Iter> for &WeightedAvgNode<Iter> {
type Output = Color;
#[inline]
fn eval(self, input: Iter) -> Self::Output {
weighted_avg_node(input)
}
}
#[derive(Debug, Clone, Copy)]
#[derive(Debug)]
pub struct GaussianNode<Sigma> {
sigma: Sigma,
}
#[node_macro::node_fn(GaussianNode)]
fn gaussian_node(input: f32, sigma: f64) -> f32 {
let sigma = sigma as f32;
@@ -157,42 +118,47 @@ fn distance_node(input: (i32, i32)) -> f32 {
pub struct ImageIndexIterNode;
#[node_macro::node_fn(ImageIndexIterNode)]
fn image_index_iter_node(input: ImageSlice<'static>) -> core::ops::Range<u32> {
fn image_index_iter_node(input: ImageSlice<'input>) -> core::ops::Range<u32> {
0..(input.width * input.height)
}
#[derive(Debug, Clone, Copy)]
pub struct WindowNode<Radius, Image> {
#[derive(Debug)]
pub struct WindowNode<Radius: for<'i> Node<'i, (), Output = u32>, Image: for<'i> Node<'i, (), Output = ImageSlice<'i>>> {
radius: Radius,
image: Image,
}
impl<Radius, Image> WindowNode<Radius, Image> {
pub fn new(radius: Radius, image: Image) -> Self {
impl<'input, S0: 'input, S1: 'input> Node<'input, u32> for WindowNode<S0, S1>
where
S0: for<'any_input> Node<'any_input, (), Output = u32>,
S1: for<'any_input> Node<'any_input, (), Output = ImageSlice<'any_input>>,
{
type Output = ImageWindowIterator<'input>;
#[inline]
fn eval<'node: 'input>(&'node self, input: u32) -> Self::Output {
let radius = self.radius.eval(());
let image = self.image.eval(());
{
let iter = ImageWindowIterator::new(image, radius, input);
iter
}
}
}
impl<S0, S1> WindowNode<S0, S1>
where
S0: for<'any_input> Node<'any_input, (), Output = u32>,
S1: for<'any_input> Node<'any_input, (), Output = ImageSlice<'any_input>>,
{
pub const fn new(radius: S0, image: S1) -> Self {
Self { radius, image }
}
}
impl<'a, Radius: Node<(), Output = u32>, Image: Node<(), Output = ImageSlice<'a>>> Node<u32> for WindowNode<Radius, Image> {
type Output = ImageWindowIterator<'a>;
#[inline]
fn eval(self, input: u32) -> Self::Output {
let radius = self.radius.eval(());
let image = self.image.eval(());
let iter = ImageWindowIterator::new(image, radius, input);
iter
}
}
impl<'a, 'b: 'a, Radius: Node<(), Output = u32> + Copy, Index: Node<(), Output = ImageSlice<'b>> + Copy> Node<u32> for &'a WindowNode<Radius, Index> {
type Output = ImageWindowIterator<'a>;
#[inline]
fn eval(self, input: u32) -> Self::Output {
let radius = self.radius.eval(());
let image = self.image.eval(());
let iter = ImageWindowIterator::new(image, radius, input);
iter
}
}
/*
#[node_macro::node_fn(WindowNode)]
fn window_node(input: u32, radius: u32, image: ImageSlice<'input>) -> ImageWindowIterator<'input> {
let iter = ImageWindowIterator::new(image, radius, input);
iter
}*/
#[derive(Debug, Clone, Copy)]
pub struct ImageWindowIterator<'a> {
@@ -245,124 +211,74 @@ impl<'a> Iterator for ImageWindowIterator<'a> {
}
}
#[derive(Debug, Clone, Copy)]
pub struct MapSndNode<MapFn> {
#[derive(Debug)]
pub struct MapSndNode<First, Second, MapFn> {
map_fn: MapFn,
_first: PhantomData<First>,
_second: PhantomData<Second>,
}
impl<MapFn> MapSndNode<MapFn> {
pub fn new(map_fn: MapFn) -> Self {
Self { map_fn }
}
}
impl<MapFn: Node<I>, I, F> Node<(F, I)> for MapSndNode<MapFn> {
type Output = (F, MapFn::Output);
#[inline]
fn eval(self, input: (F, I)) -> Self::Output {
(input.0, self.map_fn.eval(input.1))
}
}
impl<MapFn: Node<I> + Copy, I, F> Node<(F, I)> for &MapSndNode<MapFn> {
type Output = (F, MapFn::Output);
#[inline]
fn eval(self, input: (F, I)) -> Self::Output {
(input.0, self.map_fn.eval(input.1))
}
}
#[derive(Debug, Clone, Copy)]
pub struct BrightenColorNode<N: Node<(), Output = f32>>(N);
impl<N: Node<(), Output = f32>> Node<Color> for BrightenColorNode<N> {
type Output = Color;
fn eval(self, color: Color) -> Color {
let brightness = self.0.eval(());
let per_channel = |col: f32| (col + brightness / 255.).clamp(0., 1.);
Color::from_rgbaf32_unchecked(per_channel(color.r()), per_channel(color.g()), per_channel(color.b()), color.a())
}
}
impl<N: Node<(), Output = f32> + Copy> Node<Color> for &BrightenColorNode<N> {
type Output = Color;
fn eval(self, color: Color) -> Color {
let brightness = self.0.eval(());
let per_channel = |col: f32| (col + brightness / 255.).clamp(0., 1.);
Color::from_rgbaf32_unchecked(per_channel(color.r()), per_channel(color.g()), per_channel(color.b()), color.a())
}
}
impl<N: Node<(), Output = f32> + Copy> BrightenColorNode<N> {
pub fn new(node: N) -> Self {
Self(node)
}
}
#[derive(Debug, Clone, Copy)]
pub struct GammaColorNode<N: Node<(), Output = f32>>(N);
impl<N: Node<(), Output = f32>> Node<Color> for GammaColorNode<N> {
type Output = Color;
fn eval(self, color: Color) -> Color {
let gamma = self.0.eval(());
let per_channel = |col: f32| col.powf(gamma);
Color::from_rgbaf32_unchecked(per_channel(color.r()), per_channel(color.g()), per_channel(color.b()), color.a())
}
}
impl<N: Node<(), Output = f32> + Copy> Node<Color> for &GammaColorNode<N> {
type Output = Color;
fn eval(self, color: Color) -> Color {
let gamma = self.0.eval(());
let per_channel = |col: f32| col.powf(gamma);
Color::from_rgbaf32_unchecked(per_channel(color.r()), per_channel(color.g()), per_channel(color.b()), color.a())
}
}
impl<N: Node<(), Output = f32> + Copy> GammaColorNode<N> {
pub fn new(node: N) -> Self {
Self(node)
}
}
#[derive(Debug, Clone, Copy)]
#[cfg(not(target_arch = "spirv"))]
pub struct HueShiftColorNode<N: Node<(), Output = f32>>(N);
#[cfg(not(target_arch = "spirv"))]
impl<N: Node<(), Output = f32>> Node<Color> for HueShiftColorNode<N> {
type Output = Color;
fn eval(self, color: Color) -> Color {
let hue_shift = self.0.eval(());
let [hue, saturation, lightness, alpha] = color.to_hsla();
Color::from_hsla(hue + hue_shift / 360., saturation, lightness, alpha)
}
}
#[cfg(not(target_arch = "spirv"))]
impl<N: Node<(), Output = f32> + Copy> Node<Color> for &HueShiftColorNode<N> {
type Output = Color;
fn eval(self, color: Color) -> Color {
let hue_shift = self.0.eval(());
let [hue, saturation, lightness, alpha] = color.to_hsla();
Color::from_hsla(hue + hue_shift / 360., saturation, lightness, alpha)
}
}
#[cfg(not(target_arch = "spirv"))]
impl<N: Node<(), Output = f32> + Copy> HueShiftColorNode<N> {
pub fn new(node: N) -> Self {
Self(node)
}
}
pub struct ForEachNode<MN>(pub MN);
impl<'n, I: Iterator<Item = S>, MN: 'n, S> Node<I> for &'n ForEachNode<MN>
#[node_macro::node_fn(MapSndNode< _First, _Second>)]
fn map_snd_node<MapFn, _First, _Second>(input: (_First, _Second), map_fn: &'any_input MapFn) -> (_First, <MapFn as Node<'input, _Second>>::Output)
where
&'n MN: Node<S, Output = ()>,
MapFn: for<'any_input> Node<'any_input, _Second>,
{
type Output = ();
fn eval(self, input: I) -> Self::Output {
input.for_each(|x| (&self.0).eval(x))
let (a, b) = input;
(a, map_fn.eval(b))
}
#[derive(Debug)]
pub struct BrightenColorNode<Brightness> {
brightness: Brightness,
}
#[node_macro::node_fn(BrightenColorNode)]
fn brighten_color_node(color: Color, brightness: f32) -> Color {
let per_channel = |col: f32| (col + brightness / 255.).clamp(0., 1.);
Color::from_rgbaf32_unchecked(per_channel(color.r()), per_channel(color.g()), per_channel(color.b()), color.a())
}
#[derive(Debug)]
pub struct GammaColorNode<Gamma> {
gamma: Gamma,
}
#[node_macro::node_fn(GammaColorNode)]
fn gamma_color_node(color: Color, gamma: f32) -> Color {
let per_channel = |col: f32| col.powf(gamma);
Color::from_rgbaf32_unchecked(per_channel(color.r()), per_channel(color.g()), per_channel(color.b()), color.a())
}
#[cfg(not(target_arch = "spirv"))]
pub use hue_shift::HueShiftColorNode;
#[cfg(not(target_arch = "spirv"))]
mod hue_shift {
use super::*;
#[derive(Debug)]
pub struct HueShiftColorNode<Angle> {
angle: Angle,
}
#[node_macro::node_fn(HueShiftColorNode)]
fn hue_shift_color_node(color: Color, angle: f32) -> Color {
let hue_shift = angle;
let [hue, saturation, lightness, alpha] = color.to_hsla();
Color::from_hsla(hue + hue_shift / 360., saturation, lightness, alpha)
}
}
#[derive(Debug)]
pub struct ForEachNode<Iter, MapNode> {
map_node: MapNode,
_iter: PhantomData<Iter>,
}
#[node_macro::node_fn(ForEachNode<_Iter>)]
fn map_node<_Iter: Iterator, MapNode>(input: _Iter, map_node: &'any_input MapNode) -> ()
where
MapNode: for<'any_input> Node<'any_input, _Iter::Item, Output = ()> + 'input,
{
input.for_each(|x| map_node.eval(x));
}
use dyn_any::{DynAny, StaticType};
@@ -396,47 +312,24 @@ impl<'a> IntoIterator for &'a ImageSlice<'a> {
}
}
#[derive(Debug, Clone, Copy)]
pub struct MapImageSliceNode<MapFn>(MapFn);
#[derive(Debug)]
pub struct ImageDimensionsNode;
impl<MapFn> MapImageSliceNode<MapFn> {
pub fn new(map_fn: MapFn) -> Self {
Self(map_fn)
}
}
impl<'a, MapFn: Node<ImageSlice<'a>, Output = Vec<Color>>> Node<ImageSlice<'a>> for MapImageSliceNode<MapFn> {
type Output = Image;
fn eval(self, image: ImageSlice<'a>) -> Self::Output {
let data = self.0.eval(image);
Image {
width: image.width,
height: image.height,
data,
}
}
}
impl<'a, MapFn: Copy + Node<ImageSlice<'a>, Output = Vec<Color>>> Node<ImageSlice<'a>> for &MapImageSliceNode<MapFn> {
type Output = Image;
fn eval(self, image: ImageSlice<'a>) -> Self::Output {
let data = self.0.eval(image);
Image {
width: image.width,
height: image.height,
data,
}
}
#[node_macro::node_fn(ImageDimensionsNode)]
fn dimensions_node(input: ImageSlice<'input>) -> (u32, u32) {
(input.width, input.height)
}
#[cfg(feature = "alloc")]
pub use image::{CollectNode, Image, ImageRefNode};
pub use image::{CollectNode, Image, ImageRefNode, MapImageSliceNode};
#[cfg(feature = "alloc")]
mod image {
use super::{Color, ImageSlice};
use crate::Node;
use alloc::vec::Vec;
use dyn_any::{DynAny, StaticType};
#[derive(Clone, Debug, PartialEq, DynAny, Default, specta::Type)]
#[derive(Clone, Debug, PartialEq, DynAny, Default, specta::Type, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Image {
pub width: u32,
@@ -477,82 +370,63 @@ mod image {
#[derive(Debug, Clone, Copy, Default)]
pub struct ImageRefNode;
impl ImageRefNode {
pub fn new() -> Self {
Self
}
#[node_macro::node_fn(ImageRefNode)]
fn image_ref_node(image: &'input Image) -> ImageSlice<'input> {
image.as_slice()
}
impl<'a> Node<&'a Image> for ImageRefNode {
type Output = ImageSlice<'a>;
fn eval(self, image: &'a Image) -> Self::Output {
image.as_slice()
}
#[derive(Debug, Clone)]
pub struct CollectNode {}
#[node_macro::node_fn(CollectNode)]
fn collect_node<_Iter>(input: _Iter) -> Vec<_Iter::Item>
where
_Iter: Iterator,
{
input.collect()
}
impl<'a> Node<&'a Image> for &ImageRefNode {
type Output = ImageSlice<'a>;
fn eval(self, image: &'a Image) -> Self::Output {
image.as_slice()
}
#[derive(Debug)]
pub struct MapImageSliceNode<Data> {
data: Data,
}
#[derive(Debug, Clone, Copy)]
pub struct CollectNode;
use crate::Node;
impl<Iter: Iterator> Node<Iter> for CollectNode {
type Output = Vec<Iter::Item>;
fn eval(self, iter: Iter) -> Self::Output {
iter.collect()
}
}
impl<Iter: Iterator> Node<Iter> for &CollectNode {
type Output = Vec<Iter::Item>;
fn eval(self, iter: Iter) -> Self::Output {
iter.collect()
#[node_macro::node_fn(MapImageSliceNode)]
fn map_node(input: (u32, u32), data: Vec<Color>) -> Image {
Image {
width: input.0,
height: input.1,
data,
}
}
}
/*pub struct MutWrapper<N>(pub N);
impl<'n, T: Clone, N> Node<&'n mut T> for &'n MutWrapper<N>
where
&'n N: Node<T, Output = T>,
{
type Output = ();
fn eval(self, value: &'n mut T) {
*value = (&self.0).eval(value.clone());
}
}*/
#[cfg(test)]
mod test {
use crate::{
ops::TypeNode,
structural::{ComposeNode, Then},
value::ValueNode,
};
use crate::{ops::CloneNode, structural::Then, value::ValueNode, Node};
use super::*;
use alloc::vec::Vec;
#[test]
fn map_node() {
// let array = &mut [Color::from_rgbaf32(1.0, 0.0, 0.0, 1.0).unwrap()];
(&GrayscaleColorNode).eval(Color::from_rgbf32_unchecked(1., 0., 0.));
GrayscaleColorNode.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());*/
}
#[test]
fn window_node() {
let radius = ValueNode::new(1u32);
static DATA: &[Color] = &[Color::from_rgbf32_unchecked(1., 0., 0.); 25];
let image = ValueNode::<_>::new(ImageSlice { width: 5, height: 5, data: DATA });
use alloc::vec;
let radius = ValueNode::new(1u32).then(CloneNode::new());
let image = ValueNode::<_>::new(Image {
width: 5,
height: 5,
data: vec![Color::from_rgbf32_unchecked(1., 0., 0.); 25],
});
let image = image.then(ImageRefNode::new());
let window = WindowNode::new(radius, image);
//let window: TypeNode<_, u32, ImageWindowIterator<'static>> = TypeNode::new(window);
let vec = window.eval(0);
assert_eq!(vec.count(), 4);
let vec = window.eval(5);
@@ -561,29 +435,50 @@ mod test {
assert_eq!(vec.count(), 9);
}
// TODO: I can't be bothered to fix this test rn
/*
#[test]
fn blur_node() {
let radius = ValueNode::new(1u32);
let sigma = ValueNode::new(3f64);
static DATA: &[Color] = &[Color::from_rgbf32_unchecked(1., 0., 0.); 20];
let image = ValueNode::<_>::new(ImageSlice { width: 10, height: 2, data: DATA });
use alloc::vec;
let radius = ValueNode::new(1u32).then(CloneNode::new());
let sigma = ValueNode::new(3f64).then(CloneNode::new());
let radius = ValueNode::new(1u32).then(CloneNode::new());
let image = ValueNode::<_>::new(Image {
width: 5,
height: 5,
data: vec![Color::from_rgbf32_unchecked(1., 0., 0.); 25],
});
let image = image.then(ImageRefNode::new());
let window = WindowNode::new(radius, image);
let window: TypeNode<_, u32, ImageWindowIterator<'static>> = TypeNode::new(window);
let pos_to_dist = MapSndNode::new(DistanceNode);
let distance = window.then(MapNode::new(pos_to_dist));
let map_gaussian = MapSndNode::new(GaussianNode::new(sigma));
let map_distances: MapNode<_, MapSndNode<_>> = MapNode::new(map_gaussian);
let window: TypeNode<_, u32, ImageWindowIterator<'_>> = TypeNode::new(window);
let distance = ValueNode::new(DistanceNode::new());
let pos_to_dist = MapSndNode::new(distance);
let type_erased = &window as &dyn for<'a> Node<'a, u32, Output = ImageWindowIterator<'a>>;
type_erased.eval(0);
let map_pos_to_dist = MapNode::new(ValueNode::new(pos_to_dist));
let type_erased = &map_pos_to_dist as &dyn for<'a> Node<'a, u32, Output = ImageWindowIterator<'a>>;
type_erased.eval(0);
let distance = window.then(map_pos_to_dist);
let map_gaussian = MapSndNode::new(ValueNode(GaussianNode::new(sigma)));
let map_gaussian: TypeNode<_, (_, f32), (_, f32)> = TypeNode::new(map_gaussian);
let map_gaussian = ValueNode(map_gaussian);
let map_gaussian: TypeNode<_, (), &_> = TypeNode::new(map_gaussian);
let map_distances = MapNode::new(map_gaussian);
let map_distances: TypeNode<_, _, MapFnIterator<'_, '_, _, _>> = TypeNode::new(map_distances);
let gaussian_iter = distance.then(map_distances);
let avg = gaussian_iter.then(WeightedAvgNode::new());
let avg: TypeNode<_, u32, Color> = TypeNode::new(avg);
let blur_iter = MapNode::new(avg);
let blur_iter = MapNode::new(ValueNode::new(avg));
let blur = image.then(ImageIndexIterNode).then(blur_iter);
let blur: TypeNode<_, (), MapFnIterator<_, _>> = TypeNode::new(blur);
let collect = CollectNode {};
let collect = CollectNode::new();
let vec = collect.eval(0..10);
assert_eq!(vec.len(), 10);
let vec = ComposeNode::new(blur, collect);
let vec: TypeNode<_, (), Vec<Color>> = TypeNode::new(vec);
let _ = blur.eval(());
let vec = blur.then(collect);
let _image = vec.eval(());
}
*/
}

View File

@@ -1,3 +1,5 @@
use core::hash::Hash;
use dyn_any::{DynAny, StaticType};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
@@ -26,6 +28,16 @@ pub struct Color {
alpha: f32,
}
#[allow(clippy::derive_hash_xor_eq)]
impl Hash for Color {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.red.to_bits().hash(state);
self.green.to_bits().hash(state);
self.blue.to_bits().hash(state);
self.alpha.to_bits().hash(state);
}
}
impl Color {
pub const BLACK: Color = Color::from_rgbf32_unchecked(0., 0., 0.);
pub const WHITE: Color = Color::from_rgbf32_unchecked(1., 1., 1.);

View File

@@ -1,144 +1,92 @@
use core::marker::PhantomData;
use crate::{AsRefNode, Node, RefNode};
use crate::Node;
#[derive(Debug, Clone, Copy)]
pub struct ComposeNode<First, Second, Input> {
pub struct ComposeNode<First: for<'i> Node<'i, I>, Second: for<'i> Node<'i, <First as Node<'i, I>>::Output>, I> {
first: First,
second: Second,
_phantom: PhantomData<Input>,
phantom: PhantomData<I>,
}
impl<Input, Inter, First, Second> Node<Input> for ComposeNode<First, Second, Input>
impl<'i, Input: 'i, First, Second> Node<'i, Input> for ComposeNode<First, Second, Input>
where
First: Node<Input, Output = Inter>,
Second: Node<Inter>,
First: for<'a> Node<'a, Input> + 'i,
Second: for<'a> Node<'a, <First as Node<'a, Input>>::Output> + 'i,
{
type Output = <Second as Node<Inter>>::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);
type Output = <Second as Node<'i, <First as Node<'i, Input>>::Output>>::Output;
fn eval<'s: 'i>(&'s self, input: Input) -> Self::Output {
let arg = self.first.eval(input);
self.second.eval(arg)
}
}
impl<'n, Input, Inter, First, Second> Node<Input> for &'n ComposeNode<First, Second, Input>
impl<First, Second, Input> ComposeNode<First, Second, Input>
where
First: AsRefNode<'n, Input, Output = Inter>,
Second: AsRefNode<'n, Inter>,
&'n First: Node<Input, Output = Inter>,
&'n Second: Node<Inter>,
First: for<'a> Node<'a, Input>,
Second: for<'a> Node<'a, <First as Node<'a, Input>>::Output>,
{
type Output = <Second as AsRefNode<'n, Inter>>::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_box(input);
(self.second).eval_box(arg)
}
}
impl<Input, Inter, First, Second> RefNode<Input> for ComposeNode<First, Second, Input>
where
First: RefNode<Input, Output = Inter> + Copy,
Second: RefNode<Inter> + Copy,
{
type Output = <Second as RefNode<Inter>>::Output;
fn eval_ref(&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_ref(input);
(self.second).eval_ref(arg)
}
}
impl<Input: 'static, First: 'static, Second: 'static> dyn_any::StaticType for ComposeNode<First, Second, Input> {
type Static = ComposeNode<First, Second, Input>;
}
impl<'n, Input, First: 'n, Second: 'n> ComposeNode<First, Second, Input> {
pub const fn new(first: First, second: Second) -> Self {
ComposeNode::<First, Second, Input> { first, second, _phantom: PhantomData }
ComposeNode::<First, Second, Input> { first, second, phantom: PhantomData }
}
}
pub trait Then<Inter, Input>: Sized {
// impl Clone for ComposeNode<First, Second, Input>
impl<First, Second, Input> Clone for ComposeNode<First, Second, Input>
where
First: for<'a> Node<'a, Input> + Clone,
Second: for<'a> Node<'a, <First as Node<'a, Input>>::Output> + Clone,
{
fn clone(&self) -> Self {
ComposeNode::<First, Second, Input> {
first: self.first.clone(),
second: self.second.clone(),
phantom: PhantomData,
}
}
}
pub trait Then<'i, Input: 'i>: Sized {
fn then<Second>(self, second: Second) -> ComposeNode<Self, Second, Input>
where
Self: Node<Input, Output = Inter>,
Second: Node<Inter>,
Self: for<'a> Node<'a, Input>,
Second: for<'a> Node<'a, <Self as Node<'a, Input>>::Output>,
{
ComposeNode::<Self, Second, Input> {
first: self,
second,
_phantom: PhantomData,
}
ComposeNode::new(self, second)
}
}
impl<First: Node<Input, Output = Inter>, Inter, Input> Then<Inter, Input> for First {}
impl<'i, First: for<'a> Node<'a, Input>, Input: 'i> Then<'i, Input> for First {}
pub trait ThenRef<Inter, Input>: Sized {
fn after<'n, Second: 'n>(&'n self, second: Second) -> ComposeNode<&'n Self, Second, Input>
where
&'n Self: Node<Input, Output = Inter> + Copy,
Second: Node<Inter>,
Self: 'n,
{
ComposeNode::<&'n Self, Second, Input> {
first: self,
second,
_phantom: PhantomData,
}
}
}
impl<'n, First: 'n, Inter, Input> ThenRef<Inter, Input> for First where &'n First: Node<Input, Output = Inter> {}
pub struct ConsNode<I: From<()>, Root>(pub Root, PhantomData<I>);
#[cfg(feature = "async")]
pub trait ThenBox<Inter, Input> {
fn then<'n, Second: 'n>(self, second: Second) -> ComposeNode<Self, Second, Input>
where
alloc::boxed::Box<Self>: Node<Input, Output = Inter>,
Second: Node<Inter> + Copy,
Self: Sized,
{
ComposeNode::<Self, Second, Input> {
first: self,
second,
_phantom: PhantomData,
}
}
}
#[cfg(feature = "async")]
impl<'n, First: 'n, Inter, Input> ThenBox<Inter, Input> for alloc::boxed::Box<First> where &'n alloc::boxed::Box<First>: Node<Input, Output = Inter> {}
pub struct ConsNode<Root, T: From<()>>(pub Root, pub PhantomData<T>);
impl<Root, Input, T: From<()>> Node<Input> for ConsNode<Root, T>
impl<'i, Root, Input: 'i, I: 'i + From<()>> Node<'i, Input> for ConsNode<I, Root>
where
Root: Node<T>,
Root: Node<'i, I>,
{
type Output = (Input, <Root as Node<T>>::Output);
fn eval(self, input: Input) -> Self::Output {
let arg = self.0.eval(().into());
(input, arg)
}
}
impl<'n, Root: Node<T> + Copy, T: From<()>, Input> Node<Input> for &'n ConsNode<Root, T> {
type Output = (Input, Root::Output);
fn eval(self, input: Input) -> Self::Output {
let arg = self.0.eval(().into());
fn eval<'s: 'i>(&'s self, input: Input) -> Self::Output {
let arg = self.0.eval(I::from(()));
(input, arg)
}
}
impl<Root, T: From<()>> ConsNode<Root, T> {
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 crate::{ops::IdNode, value::ValueNode};
use super::*;
#[test]
fn compose() {
let value = ValueNode::new(4u32);
let compose = value.then(IdNode::new());
assert_eq!(compose.eval(()), &4u32);
let type_erased = &compose as &dyn for<'i> Node<'i, (), Output = &'i u32>;
assert_eq!(type_erased.eval(()), &4u32);
}
}

View File

@@ -1,29 +1,23 @@
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::sync::atomic::AtomicBool;
use crate::Node;
#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct IntNode<const N: u32>;
impl<const N: u32> Node<()> for IntNode<N> {
impl<'i, const N: u32> Node<'i, ()> for IntNode<N> {
type Output = u32;
fn eval(self, _: ()) -> u32 {
fn eval<'s: 'i>(&'s self, _input: ()) -> Self::Output {
N
}
}
#[derive(Default, Debug)]
pub struct ValueNode<T>(pub 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(self, _: ()) -> Self::Output {
impl<'i, T: 'i> Node<'i, ()> for ValueNode<T> {
type Output = &'i T;
fn eval<'s: 'i>(&'s self, _input: ()) -> Self::Output {
&self.0
}
}
@@ -46,58 +40,85 @@ impl<T: Clone> Clone for ValueNode<T> {
}
impl<T: Clone + Copy> Copy for ValueNode<T> {}
#[derive(Clone)]
pub struct ClonedNode<T: Clone>(pub T);
impl<'i, T: Clone + 'i> Node<'i, ()> for ClonedNode<T> {
type Output = T;
fn eval<'s: 'i>(&'s self, _input: ()) -> Self::Output {
self.0.clone()
}
}
impl<T: Clone> ClonedNode<T> {
pub const fn new(value: T) -> ClonedNode<T> {
ClonedNode(value)
}
}
impl<T: Clone> From<T> for ClonedNode<T> {
fn from(value: T) -> Self {
ClonedNode::new(value)
}
}
impl<T: Clone + Copy> Copy for ClonedNode<T> {}
#[derive(Default)]
pub struct DefaultNode<T>(PhantomData<T>);
impl<T: Default> Node<()> for DefaultNode<T> {
impl<'i, T: Default + 'i> Node<'i, ()> for DefaultNode<T> {
type Output = T;
fn eval(self, _: ()) -> T {
fn eval<'s: 'i>(&self, _input: ()) -> Self::Output {
T::default()
}
}
impl<'n, T: Default + 'n> Node<()> for &'n DefaultNode<T> {
type Output = T;
fn eval(self, _: ()) -> T {
T::default()
impl<T> DefaultNode<T> {
pub fn new() -> Self {
Self(PhantomData)
}
}
#[repr(C)]
/// Return the unit value
#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct UnitNode;
impl Node<()> for UnitNode {
pub struct ForgetNode;
impl<'i, T: 'i> Node<'i, T> for ForgetNode {
type Output = ();
fn eval(self, _: ()) -> Self::Output {}
}
impl<'n> Node<()> for &'n UnitNode {
type Output = ();
fn eval(self, _: ()) -> Self::Output {}
fn eval<'s: 'i>(&self, _input: T) -> Self::Output {}
}
pub struct InputNode<T>(MaybeUninit<T>, AtomicBool);
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(self, _: ()) -> Self::Output {
if self.1.load(core::sync::atomic::Ordering::SeqCst) {
unsafe { self.0.assume_init_ref() }
} else {
panic!("tried to access an input before setting it")
}
impl ForgetNode {
pub const fn new() -> Self {
ForgetNode
}
}
impl<T> InputNode<T> {
pub const fn new() -> InputNode<T> {
InputNode(MaybeUninit::uninit(), AtomicBool::new(false))
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_int_node() {
let node = IntNode::<5>;
assert_eq!(node.eval(()), 5);
}
#[test]
fn test_value_node() {
let node = ValueNode::new(5);
assert_eq!(node.eval(()), &5);
let type_erased = &node as &dyn for<'a> Node<'a, (), Output = &'a i32>;
assert_eq!(type_erased.eval(()), &5);
}
#[test]
fn test_default_node() {
let node = DefaultNode::<u32>::new();
assert_eq!(node.eval(()), 0);
}
#[test]
fn test_unit_node() {
let node = ForgetNode::new();
assert_eq!(node.eval(()), ());
}
}

View File

@@ -3,7 +3,7 @@ use core::ops::{Index, IndexMut};
use serde::{Deserialize, Serialize};
#[repr(usize)]
#[derive(PartialEq, Eq, Clone, Debug, Copy, Serialize, Deserialize, specta::Type)]
#[derive(PartialEq, Eq, Clone, Debug, Copy, Serialize, Deserialize, specta::Type, Hash)]
pub enum ManipulatorType {
Anchor,
InHandle,

View File

@@ -35,7 +35,7 @@ fn generate_path(_input: (), path_data: Subpath) -> VectorData {
use crate::raster::Image;
#[derive(Debug, Clone, Copy)]
pub struct BlitSubpath<P: Node<(), Output = Subpath>> {
pub struct BlitSubpath<P> {
path_data: P,
}
@@ -68,9 +68,10 @@ pub struct TransformSubpathNode<Translation, Rotation, Scale, Shear> {
}
#[node_macro::node_fn(TransformSubpathNode)]
fn transform_subpath(mut subpath: Subpath, translate: DVec2, rotate: f64, scale: DVec2, shear: DVec2) -> VectorData {
fn transform_subpath(subpath: Subpath, translate: DVec2, rotate: f64, scale: DVec2, shear: DVec2) -> VectorData {
let (sin, cos) = rotate.sin_cos();
let mut subpath = subpath;
subpath.apply_affine(DAffine2::from_cols_array(&[scale.x + cos, shear.y + sin, shear.x - sin, scale.y + cos, translate.x, translate.y]));
subpath
}

View File

@@ -17,7 +17,7 @@ use alloc::vec::Vec;
/// The downside is that currently it requires a lot of iteration.
type ElementId = u64;
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, specta::Type)]
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, specta::Type, Hash)]
pub struct IdBackedVec<T> {
/// Contained elements
elements: Vec<T>,

View File

@@ -16,7 +16,7 @@ use serde::{Deserialize, Serialize};
/// / | \
/// "Anchor" "InHandle" "OutHandle" <- These are ManipulatorPoints and the only editable "primitive"
/// ```
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, Default, specta::Type)]
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, Default, specta::Type, Hash)]
pub struct ManipulatorGroup {
/// Editable points for the anchor and handles.
pub points: [Option<ManipulatorPoint>; 3],
@@ -293,7 +293,7 @@ impl ManipulatorGroup {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ManipulatorGroupEditorState {
// Whether the angle between the handles should be maintained
pub mirror_angle_between_handles: bool,

View File

@@ -1,3 +1,5 @@
use core::hash::Hash;
use super::consts::ManipulatorType;
use glam::{DAffine2, DVec2};
use serde::{Deserialize, Serialize};
@@ -26,6 +28,16 @@ impl Default for ManipulatorPoint {
}
}
#[allow(clippy::derive_hash_xor_eq)]
impl Hash for ManipulatorPoint {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.position.to_array().iter().for_each(|x| x.to_bits().hash(state));
self.manipulator_type.hash(state);
self.editor_state.hash(state);
}
}
impl ManipulatorPoint {
/// Initialize a new [ManipulatorPoint].
pub fn new(position: glam::DVec2, manipulator_type: ManipulatorType) -> Self {
@@ -60,7 +72,7 @@ impl ManipulatorPoint {
}
}
#[derive(PartialEq, Eq, Clone, Debug, specta::Type)]
#[derive(PartialEq, Eq, Clone, Debug, specta::Type, Hash)]
pub struct ManipulatorPointEditorState {
/// Whether or not this manipulator point can be selected.
pub can_be_selected: bool,

View File

@@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize};
/// [Subpath] represents a single vector path, containing many [ManipulatorGroups].
/// For each closed shape we keep a [Subpath] which contains the [ManipulatorGroup]s (handles and anchors) that define that shape.
// TODO Add "closed" bool to subpath
#[derive(PartialEq, Clone, Debug, Default, Serialize, Deserialize, DynAny, specta::Type)]
#[derive(PartialEq, Clone, Debug, Default, Serialize, Deserialize, DynAny, specta::Type, Hash)]
pub struct Subpath(IdBackedVec<ManipulatorGroup>);
impl Subpath {