From 69ed80b79b62e52b46f7ec3094e54b5518862104 Mon Sep 17 00:00:00 2001 From: Firestar99 Date: Tue, 8 Jul 2025 01:29:59 +0200 Subject: [PATCH] Add `::IDENTITY` to node macro to return a `ProtoNodeIdentifier` that is always a `&'static str` (#2842) * fix warnings on master * make the `ProtoNodeIdentifier` of a Node be accessible and always a borrowed `&'static str` * always generate `node_name::identifier()`, even with `skip_impl` * make `FrontendNodeType` use Cow * remove broken `DocumentNodeDefinition`s for old GPU nodes * don't reexport `graphic_element` in it's entirety, only data structures * adjust everything to use the new `node_name::identifier()` * fixup imports for wasm * turn identifier fn into a constant --- .../node_graph/document_node_definitions.rs | 459 +++--------------- .../document_node_derive.rs | 4 +- .../document/node_graph/node_properties.rs | 2 +- .../document/node_graph/utility_types.rs | 27 +- .../graph_modification_utils.rs | 8 +- .../shapes/ellipse_shape.rs | 2 +- .../tool/tool_messages/artboard_tool.rs | 2 +- editor/src/node_graph_executor.rs | 9 +- editor/src/node_graph_executor/runtime.rs | 6 +- frontend/src-tauri/src/main.rs | 4 - node-graph/gcore/src/lib.rs | 6 +- node-graph/gcore/src/memo.rs | 14 +- node-graph/gcore/src/registry.rs | 6 +- node-graph/gcore/src/types.rs | 49 +- node-graph/graph-craft/src/document.rs | 11 +- node-graph/graph-craft/src/document/value.rs | 4 +- node-graph/interpreted-executor/src/lib.rs | 2 +- node-graph/interpreted-executor/src/util.rs | 4 +- node-graph/node-macro/src/codegen.rs | 109 +++-- node-graph/preprocessor/src/lib.rs | 8 +- 20 files changed, 213 insertions(+), 523 deletions(-) diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs index e2fa3128a..ce9378857 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs @@ -21,6 +21,7 @@ use graphene_std::extract_xy::XY; use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha}; use graphene_std::raster_types::{CPU, RasterDataTable}; use graphene_std::text::{Font, TypesettingConfig}; +#[allow(unused_imports)] use graphene_std::transform::Footprint; use graphene_std::vector::VectorDataTable; use graphene_std::*; @@ -88,7 +89,7 @@ fn static_nodes() -> Vec { category: "General", node_template: NodeTemplate { document_node: DocumentNode { - implementation: DocumentNodeImplementation::proto("graphene_core::ops::IdentityNode"), + implementation: DocumentNodeImplementation::ProtoNode(ops::identity::IDENTIFIER), inputs: vec![NodeInput::value(TaggedValue::None, true)], ..Default::default() }, @@ -107,7 +108,7 @@ fn static_nodes() -> Vec { category: "Debug", node_template: NodeTemplate { document_node: DocumentNode { - implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), + implementation: DocumentNodeImplementation::ProtoNode(memo::monitor::IDENTIFIER), inputs: vec![NodeInput::value(TaggedValue::None, true)], manual_composition: Some(generic!(T)), skip_deduplication: true, @@ -148,19 +149,19 @@ fn static_nodes() -> Vec { nodes: [ DocumentNode { inputs: vec![NodeInput::network(generic!(T), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, DocumentNode { inputs: vec![NodeInput::node(NodeId(0), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::FreezeRealTimeNode")), + implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::freeze_real_time::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, DocumentNode { inputs: vec![NodeInput::node(NodeId(1), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::BoundlessFootprintNode")), + implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::boundless_footprint::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, @@ -230,21 +231,21 @@ fn static_nodes() -> Vec { // Secondary (left) input type coercion DocumentNode { inputs: vec![NodeInput::network(generic!(T), 1)], - implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::ToElementNode"), + implementation: DocumentNodeImplementation::ProtoNode(graphic_element::to_element::IDENTIFIER), manual_composition: Some(concrete!(Context)), ..Default::default() }, // Primary (bottom) input type coercion DocumentNode { inputs: vec![NodeInput::network(generic!(T), 0)], - implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::ToGroupNode"), + implementation: DocumentNodeImplementation::ProtoNode(graphic_element::to_group::IDENTIFIER), manual_composition: Some(concrete!(Context)), ..Default::default() }, // The monitor node is used to display a thumbnail in the UI DocumentNode { inputs: vec![NodeInput::node(NodeId(0), 0)], - implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), + implementation: DocumentNodeImplementation::ProtoNode(memo::monitor::IDENTIFIER), manual_composition: Some(concrete!(Context)), skip_deduplication: true, ..Default::default() @@ -256,7 +257,7 @@ fn static_nodes() -> Vec { NodeInput::node(NodeId(2), 0), NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath), ], - implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::LayerNode"), + implementation: DocumentNodeImplementation::ProtoNode(graphic_element::layer::IDENTIFIER), ..Default::default() }, ] @@ -337,7 +338,7 @@ fn static_nodes() -> Vec { // Ensure this ID is kept in sync with the ID in set_alias so that the name input is kept in sync with the alias DocumentNode { manual_composition: Some(generic!(T)), - implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::ToArtboardNode"), + implementation: DocumentNodeImplementation::ProtoNode(graphic_element::to_artboard::IDENTIFIER), inputs: vec![ NodeInput::network(concrete!(TaggedValue), 1), NodeInput::value(TaggedValue::String(String::from("Artboard")), false), @@ -352,7 +353,7 @@ fn static_nodes() -> Vec { // TODO: Check if thumbnail is reversed DocumentNode { inputs: vec![NodeInput::node(NodeId(0), 0)], - implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), + implementation: DocumentNodeImplementation::ProtoNode(memo::monitor::IDENTIFIER), manual_composition: Some(generic!(T)), skip_deduplication: true, ..Default::default() @@ -364,7 +365,7 @@ fn static_nodes() -> Vec { NodeInput::node(NodeId(1), 0), NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath), ], - implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::AppendArtboardNode"), + implementation: DocumentNodeImplementation::ProtoNode(graphic_element::append_artboard::IDENTIFIER), ..Default::default() }, ] @@ -466,13 +467,13 @@ fn static_nodes() -> Vec { DocumentNode { inputs: vec![NodeInput::value(TaggedValue::None, false), NodeInput::scope("editor-api"), NodeInput::network(concrete!(String), 1)], manual_composition: Some(concrete!(Context)), - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::LoadResourceNode")), + implementation: DocumentNodeImplementation::ProtoNode(wasm_application_io::load_resource::IDENTIFIER), ..Default::default() }, DocumentNode { inputs: vec![NodeInput::node(NodeId(0), 0)], manual_composition: Some(concrete!(Context)), - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::DecodeImageNode")), + implementation: DocumentNodeImplementation::ProtoNode(wasm_application_io::decode_image::IDENTIFIER), ..Default::default() }, ] @@ -522,6 +523,7 @@ fn static_nodes() -> Vec { description: Cow::Borrowed("Loads an image from a given URL"), properties: None, }, + #[cfg(feature = "gpu")] DocumentNodeDefinition { identifier: "Create Canvas", category: "Debug: GPU", @@ -532,14 +534,14 @@ fn static_nodes() -> Vec { nodes: [ DocumentNode { inputs: vec![NodeInput::scope("editor-api")], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")), + implementation: DocumentNodeImplementation::ProtoNode(wasm_application_io::create_surface::IDENTIFIER), skip_deduplication: true, ..Default::default() }, DocumentNode { manual_composition: Some(concrete!(Context)), inputs: vec![NodeInput::node(NodeId(0), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER), ..Default::default() }, ] @@ -587,99 +589,7 @@ fn static_nodes() -> Vec { description: Cow::Borrowed("Creates a new canvas object."), properties: None, }, - DocumentNodeDefinition { - identifier: "Draw Canvas", - category: "Debug: GPU", - node_template: NodeTemplate { - document_node: DocumentNode { - implementation: DocumentNodeImplementation::Network(NodeNetwork { - exports: vec![NodeInput::node(NodeId(3), 0)], - nodes: [ - DocumentNode { - inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<_, RasterDataTable>")), - ..Default::default() - }, - DocumentNode { - inputs: vec![NodeInput::scope("editor-api")], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")), - skip_deduplication: true, - ..Default::default() - }, - DocumentNode { - manual_composition: Some(concrete!(Context)), - inputs: vec![NodeInput::node(NodeId(1), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), - ..Default::default() - }, - DocumentNode { - inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::node(NodeId(2), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::DrawImageFrameNode")), - ..Default::default() - }, - ] - .into_iter() - .enumerate() - .map(|(id, node)| (NodeId(id as u64), node)) - .collect(), - ..Default::default() - }), - inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)], - ..Default::default() - }, - persistent_node_metadata: DocumentNodePersistentMetadata { - input_metadata: vec![("In", "TODO").into()], - output_names: vec!["Canvas".to_string()], - network_metadata: Some(NodeNetworkMetadata { - persistent_metadata: NodeNetworkPersistentMetadata { - node_metadata: [ - DocumentNodeMetadata { - persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Into".to_string(), - node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), - ..Default::default() - }, - ..Default::default() - }, - DocumentNodeMetadata { - persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Create Canvas".to_string(), - node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 2)), - ..Default::default() - }, - ..Default::default() - }, - DocumentNodeMetadata { - persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Cache".to_string(), - node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 2)), - ..Default::default() - }, - ..Default::default() - }, - DocumentNodeMetadata { - persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Draw Canvas".to_string(), - node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), - ..Default::default() - }, - ..Default::default() - }, - ] - .into_iter() - .enumerate() - .map(|(id, node)| (NodeId(id as u64), node)) - .collect(), - ..Default::default() - }, - ..Default::default() - }), - ..Default::default() - }, - }, - description: Cow::Borrowed("Draws raster data to a canvas element."), - properties: None, - }, + #[cfg(all(feature = "gpu", target_arch = "wasm32"))] DocumentNodeDefinition { identifier: "Rasterize", category: "Raster", @@ -690,20 +600,20 @@ fn static_nodes() -> Vec { nodes: [ DocumentNode { inputs: vec![NodeInput::scope("editor-api")], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")), + implementation: DocumentNodeImplementation::ProtoNode(wasm_application_io::create_surface::IDENTIFIER), manual_composition: Some(concrete!(Context)), skip_deduplication: true, ..Default::default() }, DocumentNode { inputs: vec![NodeInput::node(NodeId(0), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER), manual_composition: Some(concrete!(Context)), ..Default::default() }, DocumentNode { inputs: vec![NodeInput::network(generic!(T), 0), NodeInput::network(concrete!(Footprint), 1), NodeInput::node(NodeId(1), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::RasterizeNode")), + implementation: DocumentNodeImplementation::ProtoNode(wasm_application_io::rasterize::IDENTIFIER), manual_composition: Some(concrete!(Context)), ..Default::default() }, @@ -778,7 +688,7 @@ fn static_nodes() -> Vec { node_template: NodeTemplate { document_node: DocumentNode { manual_composition: Some(concrete!(Context)), - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_raster_nodes::std_nodes::NoisePatternNode")), + implementation: DocumentNodeImplementation::ProtoNode(raster_nodes::std_nodes::noise_pattern::IDENTIFIER), inputs: vec![ NodeInput::value(TaggedValue::None, false), NodeInput::value(TaggedValue::Bool(true), false), @@ -843,7 +753,7 @@ fn static_nodes() -> Vec { NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Red), false), ], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")), + implementation: DocumentNodeImplementation::ProtoNode(raster_nodes::adjustments::extract_channel::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, @@ -852,7 +762,7 @@ fn static_nodes() -> Vec { NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Green), false), ], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")), + implementation: DocumentNodeImplementation::ProtoNode(raster_nodes::adjustments::extract_channel::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, @@ -861,7 +771,7 @@ fn static_nodes() -> Vec { NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Blue), false), ], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")), + implementation: DocumentNodeImplementation::ProtoNode(raster_nodes::adjustments::extract_channel::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, @@ -870,7 +780,7 @@ fn static_nodes() -> Vec { NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Alpha), false), ], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")), + implementation: DocumentNodeImplementation::ProtoNode(raster_nodes::adjustments::extract_channel::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, @@ -948,13 +858,13 @@ fn static_nodes() -> Vec { nodes: [ DocumentNode { inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::XY(XY::X), false)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::extract_xy::ExtractXyNode")), + implementation: DocumentNodeImplementation::ProtoNode(extract_xy::extract_xy::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, DocumentNode { inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::XY(XY::Y), false)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::extract_xy::ExtractXyNode")), + implementation: DocumentNodeImplementation::ProtoNode(extract_xy::extract_xy::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, @@ -1024,7 +934,7 @@ fn static_nodes() -> Vec { NodeInput::network(concrete!(BrushCache), 2), ], manual_composition: Some(concrete!(Context)), - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_brush::brush::BrushNode")), + implementation: DocumentNodeImplementation::ProtoNode(brush::brush::brush::IDENTIFIER), ..Default::default() }] .into_iter() @@ -1072,7 +982,7 @@ fn static_nodes() -> Vec { category: "Debug", node_template: NodeTemplate { document_node: DocumentNode { - implementation: DocumentNodeImplementation::proto("graphene_core::memo::MemoNode"), + implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER), inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)], manual_composition: Some(concrete!(Context)), ..Default::default() @@ -1091,7 +1001,7 @@ fn static_nodes() -> Vec { category: "Debug", node_template: NodeTemplate { document_node: DocumentNode { - implementation: DocumentNodeImplementation::proto("graphene_core::memo::ImpureMemoNode"), + implementation: DocumentNodeImplementation::ProtoNode(memo::impure_memo::IDENTIFIER), inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)], manual_composition: Some(concrete!(Context)), ..Default::default() @@ -1105,164 +1015,6 @@ fn static_nodes() -> Vec { description: Cow::Borrowed("TODO"), properties: None, }, - DocumentNodeDefinition { - identifier: "Storage", - category: "Debug: GPU", - node_template: NodeTemplate { - document_node: DocumentNode { - implementation: DocumentNodeImplementation::Network(NodeNetwork { - exports: vec![NodeInput::node(NodeId(2), 0)], - nodes: [ - DocumentNode { - inputs: vec![NodeInput::scope("editor-api")], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode")), - ..Default::default() - }, - DocumentNode { - inputs: vec![NodeInput::network(concrete!(Vec), 0), NodeInput::node(NodeId(0), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::StorageNode")), - ..Default::default() - }, - DocumentNode { - manual_composition: Some(concrete!(Context)), - inputs: vec![NodeInput::node(NodeId(1), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), - ..Default::default() - }, - ] - .into_iter() - .enumerate() - .map(|(id, node)| (NodeId(id as u64), node)) - .collect(), - ..Default::default() - }), - inputs: vec![NodeInput::value(TaggedValue::None, true)], - ..Default::default() - }, - persistent_node_metadata: DocumentNodePersistentMetadata { - input_metadata: vec![("In", "TODO").into()], - output_names: vec!["Storage".to_string()], - network_metadata: Some(NodeNetworkMetadata { - persistent_metadata: NodeNetworkPersistentMetadata { - node_metadata: [ - DocumentNodeMetadata { - persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Extract Executor".to_string(), - node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), - ..Default::default() - }, - ..Default::default() - }, - DocumentNodeMetadata { - persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Create Storage".to_string(), - node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), - ..Default::default() - }, - ..Default::default() - }, - DocumentNodeMetadata { - persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Cache".to_string(), - node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), - ..Default::default() - }, - ..Default::default() - }, - ] - .into_iter() - .enumerate() - .map(|(id, node)| (NodeId(id as u64), node)) - .collect(), - ..Default::default() - }, - ..Default::default() - }), - ..Default::default() - }, - }, - description: Cow::Borrowed("TODO"), - properties: None, - }, - DocumentNodeDefinition { - identifier: "Create Output Buffer", - category: "Debug: GPU", - node_template: NodeTemplate { - document_node: DocumentNode { - implementation: DocumentNodeImplementation::Network(NodeNetwork { - exports: vec![NodeInput::node(NodeId(2), 0)], - nodes: [ - DocumentNode { - inputs: vec![NodeInput::scope("editor-api")], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode")), - ..Default::default() - }, - DocumentNode { - inputs: vec![NodeInput::network(concrete!(usize), 0), NodeInput::node(NodeId(0), 0), NodeInput::network(concrete!(Type), 1)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::CreateOutputBufferNode")), - ..Default::default() - }, - DocumentNode { - manual_composition: Some(concrete!(Context)), - inputs: vec![NodeInput::node(NodeId(1), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), - ..Default::default() - }, - ] - .into_iter() - .enumerate() - .map(|(id, node)| (NodeId(id as u64), node)) - .collect(), - ..Default::default() - }), - inputs: vec![NodeInput::value(TaggedValue::None, true), NodeInput::value(TaggedValue::None, true)], - ..Default::default() - }, - persistent_node_metadata: DocumentNodePersistentMetadata { - input_metadata: vec![("In", "TODO").into(), ("In", "TODO").into()], - output_names: vec!["Output Buffer".to_string()], - network_metadata: Some(NodeNetworkMetadata { - persistent_metadata: NodeNetworkPersistentMetadata { - node_metadata: [ - DocumentNodeMetadata { - persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Extract Executor".to_string(), - node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), - ..Default::default() - }, - ..Default::default() - }, - DocumentNodeMetadata { - persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Create Output Buffer".to_string(), - node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), - ..Default::default() - }, - ..Default::default() - }, - DocumentNodeMetadata { - persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Cache".to_string(), - node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), - ..Default::default() - }, - ..Default::default() - }, - ] - .into_iter() - .enumerate() - .map(|(id, node)| (NodeId(id as u64), node)) - .collect(), - ..Default::default() - }, - ..Default::default() - }), - ..Default::default() - }, - }, - description: Cow::Borrowed("TODO"), - properties: None, - }, #[cfg(feature = "gpu")] DocumentNodeDefinition { identifier: "Create GPU Surface", @@ -1275,13 +1027,13 @@ fn static_nodes() -> Vec { DocumentNode { manual_composition: Some(concrete!(Context)), inputs: vec![NodeInput::scope("editor-api")], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::CreateGpuSurfaceNode")), + implementation: DocumentNodeImplementation::ProtoNode(wgpu_executor::create_gpu_surface::IDENTIFIER), ..Default::default() }, DocumentNode { manual_composition: Some(concrete!(Context)), inputs: vec![NodeInput::node(NodeId(0), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode")), + implementation: DocumentNodeImplementation::ProtoNode(memo::impure_memo::IDENTIFIER), ..Default::default() }, ] @@ -1329,87 +1081,6 @@ fn static_nodes() -> Vec { description: Cow::Borrowed("TODO"), properties: None, }, - #[cfg(feature = "gpu")] - DocumentNodeDefinition { - identifier: "Upload Texture", - category: "Debug: GPU", - node_template: NodeTemplate { - document_node: DocumentNode { - implementation: DocumentNodeImplementation::Network(NodeNetwork { - exports: vec![NodeInput::node(NodeId(2), 0)], - nodes: [ - DocumentNode { - inputs: vec![NodeInput::scope("editor-api")], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<&WgpuExecutor>")), - ..Default::default() - }, - DocumentNode { - inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::node(NodeId(0), 0)], - manual_composition: Some(generic!(T)), - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::UploadTextureNode")), - ..Default::default() - }, - DocumentNode { - manual_composition: Some(generic!(T)), - inputs: vec![NodeInput::node(NodeId(1), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode")), - ..Default::default() - }, - ] - .into_iter() - .enumerate() - .map(|(id, node)| (NodeId(id as u64), node)) - .collect(), - ..Default::default() - }), - inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)], - ..Default::default() - }, - persistent_node_metadata: DocumentNodePersistentMetadata { - input_metadata: vec![("In", "TODO").into()], - output_names: vec!["Texture".to_string()], - network_metadata: Some(NodeNetworkMetadata { - persistent_metadata: NodeNetworkPersistentMetadata { - node_metadata: [ - DocumentNodeMetadata { - persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Extract Executor".to_string(), - node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), - ..Default::default() - }, - ..Default::default() - }, - DocumentNodeMetadata { - persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Upload Texture".to_string(), - node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), - ..Default::default() - }, - ..Default::default() - }, - DocumentNodeMetadata { - persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Cache".to_string(), - node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), - ..Default::default() - }, - ..Default::default() - }, - ] - .into_iter() - .enumerate() - .map(|(id, node)| (NodeId(id as u64), node)) - .collect(), - ..Default::default() - }, - ..Default::default() - }), - ..Default::default() - }, - }, - description: Cow::Borrowed("TODO"), - properties: None, - }, DocumentNodeDefinition { identifier: "Extract", category: "Debug", @@ -1466,7 +1137,7 @@ fn static_nodes() -> Vec { nodes: vec![ DocumentNode { inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0)], - implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), + implementation: DocumentNodeImplementation::ProtoNode(memo::monitor::IDENTIFIER), manual_composition: Some(generic!(T)), skip_deduplication: true, ..Default::default() @@ -1478,7 +1149,7 @@ fn static_nodes() -> Vec { NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath), ], manual_composition: Some(generic!(T)), - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::vector_data::modification::PathModifyNode")), + implementation: DocumentNodeImplementation::ProtoNode(vector::path_modify::IDENTIFIER), ..Default::default() }, ] @@ -1536,7 +1207,7 @@ fn static_nodes() -> Vec { category: "Text", node_template: NodeTemplate { document_node: DocumentNode { - implementation: DocumentNodeImplementation::proto("graphene_std::text::TextNode"), + implementation: DocumentNodeImplementation::ProtoNode(text::text::IDENTIFIER), manual_composition: Some(concrete!(Context)), inputs: vec![ NodeInput::scope("editor-api"), @@ -1644,7 +1315,7 @@ fn static_nodes() -> Vec { nodes: [ DocumentNode { inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0)], - implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), + implementation: DocumentNodeImplementation::ProtoNode(memo::monitor::IDENTIFIER), manual_composition: Some(generic!(T)), skip_deduplication: true, ..Default::default() @@ -1659,7 +1330,7 @@ fn static_nodes() -> Vec { NodeInput::network(concrete!(DVec2), 5), ], manual_composition: Some(concrete!(Context)), - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::TransformNode")), + implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::transform::IDENTIFIER), ..Default::default() }, ] @@ -1743,25 +1414,25 @@ fn static_nodes() -> Vec { nodes: vec![ DocumentNode { inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0), NodeInput::network(concrete!(vector::style::Fill), 1)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_path_bool::BooleanOperationNode")), + implementation: DocumentNodeImplementation::ProtoNode(path_bool::boolean_operation::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, DocumentNode { inputs: vec![NodeInput::node(NodeId(0), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, DocumentNode { inputs: vec![NodeInput::node(NodeId(1), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::FreezeRealTimeNode")), + implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::freeze_real_time::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, DocumentNode { inputs: vec![NodeInput::node(NodeId(2), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::BoundlessFootprintNode")), + implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::boundless_footprint::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, @@ -1841,7 +1512,7 @@ fn static_nodes() -> Vec { nodes: [ DocumentNode { inputs: vec![NodeInput::network(concrete!(graphene_std::vector::VectorDataTable), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SubpathSegmentLengthsNode")), + implementation: DocumentNodeImplementation::ProtoNode(vector::subpath_segment_lengths::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, @@ -1856,25 +1527,25 @@ fn static_nodes() -> Vec { NodeInput::network(concrete!(bool), 6), NodeInput::node(NodeId(0), 0), ], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SamplePolylineNode")), + implementation: DocumentNodeImplementation::ProtoNode(vector::sample_polyline::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, DocumentNode { inputs: vec![NodeInput::node(NodeId(1), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, DocumentNode { inputs: vec![NodeInput::node(NodeId(2), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::FreezeRealTimeNode")), + implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::freeze_real_time::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, DocumentNode { inputs: vec![NodeInput::node(NodeId(3), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::BoundlessFootprintNode")), + implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::boundless_footprint::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, @@ -2012,24 +1683,24 @@ fn static_nodes() -> Vec { NodeInput::network(concrete!(u32), 2), ], manual_composition: Some(generic!(T)), - implementation: DocumentNodeImplementation::proto("graphene_core::vector::PoissonDiskPointsNode"), + implementation: DocumentNodeImplementation::ProtoNode(vector::poisson_disk_points::IDENTIFIER), ..Default::default() }, DocumentNode { inputs: vec![NodeInput::node(NodeId(0), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")), + implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, DocumentNode { inputs: vec![NodeInput::node(NodeId(1), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::FreezeRealTimeNode")), + implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::freeze_real_time::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, DocumentNode { inputs: vec![NodeInput::node(NodeId(2), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::BoundlessFootprintNode")), + implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::boundless_footprint::IDENTIFIER), manual_composition: Some(generic!(T)), ..Default::default() }, @@ -2649,11 +2320,11 @@ pub fn resolve_document_node_type(identifier: &str) -> Option<&DocumentNodeDefin pub fn collect_node_types() -> Vec { // Create a mapping from registry ID to document node identifier - let id_to_identifier_map: HashMap = DOCUMENT_NODE_TYPES + let id_to_identifier_map: HashMap = DOCUMENT_NODE_TYPES .iter() .filter_map(|definition| { - if let DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) = &definition.node_template.document_node.implementation { - Some((name.to_string(), definition.identifier)) + if let DocumentNodeImplementation::ProtoNode(name) = &definition.node_template.document_node.implementation { + Some((name.clone(), definition.identifier)) } else { None } @@ -2661,28 +2332,28 @@ pub fn collect_node_types() -> Vec { .collect(); let mut extracted_node_types = Vec::new(); - let node_registry = graphene_std::registry::NODE_REGISTRY.lock().unwrap(); - let node_metadata = graphene_std::registry::NODE_METADATA.lock().unwrap(); + let node_registry = registry::NODE_REGISTRY.lock().unwrap(); + let node_metadata = registry::NODE_METADATA.lock().unwrap(); for (id, metadata) in node_metadata.iter() { if let Some(implementations) = node_registry.get(id) { let identifier = match id_to_identifier_map.get(id) { - Some(&id) => id.to_string(), + Some(&id) => id, None => continue, }; // Extract category from metadata (already creates an owned String) - let category = metadata.category.unwrap_or_default().to_string(); + let category = metadata.category.unwrap_or_default(); // Extract input types (already creates owned Strings) let input_types = implementations .iter() - .flat_map(|(_, node_io)| node_io.inputs.iter().map(|ty| ty.nested_type().to_string())) - .collect::>() + .flat_map(|(_, node_io)| node_io.inputs.iter().map(|ty| ty.nested_type().to_cow_string())) + .collect::>>() .into_iter() - .collect::>(); + .collect::>>(); // Create a FrontendNodeType - let node_type = FrontendNodeType::with_owned_strings_and_input_types(identifier, category, input_types); + let node_type = FrontendNodeType::with_input_types(identifier, category, input_types); // Store the created node_type extracted_node_types.push(node_type); @@ -2698,8 +2369,8 @@ pub fn collect_node_types() -> Vec { .document_node .inputs .iter() - .filter_map(|node_input| node_input.as_value().map(|node_value| node_value.ty().nested_type().to_string())) - .collect::>(); + .filter_map(|node_input| node_input.as_value().map(|node_value| node_value.ty().nested_type().to_cow_string())) + .collect::>>(); FrontendNodeType::with_input_types(definition.identifier, definition.category, input_types) }) diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs index 8fcec559a..85ce4b516 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs @@ -21,7 +21,7 @@ pub(super) fn post_process_nodes(mut custom: Vec) -> Vec }; } - let node_registry = graphene_core::registry::NODE_REGISTRY.lock().unwrap(); + let node_registry = NODE_REGISTRY.lock().unwrap(); 'outer: for (id, metadata) in NODE_METADATA.lock().unwrap().iter() { for node in custom.iter() { let DocumentNodeDefinition { @@ -32,7 +32,7 @@ pub(super) fn post_process_nodes(mut custom: Vec) -> Vec .. } = node; match implementation { - DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) if name == id => continue 'outer, + DocumentNodeImplementation::ProtoNode(name) if name == id => continue 'outer, _ => (), } } diff --git a/editor/src/messages/portfolio/document/node_graph/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs index bc40dd36e..18a7f8290 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -1436,7 +1436,7 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper if let Some(field) = graphene_std::registry::NODE_METADATA .lock() .unwrap() - .get(&proto_node_identifier.name.clone().into_owned()) + .get(&proto_node_identifier) .and_then(|metadata| metadata.fields.get(input_index)) { number_options = (field.number_min, field.number_max, field.number_mode_range); diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs index b743cb1fc..0cfd49282 100644 --- a/editor/src/messages/portfolio/document/node_graph/utility_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs @@ -2,6 +2,7 @@ use crate::messages::portfolio::document::utility_types::network_interface::{Inp use graph_craft::document::NodeId; use graph_craft::document::value::TaggedValue; use graphene_std::Type; +use std::borrow::Cow; #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum FrontendGraphDataType { @@ -98,33 +99,25 @@ pub struct FrontendNode { #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub struct FrontendNodeType { - pub name: String, - pub category: String, + pub name: Cow<'static, str>, + pub category: Cow<'static, str>, #[serde(rename = "inputTypes")] - pub input_types: Option>, + pub input_types: Option>>, } impl FrontendNodeType { - pub fn new(name: &'static str, category: &'static str) -> Self { + pub fn new(name: impl Into>, category: impl Into>) -> Self { Self { - name: name.to_string(), - category: category.to_string(), + name: name.into(), + category: category.into(), input_types: None, } } - pub fn with_input_types(name: &'static str, category: &'static str, input_types: Vec) -> Self { + pub fn with_input_types(name: impl Into>, category: impl Into>, input_types: Vec>) -> Self { Self { - name: name.to_string(), - category: category.to_string(), - input_types: Some(input_types), - } - } - - pub fn with_owned_strings_and_input_types(name: String, category: String, input_types: Vec) -> Self { - Self { - name, - category, + name: name.into(), + category: category.into(), input_types: Some(input_types), } } diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index 765bfc1ea..22c53f111 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -5,9 +5,9 @@ use crate::messages::portfolio::document::utility_types::network_interface::{Flo use crate::messages::prelude::*; use bezier_rs::Subpath; use glam::DVec2; -use graph_craft::concrete; use graph_craft::document::value::TaggedValue; use graph_craft::document::{NodeId, NodeInput}; +use graph_craft::{ProtoNodeIdentifier, concrete}; use graphene_std::Color; use graphene_std::NodeInputDecleration; use graphene_std::raster::BlendMode; @@ -416,14 +416,14 @@ impl<'a> NodeGraphLayer<'a> { } /// Node id of a protonode if it exists in the layer's primary flow - pub fn upstream_node_id_from_protonode(&self, protonode_identifier: &'static str) -> Option { + pub fn upstream_node_id_from_protonode(&self, protonode_identifier: ProtoNodeIdentifier) -> Option { self.horizontal_layer_flow() // Take until a different layer is reached .take_while(|&node_id| node_id == self.layer_node || !self.network_interface.is_layer(&node_id, &[])) - .find(move |node_id| { + .find(|node_id| { self.network_interface .implementation(node_id, &[]) - .is_some_and(move |implementation| *implementation == graph_craft::document::DocumentNodeImplementation::proto(protonode_identifier)) + .is_some_and(|implementation| *implementation == graph_craft::document::DocumentNodeImplementation::ProtoNode(protonode_identifier.clone())) }) } diff --git a/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs b/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs index fe97c2231..700f3c277 100644 --- a/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs +++ b/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs @@ -77,7 +77,7 @@ mod test_ellipse { layers .filter_map(|layer| { let node_graph_layer = NodeGraphLayer::new(layer, &document.network_interface); - let ellipse_node = node_graph_layer.upstream_node_id_from_protonode(ellipse::protonode_identifier())?; + let ellipse_node = node_graph_layer.upstream_node_id_from_protonode(ellipse::IDENTIFIER)?; Some(ResolvedEllipse { radius_x: instrumented.grab_protonode_input::(&vec![ellipse_node], &editor.runtime).unwrap(), radius_y: instrumented.grab_protonode_input::(&vec![ellipse_node], &editor.runtime).unwrap(), diff --git a/editor/src/messages/tool/tool_messages/artboard_tool.rs b/editor/src/messages/tool/tool_messages/artboard_tool.rs index d72e28df5..0362b7f14 100644 --- a/editor/src/messages/tool/tool_messages/artboard_tool.rs +++ b/editor/src/messages/tool/tool_messages/artboard_tool.rs @@ -567,7 +567,7 @@ mod test_artboard { Ok(instrumented) => instrumented, Err(e) => panic!("Failed to evaluate graph: {}", e), }; - instrumented.grab_all_input::(&editor.runtime).collect() + instrumented.grab_all_input::(&editor.runtime).collect() } #[tokio::test] diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index dbb87c07f..ba2f52d7b 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -413,6 +413,7 @@ mod test { use super::*; use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface; use crate::test_utils::test_prelude::{self, NodeGraphLayer}; + use graph_craft::ProtoNodeIdentifier; use graph_craft::document::NodeNetwork; use graphene_std::Context; use graphene_std::NodeInputDecleration; @@ -422,7 +423,7 @@ mod test { /// Stores all of the monitor nodes that have been attached to a graph #[derive(Default)] pub struct Instrumented { - protonodes_by_name: HashMap>>>, + protonodes_by_name: HashMap>>>, protonodes_by_path: HashMap, Vec>>, } @@ -449,7 +450,7 @@ mod test { } if let DocumentNodeImplementation::ProtoNode(identifier) = &mut node.implementation { path.push(*id); - self.protonodes_by_name.entry(identifier.name.to_string()).or_default().push(monitor_node_ids.clone()); + self.protonodes_by_name.entry(identifier.clone()).or_default().push(monitor_node_ids.clone()); self.protonodes_by_path.insert(path.clone(), monitor_node_ids); path.pop(); } @@ -457,7 +458,7 @@ mod test { for (input, monitor_id) in monitor_nodes { let monitor_node = DocumentNode { inputs: vec![input], - implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), + implementation: DocumentNodeImplementation::ProtoNode(graphene_std::memo::monitor::IDENTIFIER), manual_composition: Some(graph_craft::generic!(T)), skip_deduplication: true, ..Default::default() @@ -495,7 +496,7 @@ mod test { Input::Result: Send + Sync + Clone + 'static, { self.protonodes_by_name - .get(Input::identifier()) + .get(&Input::identifier()) .map_or([].as_slice(), |x| x.as_slice()) .iter() .filter_map(|inputs| inputs.get(Input::INDEX)) diff --git a/editor/src/node_graph_executor/runtime.rs b/editor/src/node_graph_executor/runtime.rs index a93f73546..227999143 100644 --- a/editor/src/node_graph_executor/runtime.rs +++ b/editor/src/node_graph_executor/runtime.rs @@ -1,12 +1,12 @@ use super::*; use crate::messages::frontend::utility_types::{ExportBounds, FileType}; use glam::{DAffine2, DVec2}; -use graph_craft::concrete; use graph_craft::document::value::TaggedValue; use graph_craft::document::{NodeId, NodeNetwork}; use graph_craft::graphene_compiler::Compiler; use graph_craft::proto::GraphErrors; use graph_craft::wasm_application_io::EditorPreferences; +use graph_craft::{ProtoNodeIdentifier, concrete}; use graphene_std::Context; use graphene_std::application_io::{NodeGraphUpdateMessage, NodeGraphUpdateSender, RenderConfig}; use graphene_std::instances::Instance; @@ -46,7 +46,7 @@ pub struct NodeRuntime { inspect_state: Option, /// Mapping of the fully-qualified node paths to their preprocessor substitutions. - substitutions: HashMap, + substitutions: HashMap, // TODO: Remove, it doesn't need to be persisted anymore /// The current renders of the thumbnails for layer nodes. @@ -435,7 +435,7 @@ impl InspectState { let monitor_node = DocumentNode { inputs: vec![NodeInput::node(inspect_node, 0)], // Connect to the primary output of the inspect node - implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), + implementation: DocumentNodeImplementation::ProtoNode(graphene_std::memo::monitor::IDENTIFIER), manual_composition: Some(graph_craft::generic!(T)), skip_deduplication: true, ..Default::default() diff --git a/frontend/src-tauri/src/main.rs b/frontend/src-tauri/src/main.rs index edc544dae..64c78a79b 100644 --- a/frontend/src-tauri/src/main.rs +++ b/frontend/src-tauri/src/main.rs @@ -3,10 +3,6 @@ use axum::routing::get; use axum::Router; use fern::colors::{Color, ColoredLevelConfig}; -use graphite_editor::application::Editor; -use graphite_editor::messages::prelude::*; -use graphite_editor::node_graph_executor::GraphRuntimeRequest; -use graphite_editor::node_graph_executor::NODE_RUNTIME; use graphite_editor::node_graph_executor::*; use std::sync::Mutex; diff --git a/node-graph/gcore/src/lib.rs b/node-graph/gcore/src/lib.rs index 973b2f4d2..1333ec743 100644 --- a/node-graph/gcore/src/lib.rs +++ b/node-graph/gcore/src/lib.rs @@ -12,7 +12,7 @@ pub mod debug; pub mod extract_xy; pub mod generic; pub mod gradient; -mod graphic_element; +pub mod graphic_element; pub mod instances; pub mod logic; pub mod math; @@ -35,7 +35,7 @@ pub use blending::*; pub use context::*; pub use ctor; pub use dyn_any::{StaticTypeSized, WasmNotSend, WasmNotSync}; -pub use graphic_element::*; +pub use graphic_element::{Artboard, ArtboardGroupTable, GraphicElement, GraphicGroupTable}; pub use memo::MemoHash; pub use num_traits; pub use raster::Color; @@ -161,7 +161,7 @@ where pub trait NodeInputDecleration { const INDEX: usize; - fn identifier() -> &'static str; + fn identifier() -> ProtoNodeIdentifier; type Result; } diff --git a/node-graph/gcore/src/memo.rs b/node-graph/gcore/src/memo.rs index 66464eef4..1a124d206 100644 --- a/node-graph/gcore/src/memo.rs +++ b/node-graph/gcore/src/memo.rs @@ -2,6 +2,7 @@ use crate::{Node, WasmNotSend}; use dyn_any::DynFuture; use std::future::Future; use std::hash::DefaultHasher; +use std::hash::{Hash, Hasher}; use std::ops::Deref; use std::sync::Arc; use std::sync::Mutex; @@ -49,6 +50,10 @@ impl MemoNode { } } +pub mod memo { + pub const IDENTIFIER: crate::ProtoNodeIdentifier = crate::ProtoNodeIdentifier::new("graphene_core::memo::MemoNode"); +} + /// Caches the output of a given Node and acts as a proxy. /// In contrast to the regular `MemoNode`. This node ignores all input. /// Using this node might result in the document not updating properly, @@ -98,6 +103,10 @@ impl ImpureMemoNode { } } +pub mod impure_memo { + pub const IDENTIFIER: crate::ProtoNodeIdentifier = crate::ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode"); +} + /// Stores both what a node was called with and what it returned. #[derive(Clone, Debug)] pub struct IORecord { @@ -142,7 +151,10 @@ impl MonitorNode { } } -use std::hash::{Hash, Hasher}; +pub mod monitor { + pub const IDENTIFIER: crate::ProtoNodeIdentifier = crate::ProtoNodeIdentifier::new("graphene_core::memo::MonitorNode"); +} + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct MemoHash { hash: u64, diff --git a/node-graph/gcore/src/registry.rs b/node-graph/gcore/src/registry.rs index 8dd53ba91..5d405df09 100644 --- a/node-graph/gcore/src/registry.rs +++ b/node-graph/gcore/src/registry.rs @@ -1,4 +1,4 @@ -use crate::{Node, NodeIO, NodeIOTypes, Type, WasmNotSend}; +use crate::{Node, NodeIO, NodeIOTypes, ProtoNodeIdentifier, Type, WasmNotSend}; use dyn_any::{DynAny, StaticType}; use std::borrow::Cow; use std::collections::HashMap; @@ -103,11 +103,11 @@ pub enum RegistryValueSource { Scope(&'static str), } -type NodeRegistry = LazyLock>>>; +type NodeRegistry = LazyLock>>>; pub static NODE_REGISTRY: NodeRegistry = LazyLock::new(|| Mutex::new(HashMap::new())); -pub static NODE_METADATA: LazyLock>> = LazyLock::new(|| Mutex::new(HashMap::new())); +pub static NODE_METADATA: LazyLock>> = LazyLock::new(|| Mutex::new(HashMap::new())); #[cfg(not(target_arch = "wasm32"))] pub type DynFuture<'n, T> = Pin + 'n + Send>>; diff --git a/node-graph/gcore/src/types.rs b/node-graph/gcore/src/types.rs index 156d9a85d..48ee2d804 100644 --- a/node-graph/gcore/src/types.rs +++ b/node-graph/gcore/src/types.rs @@ -1,6 +1,7 @@ use std::any::TypeId; pub use std::borrow::Cow; +use std::ops::Deref; #[macro_export] macro_rules! concrete { @@ -128,12 +129,37 @@ impl std::fmt::Debug for NodeIOTypes { pub struct ProtoNodeIdentifier { pub name: Cow<'static, str>, } + impl From for ProtoNodeIdentifier { fn from(value: String) -> Self { Self { name: Cow::Owned(value) } } } +impl From<&'static str> for ProtoNodeIdentifier { + fn from(s: &'static str) -> Self { + ProtoNodeIdentifier { name: Cow::Borrowed(s) } + } +} + +impl ProtoNodeIdentifier { + pub const fn new(name: &'static str) -> Self { + ProtoNodeIdentifier { name: Cow::Borrowed(name) } + } + + pub const fn with_owned_string(name: String) -> Self { + ProtoNodeIdentifier { name: Cow::Owned(name) } + } +} + +impl Deref for ProtoNodeIdentifier { + type Target = str; + + fn deref(&self) -> &Self::Target { + self.name.as_ref() + } +} + fn migrate_type_descriptor_names<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result, D::Error> { use serde::Deserialize; @@ -306,6 +332,13 @@ impl Type { Self::Future(output) => output.replace_nested(f), } } + + pub fn to_cow_string(&self) -> Cow<'static, str> { + match self { + Type::Generic(name) => name.clone(), + _ => Cow::Owned(self.to_string()), + } + } } fn format_type(ty: &str) -> String { @@ -343,19 +376,3 @@ impl std::fmt::Display for Type { write!(f, "{}", result) } } - -impl From<&'static str> for ProtoNodeIdentifier { - fn from(s: &'static str) -> Self { - ProtoNodeIdentifier { name: Cow::Borrowed(s) } - } -} - -impl ProtoNodeIdentifier { - pub const fn new(name: &'static str) -> Self { - ProtoNodeIdentifier { name: Cow::Borrowed(name) } - } - - pub const fn with_owned_string(name: String) -> Self { - ProtoNodeIdentifier { name: Cow::Owned(name) } - } -} diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index 983005214..08679ce41 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -486,10 +486,6 @@ impl DocumentNodeImplementation { } } - pub const fn proto(name: &'static str) -> Self { - Self::ProtoNode(ProtoNodeIdentifier::new(name)) - } - pub fn output_count(&self) -> usize { match self { DocumentNodeImplementation::Network(network) => network.exports.len(), @@ -1268,7 +1264,6 @@ impl<'a> Iterator for RecursiveNodeIter<'a> { mod test { use super::*; use crate::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, ProtoNodeInput}; - use graphene_core::ProtoNodeIdentifier; use std::sync::atomic::AtomicU64; fn gen_node_id() -> NodeId { @@ -1540,7 +1535,7 @@ mod test { NodeId(1), DocumentNode { inputs: vec![NodeInput::network(concrete!(u32), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode")), + implementation: DocumentNodeImplementation::ProtoNode(graphene_core::ops::identity::IDENTIFIER), ..Default::default() }, ), @@ -1548,7 +1543,7 @@ mod test { NodeId(2), DocumentNode { inputs: vec![NodeInput::network(concrete!(u32), 1)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode")), + implementation: DocumentNodeImplementation::ProtoNode(graphene_core::ops::identity::IDENTIFIER), ..Default::default() }, ), @@ -1575,7 +1570,7 @@ mod test { NodeId(2), DocumentNode { inputs: vec![result_node_input], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode")), + implementation: DocumentNodeImplementation::ProtoNode(graphene_core::ops::identity::IDENTIFIER), ..Default::default() }, ), diff --git a/node-graph/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs index 00402776f..c8c896290 100644 --- a/node-graph/graph-craft/src/document/value.rs +++ b/node-graph/graph-craft/src/document/value.rs @@ -190,9 +190,9 @@ tagged_value! { VectorData(graphene_core::vector::VectorDataTable), #[cfg_attr(target_arch = "wasm32", serde(alias = "ImageFrame", deserialize_with = "graphene_core::raster::image::migrate_image_frame"))] // TODO: Eventually remove this migration document upgrade code RasterData(graphene_core::raster_types::RasterDataTable), - #[cfg_attr(target_arch = "wasm32", serde(deserialize_with = "graphene_core::migrate_graphic_group"))] // TODO: Eventually remove this migration document upgrade code + #[cfg_attr(target_arch = "wasm32", serde(deserialize_with = "graphene_core::graphic_element::migrate_graphic_group"))] // TODO: Eventually remove this migration document upgrade code GraphicGroup(graphene_core::GraphicGroupTable), - #[cfg_attr(target_arch = "wasm32", serde(deserialize_with = "graphene_core::migrate_artboard_group"))] // TODO: Eventually remove this migration document upgrade code + #[cfg_attr(target_arch = "wasm32", serde(deserialize_with = "graphene_core::graphic_element::migrate_artboard_group"))] // TODO: Eventually remove this migration document upgrade code ArtboardGroup(graphene_core::ArtboardGroupTable), // ============ // STRUCT TYPES diff --git a/node-graph/interpreted-executor/src/lib.rs b/node-graph/interpreted-executor/src/lib.rs index 097653c2a..5c05ef62b 100644 --- a/node-graph/interpreted-executor/src/lib.rs +++ b/node-graph/interpreted-executor/src/lib.rs @@ -20,7 +20,7 @@ mod tests { NodeId(0), DocumentNode { inputs: vec![NodeInput::network(concrete!(u32), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode")), + implementation: DocumentNodeImplementation::ProtoNode(ops::identity::IDENTIFIER), ..Default::default() }, ), diff --git a/node-graph/interpreted-executor/src/util.rs b/node-graph/interpreted-executor/src/util.rs index ab4c744e3..e0f52dae2 100644 --- a/node-graph/interpreted-executor/src/util.rs +++ b/node-graph/interpreted-executor/src/util.rs @@ -39,7 +39,7 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork, editor_api: Arc syn::Result quote!(stringify!(#path).replace(' ', "")), - None => quote!(std::module_path!().rsplit_once("::").unwrap().0), + + let identifier = format_ident!("{}_proto_ident", fn_name); + let identifier_path = match parsed.attributes.path.as_ref() { + Some(path) => { + let path = path.to_token_stream().to_string().replace(' ', ""); + quote!(#path) + } + None => quote!(std::module_path!()), }; - let identifier = quote!(format!("{}::{}", #path, stringify!(#struct_name))); let register_node_impl = generate_register_node_impl(parsed, &field_names, &struct_name, &identifier)?; let import_name = format_ident!("_IMPORT_STUB_{}", mod_name.to_string().to_case(Case::UpperSnake)); @@ -354,6 +358,11 @@ pub(crate) fn generate_node_code(parsed: &ParsedNodeFn) -> syn::Result #graphene_core::ProtoNodeIdentifier { + #graphene_core::ProtoNodeIdentifier::new(std::concat!(#identifier_path, "::", std::stringify!(#struct_name))) + } + #[doc(inline)] pub use #mod_name::#struct_name; @@ -418,67 +427,63 @@ pub(crate) fn generate_node_code(parsed: &ParsedNodeFn) -> syn::Result TokenStream2 { - if parsed.attributes.skip_impl { - return quote! {}; - } +fn generate_node_input_references(parsed: &ParsedNodeFn, fn_generics: &[crate::GenericParam], field_idents: &[&PatIdent], graphene_core: &TokenStream2, identifier: &Ident) -> TokenStream2 { let inputs_module_name = format_ident!("{}", parsed.struct_name.to_string().to_case(Case::Snake)); - let (mut modified, mut generic_collector) = FilterUsedGenerics::new(fn_generics); - let mut generated_input_accessor = Vec::new(); - for (input_index, (parsed_input, input_ident)) in parsed.fields.iter().zip(field_idents).enumerate() { - let mut ty = match parsed_input { - ParsedField::Regular { ty, .. } => ty, - ParsedField::Node { output_type, .. } => output_type, + if !parsed.attributes.skip_impl { + let (mut modified, mut generic_collector) = FilterUsedGenerics::new(fn_generics); + + for (input_index, (parsed_input, input_ident)) in parsed.fields.iter().zip(field_idents).enumerate() { + let mut ty = match parsed_input { + ParsedField::Regular { ty, .. } => ty, + ParsedField::Node { output_type, .. } => output_type, + } + .clone(); + + // We only want the necessary generics. + let used = generic_collector.filter_unnecessary_generics(&mut modified, &mut ty); + // TODO: figure out a better name that doesn't conflict with so many types + let struct_name = format_ident!("{}Input", input_ident.ident.to_string().to_case(Case::Pascal)); + let (fn_generic_params, phantom_data_declerations) = generate_phantom_data(used.iter()); + + // Only create structs with phantom data where necessary. + generated_input_accessor.push(if phantom_data_declerations.is_empty() { + quote! { + pub struct #struct_name; + } + } else { + quote! { + pub struct #struct_name <#(#used),*>{ + #(#phantom_data_declerations,)* + } + } + }); + generated_input_accessor.push(quote! { + impl <#(#used),*> #graphene_core::NodeInputDecleration for #struct_name <#(#fn_generic_params),*> { + const INDEX: usize = #input_index; + fn identifier() -> #graphene_core::ProtoNodeIdentifier { + #inputs_module_name::IDENTIFIER.clone() + } + type Result = #ty; + } + }) } - .clone(); - - // We only want the necessary generics. - let used = generic_collector.filter_unnecessary_generics(&mut modified, &mut ty); - // TODO: figure out a better name that doesn't conflict with so many types - let struct_name = format_ident!("{}Input", input_ident.ident.to_string().to_case(Case::Pascal)); - let (fn_generic_params, phantom_data_declerations) = generate_phantom_data(used.iter()); - - // Only create structs with phantom data where necessary. - generated_input_accessor.push(if phantom_data_declerations.is_empty() { - quote! { - pub struct #struct_name; - } - } else { - quote! { - pub struct #struct_name <#(#used),*>{ - #(#phantom_data_declerations,)* - } - } - }); - generated_input_accessor.push(quote! { - impl <#(#used),*> #graphene_core::NodeInputDecleration for #struct_name <#(#fn_generic_params),*> { - const INDEX: usize = #input_index; - fn identifier() -> &'static str { - protonode_identifier() - } - type Result = #ty; - } - }) } quote! { pub mod #inputs_module_name { use super::*; - pub fn protonode_identifier() -> &'static str { - // Storing the string in a once lock should reduce allocations (since we call this in a loop)? - static NODE_NAME: std::sync::OnceLock = std::sync::OnceLock::new(); - NODE_NAME.get_or_init(|| #identifier ) - } + /// The `ProtoNodeIdentifier` of this node without any generics attached to it + pub const IDENTIFIER: #graphene_core::ProtoNodeIdentifier = #identifier(); #(#generated_input_accessor)* } } @@ -511,7 +516,7 @@ fn generate_phantom_data<'a>(fn_generics: impl Iterator Result { +fn generate_register_node_impl(parsed: &ParsedNodeFn, field_names: &[&Ident], struct_name: &Ident, identifier: &Ident) -> Result { if parsed.attributes.skip_impl { return Ok(quote!()); } @@ -604,7 +609,7 @@ fn generate_register_node_impl(parsed: &ParsedNodeFn, field_names: &[&Ident], st fn register_node() { let mut registry = NODE_REGISTRY.lock().unwrap(); registry.insert( - #identifier, + #identifier(), vec![ #(#constructors,)* ] diff --git a/node-graph/preprocessor/src/lib.rs b/node-graph/preprocessor/src/lib.rs index 50c265f92..e0b4a0168 100644 --- a/node-graph/preprocessor/src/lib.rs +++ b/node-graph/preprocessor/src/lib.rs @@ -6,7 +6,7 @@ use graphene_std::registry::*; use graphene_std::*; use std::collections::{HashMap, HashSet}; -pub fn expand_network(network: &mut NodeNetwork, substitutions: &HashMap) { +pub fn expand_network(network: &mut NodeNetwork, substitutions: &HashMap) { if network.generated { return; } @@ -15,7 +15,7 @@ pub fn expand_network(network: &mut NodeNetwork, substitutions: &HashMap expand_network(node_network, substitutions), DocumentNodeImplementation::ProtoNode(proto_node_identifier) => { - if let Some(new_node) = substitutions.get(proto_node_identifier.name.as_ref()) { + if let Some(new_node) = substitutions.get(proto_node_identifier) { node.implementation = new_node.implementation.clone(); } } @@ -24,7 +24,7 @@ pub fn expand_network(network: &mut NodeNetwork, substitutions: &HashMap HashMap { +pub fn generate_node_substitutions() -> HashMap { let mut custom = HashMap::new(); let node_registry = graphene_core::registry::NODE_REGISTRY.lock().unwrap(); for (id, metadata) in graphene_core::registry::NODE_METADATA.lock().unwrap().iter() { @@ -49,7 +49,7 @@ pub fn generate_node_substitutions() -> HashMap { let input_count = inputs.len(); let network_inputs = (0..input_count).map(|i| NodeInput::node(NodeId(i as u64), 0)).collect(); - let identity_node = ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode"); + let identity_node = ops::identity::IDENTIFIER; let into_node_registry = &interpreted_executor::node_registry::NODE_REGISTRY;