Remove unsafe code and clean up the code base in general (#1263)

* Remove unsafe code

* Make node graph test syncronous

* Add miri step to ci

* Remove unsafe from node graph evaluation

* Replace operation pseudo_hash with hash based on discriminant

* Fix test

* Move memo module to core and make it safe

* Fix formatting

* Remove unused stuff from gstd

* Use safe casting for creating key variants

* Fix memo node types

* Fix ref node

* "fix" ub

* Use correct input types for ExtractImageFrame

* Fix types for async nodes

* Fix missing implementation

* Manually override output type for async nodes

* Fix types for EditorApi

* Fix output type for WasmSurfaceHandle

* Remove unused miri.yml

* Fix incorrect type for cache node
This commit is contained in:
Dennis Kobert 2023-06-02 11:05:32 +02:00 committed by Keavon Chambers
parent 259dcdc628
commit 4e1bfddcd8
43 changed files with 520 additions and 1252 deletions

View file

@ -13,18 +13,17 @@ quantization = ["graphene-std/quantization"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
graphene-core = { path = "../gcore", features = ["async", "std" ] }
graphene-core = { path = "../gcore", features = ["async", "std"] }
graphene-std = { path = "../gstd" }
graph-craft = { path = "../graph-craft" }
dyn-any = { path = "../../libraries/dyn-any", features = ["log-bad-types", "glam"] }
dyn-any = { path = "../../libraries/dyn-any", features = [
"log-bad-types",
"glam",
] }
num-traits = "0.2"
borrow_stack = { path = "../borrow_stack" }
dyn-clone = "1.0"
log = "0.4"
serde = { version = "1", features = ["derive"], optional = true }
glam = { version = "0.22" }
once_cell = "1.17.0"
futures = "0.3.28"
[dev-dependencies]
tokio = { version = "1.12", features = ["rt", "macros"] }

View file

@ -3,12 +3,12 @@ use std::error::Error;
use std::sync::{Arc, RwLock};
use dyn_any::StaticType;
use graph_craft::document::value::UpcastNode;
use graph_craft::document::value::{TaggedValue, UpcastNode};
use graph_craft::document::NodeId;
use graph_craft::executor::Executor;
use graph_craft::proto::{ConstructionArgs, LocalFuture, ProtoNetwork, ProtoNode, TypingContext};
use graph_craft::Type;
use graphene_std::any::{Any, TypeErasedPinned, TypeErasedPinnedRef};
use graphene_std::any::{TypeErasedPinned, TypeErasedPinnedRef};
use crate::node_registry;
@ -73,9 +73,9 @@ impl DynamicExecutor {
}
}
impl Executor for DynamicExecutor {
fn execute<'a>(&'a self, input: Any<'a>) -> LocalFuture<Result<Any<'a>, Box<dyn Error>>> {
Box::pin(async move { self.tree.eval_any(self.output, input).await.ok_or_else(|| "Failed to execute".into()) })
impl<'a, I: StaticType + 'a> Executor<I, TaggedValue> for &'a DynamicExecutor {
fn execute(&self, input: I) -> LocalFuture<Result<TaggedValue, Box<dyn Error>>> {
Box::pin(async move { self.tree.eval_tagged_value(self.output, input).await.map_err(|e| e.into()) })
}
}
@ -167,18 +167,17 @@ impl BorrowTree {
self.nodes.get(&id).cloned()
}
pub async fn eval<'i, I: StaticType + 'i + Send + Sync, O: StaticType + Send + Sync + 'i>(&'i self, id: NodeId, input: I) -> Option<O> {
pub async fn eval<'i, I: StaticType + 'i, O: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Option<O> {
let node = self.nodes.get(&id).cloned()?;
let reader = node.read().unwrap();
let output = reader.node.eval(Box::new(input));
dyn_any::downcast::<O>(output.await).ok().map(|o| *o)
}
pub async fn eval_any<'i>(&'i self, id: NodeId, input: Any<'i>) -> Option<Any<'i>> {
let node = self.nodes.get(&id)?;
// TODO: Comments by @TrueDoctor before this was merged:
// TODO: Oof I dislike the evaluation being an unsafe operation but I guess its fine because it only is a lifetime extension
// TODO: We should ideally let miri run on a test that evaluates the nodegraph multiple times to check if this contains any subtle UB but this looks fine for now
Some(unsafe { (*((&*node.read().unwrap()) as *const NodeContainer)).node.eval(input).await })
pub async fn eval_tagged_value<'i, I: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Result<TaggedValue, String> {
let node = self.nodes.get(&id).cloned().ok_or_else(|| "Output node not found in executor")?;
let reader = node.read().unwrap();
let output = reader.node.eval(Box::new(input));
TaggedValue::try_from_any(output.await)
}
pub fn free_node(&mut self, id: NodeId) {
@ -226,12 +225,15 @@ mod test {
use super::*;
#[tokio::test]
async fn push_node() {
#[test]
fn push_node_sync() {
let mut tree = BorrowTree::default();
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32)), vec![]);
tree.push_node(0, val_1_protonode, &TypingContext::default()).await.unwrap();
let context = TypingContext::default();
let future = tree.push_node(0, val_1_protonode, &context); //.await.unwrap();
futures::executor::block_on(future).unwrap();
let _node = tree.get(0).unwrap();
assert_eq!(tree.eval(0, ()).await, Some(2u32));
let result = futures::executor::block_on(tree.eval(0, ()));
assert_eq!(result, Some(2u32));
}
}

View file

@ -7,45 +7,14 @@ pub mod node_registry;
#[cfg(test)]
mod tests {
use dyn_any::IntoDynAny;
use graph_craft::document::value::TaggedValue;
use graphene_core::*;
use std::borrow::Cow;
/*
use futures::executor::block_on;
#[test]
fn borrow_stack() {
let stack = borrow_stack::FixedSizeStack::new(256);
unsafe {
let dynanynode: DynAnyNode<ValueNode<u32>, (), _, _> = DynAnyNode::new(ValueNode(2_u32));
stack.push(dynanynode.into_box());
}
stack.push_fn(|nodes| {
let pre_node = nodes.get(0).unwrap();
let downcast: DowncastNode<&TypeErasedNode, &u32> = DowncastNode::new(pre_node);
let dynanynode: DynAnyNode<ConsNode<_, Any<'_>>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData));
dynanynode.into_box()
});
stack.push_fn(|_| {
let dynanynode: DynAnyNode<_, (u32, &u32), _, _> = DynAnyNode::new(AddNode);
dynanynode.into_box()
});
stack.push_fn(|nodes| {
let compose_node = nodes[1].after(&nodes[2]);
TypeErasedNode(Box::pin(compose_node))
});
let result = unsafe { &stack.get()[0] }.eval_ref(().into_dyn());
assert_eq!(*downcast::<&u32>(result).unwrap(), &2_u32);
let result = unsafe { &stack.get()[1] }.eval_ref(4_u32.into_dyn());
assert_eq!(*downcast::<(u32, &u32)>(result).unwrap(), (4_u32, &2_u32));
let result = unsafe { &stack.get()[1] }.eval_ref(4_u32.into_dyn());
let add = unsafe { &stack.get()[2] }.eval_ref(result);
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
let add = unsafe { &stack.get()[3] }.eval_ref(4_u32.into_dyn());
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
}*/
#[tokio::test]
async fn execute_add() {
fn execute_add() {
use graph_craft::document::*;
use graph_craft::*;
@ -109,15 +78,14 @@ mod tests {
let compiler = Compiler {};
let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
let exec = DynamicExecutor::new(protograph).await.unwrap_or_else(|e| panic!("Failed to create executor: {}", e));
let exec = block_on(DynamicExecutor::new(protograph)).unwrap_or_else(|e| panic!("Failed to create executor: {}", e));
let result = exec.execute(32_u32.into_dyn()).await.unwrap();
let val = *dyn_any::downcast::<u32>(result).unwrap();
assert_eq!(val, 33_u32);
let result = block_on((&exec).execute(32_u32)).unwrap();
assert_eq!(result, TaggedValue::U32(33));
}
#[tokio::test]
async fn double_number() {
#[test]
fn double_number() {
use graph_craft::document::*;
use graph_craft::*;
@ -158,6 +126,6 @@ mod tests {
let compiler = Compiler {};
let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
let _exec = DynamicExecutor::new(protograph).await.map(|e| panic!("The network should not type check: {:#?}", e)).unwrap_err();
let _exec = block_on(DynamicExecutor::new(protograph)).map(|e| panic!("The network should not type check: {:#?}", e)).unwrap_err();
}
}

View file

@ -1,4 +1,3 @@
use graph_craft::document::DocumentNode;
use graph_craft::proto::{NodeConstructor, TypeErasedPinned};
use graphene_core::ops::IdNode;
use graphene_core::quantization::QuantizationChannels;
@ -10,13 +9,11 @@ use graphene_core::vector::brush_stroke::BrushStroke;
use graphene_core::vector::VectorData;
use graphene_core::wasm_application_io::WasmSurfaceHandle;
use graphene_core::wasm_application_io::*;
use graphene_core::{concrete, generic, value_fn};
use graphene_core::{concrete, generic};
use graphene_core::{fn_type, raster::*};
use graphene_core::{Cow, NodeIdentifier, Type, TypeDescriptor};
use graphene_core::{Node, NodeIO, NodeIOTypes};
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyInRefNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode, TypeErasedPinnedRef};
use graphene_std::brush::*;
use graphene_std::memo::{CacheNode, LetNode};
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode};
use graphene_std::raster::BlendImageTupleNode;
use graphene_std::raster::*;
@ -27,8 +24,8 @@ use std::collections::HashMap;
use std::sync::Arc;
macro_rules! construct_node {
($args: ident, $path:ty, [$($type:tt),*]) => { async move {
let mut args: Vec<TypeErasedPinnedRef<'static>> = $args.clone();
($args: ident, $path:ty, [$($type:ty),*]) => { async move {
let mut args = $args.clone();
args.reverse();
let node = <$path>::new($(
{
@ -60,7 +57,7 @@ macro_rules! register_node {
let node = <$path>::new($(
graphene_std::any::PanicNode::<(), $type>::new()
),*);
let params = vec![$(value_fn!($type)),*];
let params = vec![$(fn_type!((), $type)),*];
let mut node_io = <$path as NodeIO<'_, $input>>::to_node_io(&node, params);
node_io.input = concrete!(<$input as StaticType>::Static);
node_io
@ -69,6 +66,38 @@ macro_rules! register_node {
]
};
}
macro_rules! async_node {
// TODO: we currently need to annotate the type here because the compiler would otherwise (correctly)
// assign a Pin<Box<dyn Fututure<Output=T>>> type to the node, which is not what we want for now.
($path:ty, input: $input:ty, output: $output:ty, params: [ $($type:ty),*]) => {
vec![
(
NodeIdentifier::new(stringify!($path)),
|mut args| {
Box::pin(async move {
args.reverse();
let node = <$path>::new($(graphene_std::any::input_node::<$type>(args.pop().expect("Not enough arguments provided to construct node"))),*);
let any: DynAnyNode<$input, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
},
{
let node = <$path>::new($(
graphene_std::any::PanicNode::<(), core::pin::Pin<Box<dyn core::future::Future<Output = $type>>>>::new()
),*);
// TODO: Propagate the future type through the node graph
//let params = vec![$(Type::Fn(Box::new(concrete!(())), Box::new(Type::Future(Box::new(concrete!($type)))))),*];
let params = vec![$(Type::Fn(Box::new(concrete!(())), Box::new(concrete!($type)))),*];
let mut node_io = NodeIO::<'_, $input>::to_node_io(&node, params);
node_io.input = concrete!(<$input as StaticType>::Static);
node_io.input = concrete!(<$input as StaticType>::Static);
node_io.output = concrete!(<$output as StaticType>::Static);
node_io
},
)
]
};
}
macro_rules! raster_node {
($path:ty, params: [$($type:ty),*]) => {{
// this function could also be inlined but serves as a workaround for
@ -92,7 +121,7 @@ macro_rules! raster_node {
})
},
{
let params = vec![$(value_fn!($type)),*];
let params = vec![$(fn_type!($type)),*];
NodeIOTypes::new(concrete!(Color), concrete!(Color), params)
},
),
@ -108,7 +137,7 @@ macro_rules! raster_node {
})
},
{
let params = vec![$(value_fn!($type)),*];
let params = vec![$(fn_type!($type)),*];
NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), params)
},
),
@ -124,7 +153,7 @@ macro_rules! raster_node {
})
},
{
let params = vec![$(value_fn!($type)),*];
let params = vec![$(fn_type!($type)),*];
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), params)
},
)
@ -208,38 +237,32 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
NodeIOTypes::new(
concrete!(()),
concrete!(ImageFrame<Color>),
vec![value_fn!(ImageFrame<Color>), value_fn!(ImageFrame<Color>), value_fn!(ImageFrame<Color>), value_fn!(ImageFrame<Color>)],
vec![fn_type!(ImageFrame<Color>), fn_type!(ImageFrame<Color>), fn_type!(ImageFrame<Color>), fn_type!(ImageFrame<Color>)],
),
)],
register_node!(graphene_std::raster::EmptyImageNode<_, _>, input: DAffine2, params: [Color]),
register_node!(graphene_std::memo::MonitorNode<_>, input: ImageFrame<Color>, params: []),
register_node!(graphene_std::memo::MonitorNode<_>, input: graphene_core::GraphicGroup, params: []),
register_node!(graphene_core::wasm_application_io::CreateSurfaceNode, input: &graphene_core::EditorApi, params: []),
vec![(
NodeIdentifier::new("graphene_core::wasm_application_io::DrawImageFrameNode<_>"),
|args| {
Box::pin(async move {
let surface: DowncastBothNode<(), Arc<WasmSurfaceHandle>> = DowncastBothNode::new(args[0]);
let node = graphene_core::wasm_application_io::DrawImageFrameNode::new(surface);
let any: DynAnyNode<ImageFrame<SRGBA8>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(concrete!(ImageFrame<SRGBA8>), concrete!(WasmSurfaceHandleFrame), vec![value_fn!(Arc<WasmSurfaceHandle>)]),
)],
register_node!(graphene_core::memo::MonitorNode<_>, input: ImageFrame<Color>, params: []),
register_node!(graphene_core::memo::MonitorNode<_>, input: graphene_core::GraphicGroup, params: []),
register_node!(graphene_core::wasm_application_io::CreateSurfaceNode, input: graphene_core::EditorApi, params: []),
async_node!(
graphene_core::wasm_application_io::DrawImageFrameNode<_>,
input: ImageFrame<SRGBA8>,
output: WasmSurfaceHandleFrame,
params: [Arc<WasmSurfaceHandle>]
),
#[cfg(feature = "gpu")]
vec![(
NodeIdentifier::new("graphene_std::executor::MapGpuSingleImageNode<_>"),
|args| {
Box::pin(async move {
let document_node: DowncastBothNode<(), DocumentNode> = DowncastBothNode::new(args[0]);
let document_node: DowncastBothNode<(), graph_craft::document::DocumentNode> = DowncastBothNode::new(args[0]);
//let document_node = ClonedNode::new(document_node.eval(()));
let node = graphene_std::executor::MapGpuNode::new(document_node);
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(DocumentNode)]),
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(graph_craft::document::DocumentNode)]),
)],
#[cfg(feature = "gpu")]
vec![(
@ -258,7 +281,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
NodeIOTypes::new(
concrete!(ImageFrame<Color>),
concrete!(ImageFrame<Color>),
vec![value_fn!(ImageFrame<Color>), value_fn!(BlendMode), value_fn!(f32)],
vec![fn_type!(ImageFrame<Color>), fn_type!(BlendMode), fn_type!(f32)],
),
)],
vec![(
@ -327,28 +350,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
NodeIOTypes::new(
concrete!(()),
concrete!(ImageFrame<Color>),
vec![value_fn!(ImageFrame<Color>), value_fn!(ImageFrame<Color>), value_fn!(Vec<BrushStroke>)],
),
)],
vec![(
NodeIdentifier::new("graphene_std::brush::ReduceNode<_, _>"),
|args| {
Box::pin(async move {
let acc: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
let image = acc.eval(()).await;
let blend_node = graphene_core::raster::BlendNode::new(ClonedNode::new(BlendMode::Normal), ClonedNode::new(1.0));
let _ = &blend_node as &dyn for<'i> Node<'i, (Color, Color), Output = Color>;
let node = ReduceNode::new(ClonedNode::new(image), ValueNode::new(BlendImageTupleNode::new(ValueNode::new(blend_node))));
//let _ = &node as &dyn for<'i> Node<'i, core::slice::Iter<ImageFrame<Color>>, Output = ImageFrame<Color>>;
let node = FutureWrapperNode::new(node);
let any: DynAnyNode<Box<dyn Iterator<Item = ImageFrame<Color>> + Sync + Send>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(node));
any.into_type_erased()
})
},
NodeIOTypes::new(
concrete!(Box<dyn Iterator<Item = &ImageFrame<Color>> + Sync + Send>),
concrete!(ImageFrame<Color>),
vec![value_fn!(ImageFrame<Color>)],
vec![fn_type!(ImageFrame<Color>), fn_type!(ImageFrame<Color>), fn_type!(Vec<BrushStroke>)],
),
)],
// Filters
@ -374,7 +376,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
NodeIOTypes::new(
concrete!(ImageFrame<Color>),
concrete!(ImageFrame<Color>),
vec![value_fn!(ImageFrame<Color>), value_fn!(BlendMode), value_fn!(f64)],
vec![fn_type!(ImageFrame<Color>), fn_type!(BlendMode), fn_type!(f64)],
),
)],
raster_node!(graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>, params: [Color, f64, f64, f64, f64, f64, f64]),
@ -417,265 +419,59 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
}
})
},
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(f64), value_fn!(f64), value_fn!(bool)]),
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(f64), fn_type!(f64), fn_type!(bool)]),
)],
raster_node!(graphene_core::raster::OpacityNode<_>, params: [f64]),
raster_node!(graphene_core::raster::PosterizeNode<_>, params: [f64]),
raster_node!(graphene_core::raster::ExposureNode<_, _, _>, params: [f64, f64, f64]),
vec![
(
NodeIdentifier::new("graphene_std::memo::LetNode<_>"),
|_| {
Box::pin(async move {
let node: LetNode<ImageFrame<Color>> = graphene_std::memo::LetNode::new();
let any = graphene_std::any::DynAnyRefNode::new(node);
any.into_type_erased()
})
},
NodeIOTypes::new(concrete!(Option<ImageFrame<Color>>), concrete!(&ImageFrame<Color>), vec![]),
register_node!(graphene_core::memo::LetNode<_>, input: Option<ImageFrame<Color>>, params: []),
register_node!(graphene_core::memo::LetNode<_>, input: Option<graphene_core::EditorApi>, params: []),
async_node!(
graphene_core::memo::EndLetNode<_>,
input: graphene_core::EditorApi,
output: ImageFrame<Color>,
params: [ImageFrame<Color>]
),
async_node!(graphene_core::memo::EndLetNode<_>, input: graphene_core::EditorApi, output: VectorData, params: [VectorData]),
async_node!(
graphene_core::memo::EndLetNode<_>,
input: graphene_core::EditorApi,
output: graphene_core::GraphicGroup,
params: [graphene_core::GraphicGroup]
),
async_node!(
graphene_core::memo::EndLetNode<_>,
input: graphene_core::EditorApi,
output: graphene_core::Artboard,
params: [graphene_core::Artboard]
),
async_node!(
graphene_core::memo::EndLetNode<_>,
input: graphene_core::EditorApi,
output: WasmSurfaceHandleFrame,
params: [WasmSurfaceHandleFrame]
),
vec![(
NodeIdentifier::new("graphene_core::memo::RefNode<_, _>"),
|args| {
Box::pin(async move {
let node: DowncastBothNode<Option<graphene_core::EditorApi>, graphene_core::EditorApi> = graphene_std::any::DowncastBothNode::new(args[0]);
let node = <graphene_core::memo::RefNode<_, _>>::new(node);
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(
concrete!(()),
concrete!(graphene_core::EditorApi),
vec![fn_type!(Option<graphene_core::EditorApi>, graphene_core::EditorApi)],
),
(
NodeIdentifier::new("graphene_std::memo::LetNode<_>"),
|_| {
Box::pin(async move {
let node: LetNode<graphene_core::EditorApi> = graphene_std::memo::LetNode::new();
let any = graphene_std::any::DynAnyRefNode::new(node);
any.into_type_erased()
})
},
NodeIOTypes::new(concrete!(Option<graphene_core::EditorApi>), concrete!(&graphene_core::EditorApi), vec![]),
),
(
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|args| {
Box::pin(async move {
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
let node = graphene_std::memo::EndLetNode::new(input);
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
Box::pin(any) as TypeErasedPinned<'_>
})
},
NodeIOTypes::new(generic!(T), concrete!(ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>)]),
),
(
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|args| {
Box::pin(async move {
let input: DowncastBothNode<(), VectorData> = DowncastBothNode::new(args[0]);
let node = graphene_std::memo::EndLetNode::new(input);
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(generic!(T), concrete!(VectorData), vec![value_fn!(VectorData)]),
),
(
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|args| {
Box::pin(async move {
let input: DowncastBothNode<(), graphene_core::GraphicGroup> = DowncastBothNode::new(args[0]);
let node = graphene_std::memo::EndLetNode::new(input);
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(generic!(T), concrete!(graphene_core::GraphicGroup), vec![value_fn!(graphene_core::GraphicGroup)]),
),
(
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|args| {
Box::pin(async move {
let input: DowncastBothNode<(), graphene_core::Artboard> = DowncastBothNode::new(args[0]);
let node = graphene_std::memo::EndLetNode::new(input);
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(generic!(T), concrete!(graphene_core::Artboard), vec![value_fn!(graphene_core::Artboard)]),
),
(
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|args| {
Box::pin(async move {
let input: DowncastBothNode<(), WasmSurfaceHandleFrame> = DowncastBothNode::new(args[0]);
let node = graphene_std::memo::EndLetNode::new(input);
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(generic!(T), concrete!(WasmSurfaceHandleFrame), vec![value_fn!(WasmSurfaceHandleFrame)]),
),
(
NodeIdentifier::new("graphene_std::memo::RefNode<_, _>"),
|args| {
Box::pin(async move {
let map_fn: DowncastBothNode<Option<graphene_core::EditorApi>, &graphene_core::EditorApi> = DowncastBothNode::new(args[0]);
//let map_fn = map_fn.then(EvalSyncNode::new());
let node = graphene_std::memo::RefNode::new(map_fn);
let any = graphene_std::any::DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(
concrete!(()),
concrete!(&graphene_core::EditorApi),
vec![fn_type!(Option<graphene_core::EditorApi>, &graphene_core::EditorApi)],
),
),
/*
(
NodeIdentifier::new("graphene_std::raster::ImaginateNode<_>"),
|args| {
Box::pin(async move {
let cached = graphene_std::any::input_node::<Option<std::sync::Arc<Image<Color>>>>(args[15]);
let cached = cached.then(EvalSyncNode::new());
let node = graphene_std::raster::ImaginateNode::new(cached);
let node = FutureWrapperNode::new(node);
let any = DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(
concrete!(ImageFrame<Color>),
concrete!(ImageFrame<Color>),
vec![
value_fn!(f64),
value_fn!(Option<DVec2>),
value_fn!(f64),
value_fn!(ImaginateSamplingMethod),
value_fn!(f64),
value_fn!(String),
value_fn!(String),
value_fn!(bool),
value_fn!(f64),
value_fn!(Option<Vec<u64>>),
value_fn!(bool),
value_fn!(f64),
value_fn!(ImaginateMaskStartingFill),
value_fn!(bool),
value_fn!(bool),
value_fn!(Option<std::sync::Arc<Image<Color>>>),
value_fn!(f64),
value_fn!(ImaginateStatus),
],
),
),
*/
/*
(
NodeIdentifier::new("graphene_core::raster::BlurNode"),
|args| {
let radius = DowncastBothNode::<(), u32>::new(args[0]);
let sigma = DowncastBothNode::<(), f64>::new(args[1]);
let image = DowncastBothRefNode::<Image<Color>, Image<Color>>::new(args[2]);
let image = image.then(EvalSyncNode::new());
let empty_image: ValueNode<Image<Color>> = ValueNode::new(Image::empty());
let empty: TypeNode<_, (), Image<Color>> = TypeNode::new(empty_image.then(CloneNode::new()));
use graphene_core::Node;
let radius = ClonedNode::new(radius.eval(()));
let sigma = ClonedNode::new(sigma.eval(()));
//let image = &image as &dyn for<'a> Node<'a, (), Output = &'a Image>;
// dirty hack: we abuse that the cache node will ignore the input if it is evaluated a second time
let image = empty.then(image).then(ImageRefNode::new());
let window = WindowNode::new(radius, image.clone());
let map_gaussian = MapSndNode::new(ValueNode::new(DistanceNode.then(GaussianNode::new(sigma))));
let map_distances = MapNode::new(ValueNode::new(map_gaussian));
let gaussian_iter = window.then(map_distances);
let avg = gaussian_iter.then(WeightedAvgNode::new());
let avg: TypeNode<_, u32, Color> = TypeNode::new(avg);
let blur_iter = MapNode::new(ValueNode::new(avg));
let pixel_iter = image.clone().then(ImageIndexIterNode::new());
let blur = pixel_iter.then(blur_iter);
let collect = CollectNode {};
let vec = blur.then(collect);
let new_image = MapImageSliceNode::new(vec);
let dimensions = image.then(ImageDimensionsNode::new());
let dimensions: TypeNode<_, (), (u32, u32)> = TypeNode::new(dimensions);
let new_image = dimensions.then(new_image);
let new_image = ForgetNode::new().then(new_image);
let new_image = FutureWrapperNode::new(new_image);
let node: DynAnyNode<&Image<Color>, _, _> = DynAnyNode::new(ValueNode::new(new_image));
Box::pin(node)
},
NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), vec![value_fn!(u32), value_fn!(f64)]),
),
//register_node!(graphene_std::memo::CacheNode<_>, input: Image<Color>, params: []),
*/
(
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|args| {
Box::pin(async move {
let input: DowncastBothNode<(), Image<Color>> = DowncastBothNode::new(args[0]);
let node: CacheNode<Image<Color>, _> = graphene_std::memo::CacheNode::new(input);
let any = DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(concrete!(()), concrete!(Image<Color>), vec![value_fn!(Image<Color>)]),
),
(
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|args| {
Box::pin(async move {
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input);
let any = DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(concrete!(()), concrete!(ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>)]),
),
(
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|args| {
Box::pin(async move {
let input: DowncastBothNode<ImageFrame<Color>, ImageFrame<Color>> = DowncastBothNode::new(args[0]);
let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input);
let any = DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(ImageFrame<Color>, ImageFrame<Color>)]),
),
(
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|args| {
Box::pin(async move {
let input: DowncastBothNode<(), QuantizationChannels> = DowncastBothNode::new(args[0]);
let node: CacheNode<QuantizationChannels, _> = graphene_std::memo::CacheNode::new(input);
let any = DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(concrete!(()), concrete!(QuantizationChannels), vec![value_fn!(QuantizationChannels)]),
),
(
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|args| {
Box::pin(async move {
let input: DowncastBothNode<(), Vec<DVec2>> = DowncastBothNode::new(args[0]);
let node: CacheNode<Vec<DVec2>, _> = graphene_std::memo::CacheNode::new(input);
let any = DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(concrete!(()), concrete!(Vec<DVec2>), vec![value_fn!(Vec<DVec2>)]),
),
(
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|args| {
Box::pin(async move {
let input: DowncastBothNode<(), Arc<WasmSurfaceHandle>> = DowncastBothNode::new(args[0]);
let node: CacheNode<Arc<WasmSurfaceHandle>, _> = graphene_std::memo::CacheNode::new(input);
let any = DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(concrete!(()), concrete!(Arc<WasmSurfaceHandle>), vec![value_fn!(Arc<WasmSurfaceHandle>)]),
),
],
)],
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Image<Color>, params: [Image<Color>]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: ImageFrame<Color>, params: [ImageFrame<Color>]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: QuantizationChannels, params: [QuantizationChannels]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Vec<DVec2>, params: [Vec<DVec2>]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Arc<WasmSurfaceHandle>, params: [Arc<WasmSurfaceHandle>]),
register_node!(graphene_core::structural::ConsNode<_, _>, input: Image<Color>, params: [&str]),
register_node!(graphene_std::raster::ImageFrameNode<_, _>, input: Image<Color>, params: [DAffine2]),
#[cfg(feature = "quantization")]
@ -698,9 +494,9 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
input: Vec<graphene_core::vector::bezier_rs::Subpath<graphene_core::uuid::ManipulatorGroupId>>,
params: [Vec<graphene_core::uuid::ManipulatorGroupId>]
),
register_node!(graphene_core::text::TextGenerator<_, _, _>, input: &graphene_core::EditorApi, params: [String, graphene_core::text::Font, f64]),
register_node!(graphene_core::text::TextGenerator<_, _, _>, input: graphene_core::EditorApi, params: [String, graphene_core::text::Font, f64]),
register_node!(graphene_std::brush::VectorPointsNode, input: VectorData, params: []),
register_node!(graphene_core::ExtractImageFrame, input: &graphene_core::EditorApi, params: []),
register_node!(graphene_core::ExtractImageFrame, input: graphene_core::EditorApi, params: []),
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::vector::VectorData, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: ImageFrame<Color>, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::GraphicGroup, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),