Make node trait consume self
This commit is contained in:
parent
12b33da083
commit
bdad7aca47
|
|
@ -1,31 +1,45 @@
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::Node;
|
use crate::Node;
|
||||||
pub struct FnNode<'n, T: Fn(I) -> O, I, O>(T, PhantomData<&'n (I, O)>);
|
pub struct FnNode<T: Fn(I) -> O, I, O>(T, PhantomData<(I, O)>);
|
||||||
impl<'n, T: Fn(I) -> O, O, I> Node<'n, I> for FnNode<'n, T, I, O> {
|
impl<T: Fn(I) -> O, O, I> Node<I> for FnNode<T, I, O> {
|
||||||
type Output = O;
|
type Output = O;
|
||||||
|
|
||||||
fn eval(&'n self, input: I) -> Self::Output {
|
fn eval(self, input: I) -> Self::Output {
|
||||||
|
self.0(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'n, T: Fn(I) -> O, O, I> Node<I> for &'n FnNode<T, I, O> {
|
||||||
|
type Output = O;
|
||||||
|
|
||||||
|
fn eval(self, input: I) -> Self::Output {
|
||||||
self.0(input)
|
self.0(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'n, T: Fn(I) -> O, I, O> FnNode<'n, T, I, O> {
|
impl<T: Fn(I) -> O, I, O> FnNode<T, I, O> {
|
||||||
pub fn new(f: T) -> Self {
|
pub fn new(f: T) -> Self {
|
||||||
FnNode(f, PhantomData)
|
FnNode(f, PhantomData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FnNodeWithState<'n, T: Fn(I, &'n State) -> O, I, O, State: 'n>(T, State, PhantomData<&'n (O, I)>);
|
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, &'n State) -> O, I, O: 'n, State: 'n> Node<'n, I> for FnNodeWithState<'n, T, I, O, State> {
|
impl<'n, T: Fn(I, &State) -> O, I, O: 'n, State: 'n> Node<I> for &'n FnNodeWithState<'n, T, I, O, State> {
|
||||||
type Output = O;
|
type Output = O;
|
||||||
|
|
||||||
fn eval(&'n self, input: I) -> Self::Output {
|
fn eval(self, input: I) -> Self::Output {
|
||||||
|
self.0(input, &self.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'n, T: Fn(I, &State) -> O, I, O: 'n, State: 'n> Node<I> for FnNodeWithState<'n, T, I, O, State> {
|
||||||
|
type Output = O;
|
||||||
|
|
||||||
|
fn eval(self, input: I) -> Self::Output {
|
||||||
self.0(input, &self.1)
|
self.0(input, &self.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'n, T: Fn(I, &'n State) -> O, I, O: 'n, State: 'n> FnNodeWithState<'n, T, I, O, State> {
|
impl<'n, T: Fn(I, &State) -> O, I, O, State> FnNodeWithState<'n, T, I, O, State> {
|
||||||
pub fn new(f: T, state: State) -> Self {
|
pub fn new(f: T, state: State) -> Self {
|
||||||
FnNodeWithState(f, state, PhantomData)
|
FnNodeWithState(f, state, PhantomData)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,18 +14,10 @@ pub mod raster;
|
||||||
pub mod structural;
|
pub mod structural;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
|
||||||
pub trait Node<'n, T> {
|
pub trait Node<T> {
|
||||||
type Output; // TODO: replace with generic associated type
|
type Output;
|
||||||
|
|
||||||
fn eval(&'n self, input: T) -> Self::Output;
|
fn eval(self, input: T) -> Self::Output;
|
||||||
}
|
|
||||||
|
|
||||||
impl<'n, N: Node<'n, T>, T> Node<'n, T> for &'n N {
|
|
||||||
type Output = N::Output;
|
|
||||||
|
|
||||||
fn eval(&'n self, input: T) -> Self::Output {
|
|
||||||
Node::eval(*self, input)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Input<I> {
|
trait Input<I> {
|
||||||
|
|
@ -34,21 +26,21 @@ trait Input<I> {
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait AsyncNode<'n, T> {
|
pub trait AsyncNode<T> {
|
||||||
type Output; // TODO: replace with generic associated type
|
type Output;
|
||||||
|
|
||||||
async fn eval_async(&'n self, input: T) -> Self::Output;
|
async fn eval_async(self, input: T) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
/*#[cfg(feature = "async")]
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<'n, N: Node<'n, T> + Sync, T: Send + 'n> AsyncNode<'n, T> for N {
|
impl<'n, N: Node<T> + Send + Sync + 'n, T: Send + 'n> AsyncNode<T> for N {
|
||||||
type Output = N::Output;
|
type Output = N::Output;
|
||||||
|
|
||||||
async fn eval_async(&'n self, input: T) -> Self::Output {
|
async fn eval_async(self, input: T) -> Self::Output {
|
||||||
Node::eval(self, input)
|
Node::eval(self, input)
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
pub trait Cache {
|
pub trait Cache {
|
||||||
fn clear(&mut self);
|
fn clear(&mut self);
|
||||||
|
|
|
||||||
|
|
@ -3,111 +3,124 @@ use core::ops::Add;
|
||||||
|
|
||||||
use crate::Node;
|
use crate::Node;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct AddNode;
|
pub struct AddNode;
|
||||||
impl<'n, L: Add<R, Output = O> + 'n, R, O: 'n> Node<'n, (L, R)> for AddNode {
|
impl<'n, L: Add<R, Output = O> + 'n, R, O: 'n> Node<(L, R)> for AddNode {
|
||||||
type Output = <L as Add<R>>::Output;
|
type Output = <L as Add<R>>::Output;
|
||||||
fn eval(&'n self, input: (L, R)) -> Self::Output {
|
fn eval(self, input: (L, R)) -> Self::Output {
|
||||||
input.0 + input.1
|
input.0 + input.1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct CloneNode;
|
pub struct CloneNode;
|
||||||
impl<'n, O: Clone> Node<'n, &'n O> for CloneNode {
|
impl<'n, O: Clone> Node<&'n O> for CloneNode {
|
||||||
type Output = O;
|
type Output = O;
|
||||||
fn eval(&'n self, input: &'n O) -> Self::Output {
|
fn eval(self, input: &'n O) -> Self::Output {
|
||||||
input.clone()
|
input.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct FstNode;
|
pub struct FstNode;
|
||||||
impl<'n, T: 'n, U> Node<'n, (T, U)> for FstNode {
|
impl<'n, T: 'n, U> Node<(T, U)> for FstNode {
|
||||||
type Output = T;
|
type Output = T;
|
||||||
fn eval(&'n self, input: (T, U)) -> Self::Output {
|
fn eval(self, input: (T, U)) -> Self::Output {
|
||||||
let (a, _) = input;
|
let (a, _) = input;
|
||||||
a
|
a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'n, T: 'n, U> Node<'n, &'n (T, U)> for FstNode {
|
impl<'n, T: 'n, U> Node<&'n (T, U)> for FstNode {
|
||||||
type Output = &'n T;
|
type Output = &'n T;
|
||||||
fn eval(&'n self, input: &'n (T, U)) -> Self::Output {
|
fn eval(self, input: &'n (T, U)) -> Self::Output {
|
||||||
let (a, _) = input;
|
let (a, _) = input;
|
||||||
a
|
a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destructures a Tuple of two values and returns the first one
|
/// Destructures a Tuple of two values and returns the first one
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct SndNode;
|
pub struct SndNode;
|
||||||
impl<'n, T, U: 'n> Node<'n, (T, U)> for SndNode {
|
impl<'n, T, U: 'n> Node<(T, U)> for SndNode {
|
||||||
type Output = U;
|
type Output = U;
|
||||||
fn eval(&'n self, input: (T, U)) -> Self::Output {
|
fn eval(self, input: (T, U)) -> Self::Output {
|
||||||
let (_, b) = input;
|
let (_, b) = input;
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'n, T, U: 'n> Node<'n, &'n (T, U)> for SndNode {
|
impl<'n, T, U: 'n> Node<&'n (T, U)> for SndNode {
|
||||||
type Output = &'n U;
|
type Output = &'n U;
|
||||||
fn eval(&'n self, input: &'n (T, U)) -> Self::Output {
|
fn eval(self, input: &'n (T, U)) -> Self::Output {
|
||||||
let (_, b) = input;
|
let (_, b) = input;
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destructures a Tuple of two values and returns them in reverse order
|
/// Destructures a Tuple of two values and returns them in reverse order
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct SwapNode;
|
pub struct SwapNode;
|
||||||
impl<'n, T: 'n, U: 'n> Node<'n, (T, U)> for SwapNode {
|
impl<'n, T: 'n, U: 'n> Node<(T, U)> for SwapNode {
|
||||||
type Output = (U, T);
|
type Output = (U, T);
|
||||||
fn eval(&'n self, input: (T, U)) -> Self::Output {
|
fn eval(self, input: (T, U)) -> Self::Output {
|
||||||
let (a, b) = input;
|
let (a, b) = input;
|
||||||
(b, a)
|
(b, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'n, T, U: 'n> Node<'n, &'n (T, U)> for SwapNode {
|
impl<'n, T, U: 'n> Node<&'n (T, U)> for SwapNode {
|
||||||
type Output = (&'n U, &'n T);
|
type Output = (&'n U, &'n T);
|
||||||
fn eval(&'n self, input: &'n (T, U)) -> Self::Output {
|
fn eval(self, input: &'n (T, U)) -> Self::Output {
|
||||||
let (a, b) = input;
|
let (a, b) = input;
|
||||||
(b, a)
|
(b, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a tuple with two instances of the input argument
|
/// Return a tuple with two instances of the input argument
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct DupNode;
|
pub struct DupNode;
|
||||||
impl<'n, T: Clone + 'n> Node<'n, T> for DupNode {
|
impl<'n, T: Clone + 'n> Node<T> for DupNode {
|
||||||
type Output = (T, T);
|
type Output = (T, T);
|
||||||
fn eval(&'n self, input: T) -> Self::Output {
|
fn eval(self, input: T) -> Self::Output {
|
||||||
(input.clone(), input) //TODO: use Copy/Clone implementation
|
(input.clone(), input) //TODO: use Copy/Clone implementation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the Input Argument
|
/// Return the Input Argument
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct IdNode;
|
pub struct IdNode;
|
||||||
impl<'n, T: 'n> Node<'n, T> for IdNode {
|
impl<'n, T: 'n> Node<T> for IdNode {
|
||||||
type Output = T;
|
type Output = T;
|
||||||
fn eval(&'n self, input: T) -> Self::Output {
|
fn eval(self, input: T) -> Self::Output {
|
||||||
input
|
input
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MapResultNode<'n, MN: Node<'n, I>, I, E>(pub MN, pub PhantomData<&'n (I, E)>);
|
pub struct MapResultNode<MN, I, E>(pub MN, pub PhantomData<(I, E)>);
|
||||||
|
|
||||||
impl<'n, MN: Node<'n, I>, I, E> Node<'n, Result<I, E>> for MapResultNode<'n, MN, I, E> {
|
impl<MN: Node<I>, I, E> Node<Result<I, E>> for MapResultNode<MN, I, E> {
|
||||||
type Output = Result<MN::Output, E>;
|
type Output = Result<MN::Output, E>;
|
||||||
fn eval(&'n self, input: Result<I, E>) -> Self::Output {
|
fn eval(self, input: Result<I, E>) -> Self::Output {
|
||||||
input.map(|x| self.0.eval(x))
|
input.map(|x| self.0.eval(x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'n, MN: Node<I> + Copy, I, E> Node<Result<I, E>> for &'n MapResultNode<MN, I, E> {
|
||||||
|
type Output = Result<MN::Output, E>;
|
||||||
|
fn eval(self, input: Result<I, E>) -> Self::Output {
|
||||||
|
input.map(|x| (&self.0).eval(x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'n, MN: Node<'n, I>, I, E> MapResultNode<'n, MN, I, E> {
|
impl<MN, I, E> MapResultNode<MN, I, E> {
|
||||||
pub const fn new(mn: MN) -> Self {
|
pub const fn new(mn: MN) -> Self {
|
||||||
Self(mn, PhantomData)
|
Self(mn, PhantomData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub struct FlatMapResultNode<'n, MN: Node<'n, I>, I, E>(pub MN, pub PhantomData<&'n (I, E)>);
|
pub struct FlatMapResultNode<MN: Node<I>, I, E>(pub MN, pub PhantomData<(I, E)>);
|
||||||
|
|
||||||
impl<'n, MN: Node<'n, I, Output = Result<O, E>>, I, O: 'n, E: 'n> Node<'n, Result<I, E>> for FlatMapResultNode<'n, MN, I, E> {
|
impl<'n, MN: Node<I, Output = Result<O, E>>, I, O: 'n, E: 'n> Node<Result<I, E>> for FlatMapResultNode<MN, I, E> {
|
||||||
type Output = Result<O, E>;
|
type Output = Result<O, E>;
|
||||||
fn eval(&'n self, input: Result<I, E>) -> Self::Output {
|
fn eval(self, input: Result<I, E>) -> Self::Output {
|
||||||
match input.map(|x| self.0.eval(x)) {
|
match input.map(|x| self.0.eval(x)) {
|
||||||
Ok(Ok(x)) => Ok(x),
|
Ok(Ok(x)) => Ok(x),
|
||||||
Ok(Err(e)) => Err(e),
|
Ok(Err(e)) => Err(e),
|
||||||
|
|
@ -116,7 +129,7 @@ impl<'n, MN: Node<'n, I, Output = Result<O, E>>, I, O: 'n, E: 'n> Node<'n, Resul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'n, MN: Node<'n, I>, I, E> FlatMapResultNode<'n, MN, I, E> {
|
impl<MN: Node<I>, I, E> FlatMapResultNode<MN, I, E> {
|
||||||
pub const fn new(mn: MN) -> Self {
|
pub const fn new(mn: MN) -> Self {
|
||||||
Self(mn, PhantomData)
|
Self(mn, PhantomData)
|
||||||
}
|
}
|
||||||
|
|
@ -131,26 +144,26 @@ mod test {
|
||||||
pub fn dup_node() {
|
pub fn dup_node() {
|
||||||
let value = ValueNode(4u32);
|
let value = ValueNode(4u32);
|
||||||
let dup = DupNode.after(value);
|
let dup = DupNode.after(value);
|
||||||
assert_eq!(dup.eval(()), (&4, &4));
|
assert_eq!(dup.eval(()), (4, 4));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
pub fn id_node() {
|
pub fn id_node() {
|
||||||
let value = IdNode.after(ValueNode(4u32));
|
let value = IdNode.after(ValueNode(4u32));
|
||||||
assert_eq!(value.eval(()), &4);
|
assert_eq!(value.eval(()), 4);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
pub fn clone_node() {
|
pub fn clone_node() {
|
||||||
let cloned = CloneNode.after(ValueNode(4u32));
|
let cloned = CloneNode.after(&ValueNode(4u32));
|
||||||
assert_eq!(cloned.eval(()), 4);
|
assert_eq!(cloned.eval(()), 4);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
pub fn fst_node() {
|
pub fn fst_node() {
|
||||||
let fst = FstNode.after(ValueNode((4u32, "a")).clone());
|
let fst = FstNode.after(ValueNode((4u32, "a")));
|
||||||
assert_eq!(fst.eval(()), 4);
|
assert_eq!(fst.eval(()), 4);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
pub fn snd_node() {
|
pub fn snd_node() {
|
||||||
let fst = SndNode.after(ValueNode((4u32, "a")).clone());
|
let fst = SndNode.after(ValueNode((4u32, "a")));
|
||||||
assert_eq!(fst.eval(()), "a");
|
assert_eq!(fst.eval(()), "a");
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -164,8 +177,8 @@ mod test {
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
pub fn foo() {
|
pub fn foo() {
|
||||||
fn int(_: (), state: &u32) -> &u32 {
|
fn int(_: (), state: &u32) -> u32 {
|
||||||
state
|
*state
|
||||||
}
|
}
|
||||||
fn swap(input: (u32, u32)) -> (u32, u32) {
|
fn swap(input: (u32, u32)) -> (u32, u32) {
|
||||||
(input.1, input.0)
|
(input.1, input.0)
|
||||||
|
|
@ -173,6 +186,7 @@ mod test {
|
||||||
let fnn = FnNode::new(&swap);
|
let fnn = FnNode::new(&swap);
|
||||||
let fns = FnNodeWithState::new(int, 42u32);
|
let fns = FnNodeWithState::new(int, 42u32);
|
||||||
assert_eq!(fnn.eval((1u32, 2u32)), (2, 1));
|
assert_eq!(fnn.eval((1u32, 2u32)), (2, 1));
|
||||||
assert_eq!(fns.eval(()), &42);
|
let result: u32 = (&fns).eval(());
|
||||||
|
assert_eq!(result, 42);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,48 @@
|
||||||
use core::marker::PhantomData;
|
|
||||||
|
|
||||||
use crate::Node;
|
use crate::Node;
|
||||||
|
|
||||||
use self::color::Color;
|
use self::color::Color;
|
||||||
|
|
||||||
pub mod color;
|
pub mod color;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct GrayscaleNode;
|
pub struct GrayscaleNode;
|
||||||
|
|
||||||
impl<'n> Node<'n, Color> for GrayscaleNode {
|
impl Node<Color> for GrayscaleNode {
|
||||||
type Output = Color;
|
type Output = Color;
|
||||||
fn eval(&'n self, color: Color) -> Color {
|
fn eval(self, color: Color) -> Color {
|
||||||
let avg = (color.r() + color.g() + color.b()) / 3.0;
|
let avg = (color.r() + color.g() + color.b()) / 3.0;
|
||||||
Color::from_rgbaf32(avg, avg, avg, color.a()).expect("Grayscale node created an invalid color")
|
Color::from_rgbaf32_unchecked(avg, avg, avg, color.a())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'n> Node<Color> for &'n GrayscaleNode {
|
||||||
|
type Output = Color;
|
||||||
|
fn eval(self, color: Color) -> Color {
|
||||||
|
let avg = (color.r() + color.g() + color.b()) / 3.0;
|
||||||
|
Color::from_rgbaf32_unchecked(avg, avg, avg, color.a())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ForEachNode<'n, I: Iterator<Item = S>, MN: Node<'n, S>, S>(pub MN, PhantomData<&'n (I, S)>);
|
pub struct ForEachNode<MN>(pub MN);
|
||||||
|
|
||||||
impl<'n, I: Iterator<Item = S>, MN: Node<'n, S, Output = ()>, S> Node<'n, I> for ForEachNode<'n, I, MN, S> {
|
impl<'n, I: Iterator<Item = S>, MN: 'n, S> Node<I> for &'n ForEachNode<MN>
|
||||||
|
where
|
||||||
|
&'n MN: Node<S, Output = ()>,
|
||||||
|
{
|
||||||
type Output = ();
|
type Output = ();
|
||||||
fn eval(&'n self, input: I) -> Self::Output {
|
fn eval(self, input: I) -> Self::Output {
|
||||||
input.for_each(|x| self.0.eval(x))
|
input.for_each(|x| (&self.0).eval(x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MutWrapper<'n, N: Node<'n, T, Output = T>, T: Clone>(pub N, PhantomData<&'n T>);
|
pub struct MutWrapper<N>(pub N);
|
||||||
|
|
||||||
impl<'n, T: Clone, N: Node<'n, T, Output = T>> Node<'n, &'n mut T> for MutWrapper<'n, N, T> {
|
impl<'n, T: Clone, N> Node<&'n mut T> for &'n MutWrapper<N>
|
||||||
|
where
|
||||||
|
&'n N: Node<T, Output = T>,
|
||||||
|
{
|
||||||
type Output = ();
|
type Output = ();
|
||||||
fn eval(&'n self, value: &'n mut T) {
|
fn eval(self, value: &'n mut T) {
|
||||||
*value = self.0.eval(value.clone());
|
*value = (&self.0).eval(value.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,8 +53,9 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn map_node() {
|
fn map_node() {
|
||||||
let array = &mut [Color::from_rgbaf32(1.0, 0.0, 0.0, 1.0).unwrap()];
|
let array = &mut [Color::from_rgbaf32(1.0, 0.0, 0.0, 1.0).unwrap()];
|
||||||
let map = ForEachNode(MutWrapper(GrayscaleNode, PhantomData), PhantomData);
|
(&GrayscaleNode).eval(Color::from_rgbf32_unchecked(1., 0., 0.));
|
||||||
map.eval(array.iter_mut());
|
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());
|
assert_eq!(array[0], Color::from_rgbaf32(0.33333334, 0.33333334, 0.33333334, 1.0).unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,11 @@ pub struct Color {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
pub const BLACK: Color = Color::from_unsafe(0., 0., 0.);
|
pub const BLACK: Color = Color::from_rgbf32_unchecked(0., 0., 0.);
|
||||||
pub const WHITE: Color = Color::from_unsafe(1., 1., 1.);
|
pub const WHITE: Color = Color::from_rgbf32_unchecked(1., 1., 1.);
|
||||||
pub const RED: Color = Color::from_unsafe(1., 0., 0.);
|
pub const RED: Color = Color::from_rgbf32_unchecked(1., 0., 0.);
|
||||||
pub const GREEN: Color = Color::from_unsafe(0., 1., 0.);
|
pub const GREEN: Color = Color::from_rgbf32_unchecked(0., 1., 0.);
|
||||||
pub const BLUE: Color = Color::from_unsafe(0., 0., 1.);
|
pub const BLUE: Color = Color::from_rgbf32_unchecked(0., 0., 1.);
|
||||||
|
|
||||||
/// Returns `Some(Color)` if `red`, `green`, `blue` and `alpha` have a valid value. Negative numbers (including `-0.0`), NaN, and infinity are not valid values and return `None`.
|
/// Returns `Some(Color)` if `red`, `green`, `blue` and `alpha` have a valid value. Negative numbers (including `-0.0`), NaN, and infinity are not valid values and return `None`.
|
||||||
/// Alpha values greater than `1.0` are not valid.
|
/// Alpha values greater than `1.0` are not valid.
|
||||||
|
|
@ -40,7 +40,12 @@ impl Color {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an opaque `Color` from given `f32` RGB channels.
|
/// Return an opaque `Color` from given `f32` RGB channels.
|
||||||
pub const fn from_unsafe(red: f32, green: f32, blue: f32) -> Color {
|
pub const fn from_rgbaf32_unchecked(red: f32, green: f32, blue: f32, alpha: f32) -> Color {
|
||||||
|
Color { red, green, blue, alpha }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return an opaque `Color` from given `f32` RGB channels.
|
||||||
|
pub const fn from_rgbf32_unchecked(red: f32, green: f32, blue: f32) -> Color {
|
||||||
Color { red, green, blue, alpha: 1. }
|
Color { red, green, blue, alpha: 1. }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,20 @@ use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::Node;
|
use crate::Node;
|
||||||
|
|
||||||
pub struct ComposeNode<'n, Input, First: Node<'n, Input>, Second> {
|
pub struct ComposeNode<First, Second, Input> {
|
||||||
first: First,
|
first: First,
|
||||||
second: Second,
|
second: Second,
|
||||||
_phantom: PhantomData<&'n Input>,
|
_phantom: PhantomData<Input>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'n, Input, Inter, First, Second> Node<'n, Input> for ComposeNode<'n, Input, First, Second>
|
impl<Input, Inter, First, Second> Node<Input> for ComposeNode<First, Second, Input>
|
||||||
where
|
where
|
||||||
First: Node<'n, Input, Output = Inter>,
|
First: Node<Input, Output = Inter>,
|
||||||
Second: Node<'n, Inter>,
|
Second: Node<Inter>,
|
||||||
{
|
{
|
||||||
type Output = <Second as Node<'n, Inter>>::Output;
|
type Output = <Second as Node<Inter>>::Output;
|
||||||
|
|
||||||
fn eval(&'n self, input: Input) -> Self::Output {
|
fn eval(self, input: Input) -> Self::Output {
|
||||||
// evaluate the first node with the given input
|
// evaluate the first node with the given input
|
||||||
// and then pipe the result from the first computation
|
// and then pipe the result from the first computation
|
||||||
// into the second node
|
// into the second node
|
||||||
|
|
@ -23,52 +23,105 @@ where
|
||||||
self.second.eval(arg)
|
self.second.eval(arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'n, Input, Inter, First, Second> Node<Input> for &'n ComposeNode<First, Second, Input>
|
||||||
impl<'n, Input, First, Second> ComposeNode<'n, Input, First, Second>
|
|
||||||
where
|
where
|
||||||
First: Node<'n, Input>,
|
First: Node<Input, Output = Inter> + Copy,
|
||||||
Second: Node<'n, First::Output>,
|
Second: Node<Inter> + Copy,
|
||||||
|
{
|
||||||
|
type Output = Second::Output;
|
||||||
|
|
||||||
|
fn eval(self, input: Input) -> Self::Output {
|
||||||
|
// evaluate the first node with the given input
|
||||||
|
// and then pipe the result from the first computation
|
||||||
|
// into the second node
|
||||||
|
let arg: Inter = self.first.eval(input);
|
||||||
|
(&self.second).eval(arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'n, Input, First: 'n, Second: 'n> ComposeNode<First, Second, Input>
|
||||||
|
where
|
||||||
|
First: Node<Input>,
|
||||||
|
Second: Node<First::Output>,
|
||||||
{
|
{
|
||||||
pub const fn new(first: First, second: Second) -> Self {
|
pub const fn new(first: First, second: Second) -> Self {
|
||||||
ComposeNode::<'n, Input, First, Second> { first, second, _phantom: PhantomData }
|
ComposeNode::<First, Second, Input> { first, second, _phantom: PhantomData }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait After<Inter>: Sized {
|
pub trait After<Inter>: Sized {
|
||||||
fn after<'n, First, Input>(self, first: First) -> ComposeNode<'n, Input, First, Self>
|
fn after<First, Input>(self, first: First) -> ComposeNode<First, Self, Input>
|
||||||
where
|
where
|
||||||
First: Node<'n, Input, Output = Inter>,
|
First: Node<Input, Output = Inter>,
|
||||||
Self: Node<'n, Inter>,
|
Self: Node<Inter>,
|
||||||
{
|
{
|
||||||
ComposeNode::new(first, self)
|
ComposeNode::<First, Self, Input> {
|
||||||
|
first,
|
||||||
|
second: self,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'n, Second: Node<'n, I>, I> After<I> for Second {}
|
impl<Second: Node<I>, I> After<I> for Second {}
|
||||||
|
|
||||||
|
pub trait AfterRef<Inter>: Sized {
|
||||||
|
fn after<'n, First: 'n, Input>(&'n self, first: First) -> ComposeNode<First, &'n Self, Input>
|
||||||
|
where
|
||||||
|
First: Node<Input, Output = Inter> + Copy,
|
||||||
|
&'n Self: Node<Inter>,
|
||||||
|
Self: 'n,
|
||||||
|
{
|
||||||
|
ComposeNode::<First, &'n Self, Input> {
|
||||||
|
first,
|
||||||
|
second: self,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'n, Second: 'n, I> AfterRef<I> for Second where &'n Second: Node<I> {}
|
||||||
|
|
||||||
pub struct ConsNode<Root>(pub Root);
|
pub struct ConsNode<Root>(pub Root);
|
||||||
|
|
||||||
impl<'n, Root, Input> Node<'n, Input> for ConsNode<Root>
|
impl<Root, Input> Node<Input> for ConsNode<Root>
|
||||||
where
|
where
|
||||||
Root: Node<'n, ()>,
|
Root: Node<()>,
|
||||||
{
|
{
|
||||||
type Output = (Input, <Root as Node<'n, ()>>::Output);
|
type Output = (Input, <Root as Node<()>>::Output);
|
||||||
|
|
||||||
fn eval(&'n self, input: Input) -> Self::Output {
|
fn eval(self, input: Input) -> Self::Output {
|
||||||
let arg = self.0.eval(());
|
let arg = self.0.eval(());
|
||||||
(input, arg)
|
(input, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'n, Root: Node<()> + Copy, Input> Node<Input> for &'n ConsNode<Root> {
|
||||||
|
type Output = (Input, Root::Output);
|
||||||
|
|
||||||
|
fn eval(self, input: Input) -> Self::Output {
|
||||||
|
let arg = (&self.0).eval(());
|
||||||
|
(input, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ConsPassInputNode<Root>(pub Root);
|
pub struct ConsPassInputNode<Root>(pub Root);
|
||||||
|
|
||||||
impl<'n, Root, L, R> Node<'n, (L, R)> for ConsPassInputNode<Root>
|
impl<Root, L, R> Node<(L, R)> for ConsPassInputNode<Root>
|
||||||
where
|
where
|
||||||
Root: Node<'n, R>,
|
Root: Node<R>,
|
||||||
{
|
{
|
||||||
type Output = (L, <Root as Node<'n, R>>::Output);
|
type Output = (L, <Root as Node<R>>::Output);
|
||||||
|
|
||||||
fn eval(&'n self, input: (L, R)) -> Self::Output {
|
fn eval(self, input: (L, R)) -> Self::Output {
|
||||||
let arg = self.0.eval(input.1);
|
let arg = self.0.eval(input.1);
|
||||||
(input.0, arg)
|
(input.0, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'n, Root, L, R> Node<(L, R)> for &'n ConsPassInputNode<Root>
|
||||||
|
where
|
||||||
|
&'n Root: Node<R>,
|
||||||
|
{
|
||||||
|
type Output = (L, <&'n Root as Node<R>>::Output);
|
||||||
|
|
||||||
|
fn eval(self, input: (L, R)) -> Self::Output {
|
||||||
|
let arg = (&self.0).eval(input.1);
|
||||||
|
(input.0, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,23 +2,28 @@ use core::marker::PhantomData;
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
use core::sync::atomic::AtomicBool;
|
use core::sync::atomic::AtomicBool;
|
||||||
|
|
||||||
use crate::ops::CloneNode;
|
|
||||||
use crate::structural::ComposeNode;
|
|
||||||
use crate::Node;
|
use crate::Node;
|
||||||
|
|
||||||
|
#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
pub struct IntNode<const N: u32>;
|
pub struct IntNode<const N: u32>;
|
||||||
impl<'n, const N: u32> Node<'n, ()> for IntNode<N> {
|
impl<const N: u32> Node<()> for IntNode<N> {
|
||||||
type Output = u32;
|
type Output = u32;
|
||||||
fn eval(&self, _: ()) -> u32 {
|
fn eval(self, _: ()) -> u32 {
|
||||||
N
|
N
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default, Debug)]
|
||||||
pub struct ValueNode<T>(pub T);
|
pub struct ValueNode<T>(pub T);
|
||||||
impl<'n, T: 'n> Node<'n, ()> for ValueNode<T> {
|
impl<'n, T: 'n> Node<()> for ValueNode<T> {
|
||||||
|
type Output = T;
|
||||||
|
fn eval(self, _: ()) -> Self::Output {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'n, T: 'n> Node<()> for &'n ValueNode<T> {
|
||||||
type Output = &'n T;
|
type Output = &'n T;
|
||||||
fn eval(&'n self, _: ()) -> Self::Output {
|
fn eval(self, _: ()) -> Self::Output {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -29,39 +34,60 @@ impl<T> ValueNode<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'n, T: Clone + 'n> ValueNode<T> {
|
|
||||||
pub const fn clone(self) -> ComposeNode<'n, (), ValueNode<T>, CloneNode> {
|
|
||||||
ComposeNode::new(self, CloneNode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> From<T> for ValueNode<T> {
|
impl<T> From<T> for ValueNode<T> {
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self {
|
||||||
ValueNode::new(value)
|
ValueNode::new(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<T: Clone> Clone for ValueNode<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Clone + Copy> Copy for ValueNode<T> {}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct DefaultNode<T>(PhantomData<T>);
|
pub struct DefaultNode<T>(PhantomData<T>);
|
||||||
impl<'n, T: Default + 'n> Node<'n, ()> for DefaultNode<T> {
|
impl<T: Default> Node<()> for DefaultNode<T> {
|
||||||
type Output = T;
|
type Output = T;
|
||||||
fn eval(&self, _: ()) -> T {
|
fn eval(self, _: ()) -> T {
|
||||||
|
T::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'n, T: Default + 'n> Node<()> for &'n DefaultNode<T> {
|
||||||
|
type Output = T;
|
||||||
|
fn eval(self, _: ()) -> T {
|
||||||
T::default()
|
T::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
/// Return the unit value
|
/// Return the unit value
|
||||||
|
#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
pub struct UnitNode;
|
pub struct UnitNode;
|
||||||
impl<'n> Node<'n, ()> for UnitNode {
|
impl Node<()> for UnitNode {
|
||||||
type Output = ();
|
type Output = ();
|
||||||
fn eval(&'n self, _: ()) -> Self::Output {}
|
fn eval(self, _: ()) -> Self::Output {}
|
||||||
|
}
|
||||||
|
impl<'n> Node<()> for &'n UnitNode {
|
||||||
|
type Output = ();
|
||||||
|
fn eval(self, _: ()) -> Self::Output {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct InputNode<T>(MaybeUninit<T>, AtomicBool);
|
pub struct InputNode<T>(MaybeUninit<T>, AtomicBool);
|
||||||
impl<'n, T: 'n> Node<'n, ()> for InputNode<T> {
|
impl<'n, T: 'n> Node<()> for InputNode<T> {
|
||||||
|
type Output = T;
|
||||||
|
fn eval(self, _: ()) -> Self::Output {
|
||||||
|
if self.1.load(core::sync::atomic::Ordering::SeqCst) {
|
||||||
|
unsafe { self.0.assume_init() }
|
||||||
|
} else {
|
||||||
|
panic!("tried to access an input before setting it")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'n, T: 'n> Node<()> for &'n InputNode<T> {
|
||||||
type Output = &'n T;
|
type Output = &'n T;
|
||||||
fn eval(&'n self, _: ()) -> Self::Output {
|
fn eval(self, _: ()) -> Self::Output {
|
||||||
if self.1.load(core::sync::atomic::Ordering::SeqCst) {
|
if self.1.load(core::sync::atomic::Ordering::SeqCst) {
|
||||||
unsafe { self.0.assume_init_ref() }
|
unsafe { self.0.assume_init_ref() }
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#![feature(type_alias_impl_trait)]
|
|
||||||
//pub mod value;
|
//pub mod value;
|
||||||
pub use graphene_core::{generic, ops /*, structural*/};
|
pub use graphene_core::{generic, ops /*, structural*/};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,34 +3,26 @@ use once_cell::sync::OnceCell;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// Caches the output of a given Node and acts as a proxy
|
/// Caches the output of a given Node and acts as a proxy
|
||||||
pub struct CacheNode<'n, CachedNode: Node<'n, I>, I> {
|
pub struct CacheNode<CachedNode: Node<I>, I> {
|
||||||
node: CachedNode,
|
node: CachedNode,
|
||||||
cache: OnceCell<CachedNode::Output>,
|
cache: OnceCell<CachedNode::Output>,
|
||||||
_phantom: PhantomData<&'n ()>,
|
|
||||||
}
|
}
|
||||||
impl<'n, CashedNode: Node<'n, I>, I> Node<'n, I> for CacheNode<'n, CashedNode, I>
|
impl<'n, CashedNode: Node<I> + Copy, I> Node<I> for &'n CacheNode<CashedNode, I> {
|
||||||
where
|
|
||||||
CashedNode::Output: 'n,
|
|
||||||
{
|
|
||||||
type Output = &'n CashedNode::Output;
|
type Output = &'n CashedNode::Output;
|
||||||
fn eval(&'n self, input: I) -> Self::Output {
|
fn eval(self, input: I) -> Self::Output {
|
||||||
self.cache.get_or_init(|| self.node.eval(input))
|
self.cache.get_or_init(|| self.node.eval(input))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'n, CachedNode: Node<'n, I>, I> CacheNode<'n, CachedNode, I> {
|
impl<'n, CachedNode: Node<I>, I> CacheNode<CachedNode, I> {
|
||||||
pub fn clear(&'n mut self) {
|
pub fn clear(&'n mut self) {
|
||||||
self.cache = OnceCell::new();
|
self.cache = OnceCell::new();
|
||||||
}
|
}
|
||||||
pub fn new(node: CachedNode) -> CacheNode<'n, CachedNode, I> {
|
pub fn new(node: CachedNode) -> CacheNode<CachedNode, I> {
|
||||||
CacheNode {
|
CacheNode { node, cache: OnceCell::new() }
|
||||||
node,
|
|
||||||
cache: OnceCell::new(),
|
|
||||||
_phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'n, CachedNode: Node<'n, I>, I> Cache for CacheNode<'n, CachedNode, I> {
|
impl<CachedNode: Node<I>, I> Cache for CacheNode<CachedNode, I> {
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
self.cache = OnceCell::new();
|
self.cache = OnceCell::new();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,30 +2,36 @@ use core::marker::PhantomData;
|
||||||
use graphene_core::ops::FlatMapResultNode;
|
use graphene_core::ops::FlatMapResultNode;
|
||||||
use graphene_core::raster::color::Color;
|
use graphene_core::raster::color::Color;
|
||||||
use graphene_core::structural::{ComposeNode, ConsNode};
|
use graphene_core::structural::{ComposeNode, ConsNode};
|
||||||
use graphene_core::{generic::FnNode, ops::MapResultNode, structural::After, value::ValueNode, Node};
|
use graphene_core::{
|
||||||
|
generic::FnNode,
|
||||||
|
ops::MapResultNode,
|
||||||
|
structural::{After, AfterRef},
|
||||||
|
value::ValueNode,
|
||||||
|
Node,
|
||||||
|
};
|
||||||
use image::Pixel;
|
use image::Pixel;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
pub struct MapNode<'n, MN: Node<'n, S>, I: IntoIterator<Item = S>, S>(pub MN, PhantomData<&'n (S, I)>);
|
pub struct MapNode<MN: Node<S>, I: IntoIterator<Item = S>, S>(pub MN, PhantomData<(S, I)>);
|
||||||
|
|
||||||
impl<'n, I: IntoIterator<Item = S>, MN: Node<'n, S>, S> Node<'n, I> for MapNode<'n, MN, I, S> {
|
impl<I: IntoIterator<Item = S>, MN: Node<S> + Copy, S> Node<I> for MapNode<MN, I, S> {
|
||||||
type Output = Vec<MN::Output>;
|
type Output = Vec<MN::Output>;
|
||||||
fn eval(&'n self, input: I) -> Self::Output {
|
fn eval(self, input: I) -> Self::Output {
|
||||||
input.into_iter().map(|x| self.0.eval(x)).collect()
|
input.into_iter().map(|x| self.0.eval(x)).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'n, I: IntoIterator<Item = S>, MN: Node<'n, S>, S> MapNode<'n, MN, I, S> {
|
impl<I: IntoIterator<Item = S>, MN: Node<S>, S> MapNode<MN, I, S> {
|
||||||
pub const fn new(mn: MN) -> Self {
|
pub const fn new(mn: MN) -> Self {
|
||||||
MapNode(mn, PhantomData)
|
MapNode(mn, PhantomData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MapImageNode<'n, MN: Node<'n, Color, Output = Color>>(pub MN, PhantomData<&'n ()>);
|
pub struct MapImageNode<MN: Node<Color, Output = Color> + Copy>(pub MN);
|
||||||
|
|
||||||
impl<'n, MN: Node<'n, Color, Output = Color>> Node<'n, Image> for MapImageNode<'n, MN> {
|
impl<'n, MN: Node<Color, Output = Color> + Copy> Node<Image> for &'n MapImageNode<MN> {
|
||||||
type Output = Image;
|
type Output = Image;
|
||||||
fn eval(&'n self, input: Image) -> Self::Output {
|
fn eval(self, input: Image) -> Self::Output {
|
||||||
Image {
|
Image {
|
||||||
width: input.width,
|
width: input.width,
|
||||||
height: input.height,
|
height: input.height,
|
||||||
|
|
@ -34,9 +40,9 @@ impl<'n, MN: Node<'n, Color, Output = Color>> Node<'n, Image> for MapImageNode<'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'n, MN: Node<'n, Color, Output = Color>> MapImageNode<'n, MN> {
|
impl<MN: Node<Color, Output = Color> + Copy> MapImageNode<MN> {
|
||||||
pub const fn new(mn: MN) -> Self {
|
pub const fn new(mn: MN) -> Self {
|
||||||
MapImageNode(mn, PhantomData)
|
MapImageNode(mn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,20 +72,20 @@ impl FileSystem for StdFs {
|
||||||
type Reader = Box<dyn std::io::Read>;
|
type Reader = Box<dyn std::io::Read>;
|
||||||
|
|
||||||
pub struct FileNode<P: AsRef<Path>, FS: FileSystem>(PhantomData<(P, FS)>);
|
pub struct FileNode<P: AsRef<Path>, FS: FileSystem>(PhantomData<(P, FS)>);
|
||||||
impl<'n, P: AsRef<Path>, FS: FileSystem> Node<'n, (P, FS)> for FileNode<P, FS> {
|
impl<P: AsRef<Path>, FS: FileSystem> Node<(P, FS)> for FileNode<P, FS> {
|
||||||
type Output = Result<Reader, Error>;
|
type Output = Result<Reader, Error>;
|
||||||
|
|
||||||
fn eval(&'n self, input: (P, FS)) -> Self::Output {
|
fn eval(self, input: (P, FS)) -> Self::Output {
|
||||||
let (path, fs) = input;
|
let (path, fs) = input;
|
||||||
fs.open(path)
|
fs.open(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BufferNode;
|
pub struct BufferNode;
|
||||||
impl<'n, Reader: std::io::Read> Node<'n, Reader> for BufferNode {
|
impl<Reader: std::io::Read> Node<Reader> for BufferNode {
|
||||||
type Output = Result<Vec<u8>, Error>;
|
type Output = Result<Vec<u8>, Error>;
|
||||||
|
|
||||||
fn eval(&'n self, mut reader: Reader) -> Self::Output {
|
fn eval(self, mut reader: Reader) -> Self::Output {
|
||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
reader.read_to_end(&mut buffer)?;
|
reader.read_to_end(&mut buffer)?;
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
|
|
@ -109,23 +115,18 @@ impl<'a> IntoIterator for &'a Image {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_node<'n, P: AsRef<Path> + 'n>() -> impl Node<'n, P, Output = Result<Vec<u8>, Error>> {
|
pub fn file_node<'n, P: AsRef<Path> + 'n>() -> impl Node<P, Output = Result<Vec<u8>, Error>> {
|
||||||
let fs = ValueNode(StdFs).clone();
|
let fs = ValueNode(StdFs).clone();
|
||||||
let fs = ConsNode(fs);
|
let fs = ConsNode(fs);
|
||||||
let file: ComposeNode<P, _, FileNode<P, _>> = FileNode(PhantomData).after(fs);
|
let file: ComposeNode<_, _, P> = FileNode(PhantomData).after(fs);
|
||||||
let buffer = FlatMapResultNode::new(BufferNode).after(file);
|
|
||||||
buffer
|
|
||||||
}
|
|
||||||
type Ret<'n> = impl Node<'n, (), Output = u32>;
|
|
||||||
|
|
||||||
pub fn test_node<'n>() -> Ret<'n> {
|
FlatMapResultNode::new(BufferNode).after(file)
|
||||||
ValueNode(432).clone()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn image_node<'n, P: AsRef<Path> + 'n>() -> impl Node<'n, P, Output = Result<Image, Error>> {
|
pub fn image_node<'n, P: AsRef<Path> + 'n>() -> impl Node<P, Output = Result<Image, Error>> {
|
||||||
let file = file_node();
|
let file = file_node();
|
||||||
let image_loader = FnNode::new(|data: Vec<u8>| image::load_from_memory(&data).map_err(Error::Image).map(|image| image.into_rgba32f()));
|
let image_loader = FnNode::new(|data: Vec<u8>| image::load_from_memory(&data).map_err(Error::Image).map(|image| image.into_rgba32f()));
|
||||||
let image: ComposeNode<'_, P, _, _> = FlatMapResultNode::new(image_loader).after(file);
|
let image: ComposeNode<_, _, P> = FlatMapResultNode::new(image_loader).after(file);
|
||||||
let convert_image = FnNode::new(|image: image::ImageBuffer<_, _>| {
|
let convert_image = FnNode::new(|image: image::ImageBuffer<_, _>| {
|
||||||
let data = image
|
let data = image
|
||||||
.enumerate_pixels()
|
.enumerate_pixels()
|
||||||
|
|
@ -140,11 +141,11 @@ pub fn image_node<'n, P: AsRef<Path> + 'n>() -> impl Node<'n, P, Output = Result
|
||||||
data,
|
data,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let image = MapResultNode::new(convert_image).after(image);
|
|
||||||
image
|
MapResultNode::new(convert_image).after(image)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn export_image_node<'n>() -> impl Node<'n, (Image, &'n str), Output = Result<(), Error>> {
|
pub fn export_image_node<'n>() -> impl Node<(Image, &'n str), Output = Result<(), Error>> {
|
||||||
FnNode::new(|input: (Image, &str)| {
|
FnNode::new(|input: (Image, &str)| {
|
||||||
let (image, path) = input;
|
let (image, path) = input;
|
||||||
let mut new_image = image::ImageBuffer::new(image.width, image.height);
|
let mut new_image = image::ImageBuffer::new(image.width, image.height);
|
||||||
|
|
@ -152,7 +153,7 @@ pub fn export_image_node<'n>() -> impl Node<'n, (Image, &'n str), Output = Resul
|
||||||
let color: Color = *color;
|
let color: Color = *color;
|
||||||
assert!(x < image.width);
|
assert!(x < image.width);
|
||||||
assert!(y < image.height);
|
assert!(y < image.height);
|
||||||
*pixel = image::Rgba([color.r(), color.g(), color.b(), color.a()])
|
*pixel = image::Rgba(color.to_rgba8())
|
||||||
}
|
}
|
||||||
new_image.save(path).map_err(Error::Image)
|
new_image.save(path).map_err(Error::Image)
|
||||||
})
|
})
|
||||||
|
|
@ -174,24 +175,13 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn load_image() {
|
fn load_image() {
|
||||||
/*let image = image_node();
|
let image = image_node::<&str>();
|
||||||
let gray = MapImageNode::new(GrayscaleNode);
|
let gray = MapImageNode::new(GrayscaleNode);
|
||||||
|
|
||||||
let gray_scale_picture = MapResultNode::new(gray).after(image);
|
let grayscale_picture = MapResultNode::new(&gray).after(image);
|
||||||
let gray_scale_picture = gray_scale_picture.eval("image");
|
|
||||||
*/
|
|
||||||
let test_node = test_node();
|
|
||||||
{
|
|
||||||
let foo = test_node.eval(());
|
|
||||||
std::mem::drop(foo);
|
|
||||||
}
|
|
||||||
let export = export_image_node();
|
let export = export_image_node();
|
||||||
|
|
||||||
/*let export = FnNode::new(|input: (&str, &str)| {
|
let picture = grayscale_picture.eval("/home/dennis/screenshot.png").expect("failed to load image");
|
||||||
let (input, output) = input;*/
|
export.eval((picture, "/tmp/screenshot.png")).unwrap();
|
||||||
//let picture = gray_scale_picture.eval("/home/dennis/screenshot.png").unwrap().clone();
|
|
||||||
//export.eval((picture, "screenshot.png"));
|
|
||||||
/*});
|
|
||||||
export.eval(("screenshot.png", "/home/dennis/screenshot.png"));*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue