mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-16 23:08:05 +08:00
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:
committed by
Keavon Chambers
parent
12d6818d73
commit
004e87ca3e
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(());
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -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.);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(()), ());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user