Incremental compilation and stable node IDs (#977)

* Generate stable node ids

* checkpoint

* Implement borrow tree

* Add eval function on borrow tree

* Refactor Node trait to fix lifetime issues

* Compiler infinite loop

* Impl compose pair

* Transition to double lifetime on trait

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

* Start adapting node_macro

* Migrate more nodes to new macro

* Fix raster tests

* Port vector nodes

* Make Node trait object safe

* Fix FlatMapResultNode

* Translate most of gstd

* Fix DowncastBothNode

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

* Start working on type erased nodes

* Try getting DowncastBothNode to work

* Introduce Upcasting node + work on BorrowTree

* Make enough 'static to get the code to compile

* Transition DynamicExecutor to use borrow tree

* Make Compose Node use HRTB's

* Fix MapResultNode

* Disable blur test

* Add workaround for Composing type erased nodes

* Convert more nodes in the node_registry

* Convert more of the node_registry

* Add update tree fn and hook up to frontend

* Fix blur node

* Implement CacheNode

* Make frontend use graph compiler

* Fix document_node_types type declaration for most nodes

* Remove unused imports

* Move comment down

* Reuse nodes via borrow tree

* Deprecate trait based value in favor of TaggedValue

* Remove unsafe code in buffer creation

* Fix blur node

* Fix stable node id generation

* Fix types for Image adjustment document nodes

* Fix Imaginate Node

* Remove unused imports

* Remove log

* Fix off by one error

* Remove macro generated imaginate node entry

* Create parameterized add node

* Fix test case

* Remove link from layer_panel.rs

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

1
Cargo.lock generated
View file

@ -2676,6 +2676,7 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
name = "node-macro"
version = "0.0.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View file

@ -14,11 +14,11 @@ pub struct Color {
}
impl Color {
pub const BLACK: Color = Color::from_unsafe(0., 0., 0.);
pub const WHITE: Color = Color::from_unsafe(1., 1., 1.);
pub const RED: Color = Color::from_unsafe(1., 0., 0.);
pub const GREEN: Color = Color::from_unsafe(0., 1., 0.);
pub const BLUE: Color = Color::from_unsafe(0., 0., 1.);
pub const BLACK: Color = Color::from_uchecked(0., 0., 0.);
pub const WHITE: Color = Color::from_uchecked(1., 1., 1.);
pub const RED: Color = Color::from_uchecked(1., 0., 0.);
pub const GREEN: Color = Color::from_uchecked(0., 1., 0.);
pub const BLUE: Color = Color::from_uchecked(0., 0., 1.);
pub const TRANSPARENT: Color = Self {
red: 0.,
green: 0.,
@ -46,7 +46,7 @@ impl Color {
}
/// Return an opaque `Color` from given `f32` RGB channels.
pub const fn from_unsafe(red: f32, green: f32, blue: f32) -> Color {
pub const fn from_uchecked(red: f32, green: f32, blue: f32) -> Color {
Color { red, green, blue, alpha: 1. }
}

View file

@ -68,7 +68,7 @@ pub const ASYMPTOTIC_EFFECT: f64 = 0.5;
pub const SCALE_EFFECT: f64 = 0.5;
// Colors
pub const COLOR_ACCENT: Color = Color::from_unsafe(0x00 as f32 / 255., 0xA8 as f32 / 255., 0xFF as f32 / 255.);
pub const COLOR_ACCENT: Color = Color::from_uchecked(0x00 as f32 / 255., 0xA8 as f32 / 255., 0xFF as f32 / 255.);
// Fonts
pub const DEFAULT_FONT_FAMILY: &str = "Merriweather";

View file

@ -284,7 +284,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
}
ClearLayerTree => {
// Send an empty layer tree
let data_buffer: RawBuffer = Self::default().serialize_root().into();
let data_buffer: RawBuffer = Self::default().serialize_root().as_slice().into();
responses.push_back(FrontendMessage::UpdateDocumentLayerTreeStructure { data_buffer }.into());
// Clear the options bar
@ -360,7 +360,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
DocumentHistoryBackward => self.undo(responses).unwrap_or_else(|e| warn!("{}", e)),
DocumentHistoryForward => self.redo(responses).unwrap_or_else(|e| warn!("{}", e)),
DocumentStructureChanged => {
let data_buffer: RawBuffer = self.serialize_root().into();
let data_buffer: RawBuffer = self.serialize_root().as_slice().into();
responses.push_back(FrontendMessage::UpdateDocumentLayerTreeStructure { data_buffer }.into())
}
DuplicateSelectedLayers => {

View file

@ -1,11 +1,11 @@
use super::{node_properties, FrontendGraphDataType, FrontendNodeType};
use crate::messages::layout::utility_types::layout_widget::LayoutGroup;
use graph_craft::concrete;
use graph_craft::document::value::*;
use graph_craft::document::*;
use graph_craft::document::{value::*, DocumentNodeImplementation};
use graph_craft::imaginate_input::ImaginateSamplingMethod;
use graph_craft::proto::{NodeIdentifier, Type};
use graph_craft::{concrete, generic};
use graphene_core::raster::Image;
use std::collections::VecDeque;
@ -91,8 +91,8 @@ fn document_node_types() -> Vec<DocumentNodeType> {
1,
DocumentNode {
name: "BlurNode".to_string(),
inputs: vec![NodeInput::Node(0), NodeInput::Network, NodeInput::Network],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::raster::BlurNode", &[])),
inputs: vec![NodeInput::Node(0), NodeInput::Network, NodeInput::Network, NodeInput::Node(0)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::raster::BlurNode", &[concrete!("Image")])),
metadata: Default::default(),
},
),
@ -118,7 +118,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "Identity",
category: "General",
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[generic!("T")]),
inputs: &[DocumentInputType {
name: "In",
data_type: FrontendGraphDataType::General,
@ -130,7 +130,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "Image",
category: "Ignore",
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[generic!("T")]),
inputs: &[DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), false)],
outputs: &[FrontendGraphDataType::Raster],
properties: |_document_node, _node_id, _context| node_properties::string_properties("A bitmap image embedded in this node"),
@ -138,7 +138,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "Input",
category: "Ignore",
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[generic!("T")]),
inputs: &[DocumentInputType {
name: "In",
data_type: FrontendGraphDataType::Raster,
@ -150,7 +150,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "Output",
category: "Ignore",
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[generic!("T")]),
inputs: &[DocumentInputType {
name: "In",
data_type: FrontendGraphDataType::Raster,
@ -162,7 +162,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "Grayscale",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_std::raster::GrayscaleNode", &[]),
identifier: NodeImplementation::proto("graphene_std::raster::GrayscaleNode", &[concrete!("Image")]),
inputs: &[DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true)],
outputs: &[FrontendGraphDataType::Raster],
properties: node_properties::no_properties,
@ -171,7 +171,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "GpuImage",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_std::executor::MapGpuSingleImageNode", &[concrete!("&TypeErasedNode")]),
identifier: NodeImplementation::proto("graphene_std::executor::MapGpuSingleImageNode", &[concrete!("Image")]),
inputs: &[
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
DocumentInputType {
@ -187,7 +187,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "QuantizeImage",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_std::quantization::GenerateQuantizationNode", &[concrete!("&TypeErasedNode")]),
identifier: NodeImplementation::proto("graphene_std::quantization::GenerateQuantizationNode", &[concrete!("Image")]),
inputs: &[
DocumentInputType {
name: "Image",
@ -219,7 +219,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "Invert RGB",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_std::raster::InvertRGBNode", &[]),
identifier: NodeImplementation::proto("graphene_std::raster::InvertRGBNode", &[concrete!("Image")]),
inputs: &[DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true)],
outputs: &[FrontendGraphDataType::Raster],
properties: node_properties::no_properties,
@ -227,7 +227,10 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "Hue/Saturation",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_std::raster::HueSaturationNode", &[concrete!("&TypeErasedNode")]),
identifier: NodeImplementation::proto(
"graphene_std::raster::HueSaturationNode<_, _, _>",
&[concrete!("Image"), concrete!("f64"), concrete!("f64"), concrete!("f64")],
),
inputs: &[
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
DocumentInputType::new("Hue Shift", TaggedValue::F64(0.), false),
@ -240,7 +243,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "Brightness/Contrast",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_std::raster::BrightnessContrastNode", &[concrete!("&TypeErasedNode")]),
identifier: NodeImplementation::proto("graphene_std::raster::BrightnessContrastNode<_, _>", &[concrete!("Image"), concrete!("f64"), concrete!("f64")]),
inputs: &[
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
DocumentInputType::new("Brightness", TaggedValue::F64(0.), false),
@ -252,7 +255,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "Gamma",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_std::raster::GammaNode", &[concrete!("&TypeErasedNode")]),
identifier: NodeImplementation::proto("graphene_std::raster::GammaNode<_>", &[concrete!("Image"), concrete!("f64")]),
inputs: &[
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
DocumentInputType::new("Gamma", TaggedValue::F64(1.), false),
@ -263,7 +266,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "Opacity",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_std::raster::OpacityNode", &[concrete!("&TypeErasedNode")]),
identifier: NodeImplementation::proto("graphene_std::raster::OpacityNode<_>", &[concrete!("Image"), concrete!("f64")]),
inputs: &[
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
DocumentInputType::new("Factor", TaggedValue::F64(1.), false),
@ -274,7 +277,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "Posterize",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_std::raster::PosterizeNode", &[concrete!("&TypeErasedNode")]),
identifier: NodeImplementation::proto("graphene_std::raster::PosterizeNode<_>", &[concrete!("Image"), concrete!("f64")]),
inputs: &[
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
DocumentInputType::new("Value", TaggedValue::F64(5.), false),
@ -285,7 +288,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "Exposure",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_std::raster::ExposureNode", &[concrete!("&TypeErasedNode")]),
identifier: NodeImplementation::proto("graphene_std::raster::ExposureNode<_>", &[concrete!("Image"), concrete!("f64")]),
inputs: &[
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
DocumentInputType::new("Value", TaggedValue::F64(0.), false),
@ -297,7 +300,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "Add",
category: "Math",
identifier: NodeImplementation::proto("graphene_core::ops::AddNode", &[concrete!("&TypeErasedNode")]),
identifier: NodeImplementation::proto("graphene_core::ops::AddParameterNode<_>", &[concrete!("f64"), concrete!("f64")]),
inputs: &[
DocumentInputType::new("Input", TaggedValue::F64(0.), true),
DocumentInputType::new("Addend", TaggedValue::F64(0.), true),
@ -324,7 +327,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
DocumentNodeType {
name: "Path Generator",
category: "Vector",
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[generic!("T")]),
inputs: &[DocumentInputType {
name: "Path Data",
data_type: FrontendGraphDataType::Subpath,
@ -363,7 +366,7 @@ static STATIC_NODES: &[DocumentNodeType] = &[
pub const IMAGINATE_NODE: DocumentNodeType = DocumentNodeType {
name: "Imaginate",
category: "Image Synthesis",
identifier: NodeImplementation::proto("graphene_std::raster::ImaginateNode", &[concrete!("&TypeErasedNode")]),
identifier: NodeImplementation::proto("graphene_std::raster::ImaginateNode<_>", &[concrete!("Image"), concrete!("Option<std::sync::Arc<Image>>")]),
inputs: &[
DocumentInputType::new("Input Image", TaggedValue::Image(Image::empty()), true),
DocumentInputType::new("Seed", TaggedValue::F64(0.), false),

View file

@ -373,7 +373,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
panic!("Invalid status input")
};
let NodeInput::Value {tagged_value: TaggedValue::RcImage( cached_data),..} = cached_value else {
panic!("Invalid cached image input")
panic!("Invalid cached image input, recieved {:?}, index: {}", cached_value, cached_index)
};
let &NodeInput::Value {tagged_value: TaggedValue::F64( percent_complete),..} = complete_value else {
panic!("Invalid percent complete input")

View file

@ -9,15 +9,9 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)]
pub struct RawBuffer(Vec<u8>);
impl From<Vec<u64>> for RawBuffer {
fn from(iter: Vec<u64>) -> Self {
// https://github.com/rust-lang/rust-clippy/issues/4484
let v_from_raw: Vec<u8> = unsafe {
// prepare for an auto-forget of the initial vec:
let v_orig: &mut Vec<_> = &mut *std::mem::ManuallyDrop::new(iter);
Vec::from_raw_parts(v_orig.as_mut_ptr() as *mut u8, v_orig.len() * 8, v_orig.capacity() * 8)
// v_orig is never used again, so no aliasing issue
};
impl From<&[u64]> for RawBuffer {
fn from(iter: &[u64]) -> Self {
let v_from_raw: Vec<u8> = iter.iter().flat_map(|x| x.to_ne_bytes()).collect();
Self(v_from_raw)
}
}

View file

@ -20,9 +20,11 @@ use document_legacy::{LayerId, Operation as DocumentOperation};
use graph_craft::document::value::TaggedValue;
use graph_craft::document::NodeId;
use graph_craft::document::{NodeInput, NodeNetwork};
use graph_craft::executor::Compiler;
use graphene_core::raster::Image;
use glam::DVec2;
use interpreted_executor::executor::DynamicExecutor;
use std::borrow::Cow;
#[derive(Debug, Clone, Default)]
@ -30,6 +32,7 @@ pub struct PortfolioMessageHandler {
menu_bar_message_handler: MenuBarMessageHandler,
documents: HashMap<u64, DocumentMessageHandler>,
document_ids: Vec<u64>,
executor: interpreted_executor::executor::DynamicExecutor,
active_document_id: Option<u64>,
copy_buffer: [Vec<CopyBufferEntry>; INTERNAL_CLIPBOARD_COUNT as usize],
pub persistent_data: PersistentData,
@ -680,39 +683,31 @@ impl PortfolioMessageHandler {
}
/// Execute the network by flattening it and creating a borrow stack. Casts the output to the generic `T`.
fn execute_network<T: dyn_any::StaticType>(mut network: NodeNetwork, image: Image) -> Result<T, String> {
for node_id in network.nodes.keys().copied().collect::<Vec<_>>() {
network.flatten(node_id);
}
let mut proto_network = network.into_proto_network();
proto_network.reorder_ids();
fn execute_network<T: dyn_any::StaticType>(executor: &mut DynamicExecutor, network: NodeNetwork, image: Image) -> Result<T, String> {
let c = Compiler {};
let proto_network = c.compile(network, true);
assert_ne!(proto_network.nodes.len(), 0, "No protonodes exist?");
let stack = borrow_stack::FixedSizeStack::new(proto_network.nodes.len());
for (_id, node) in proto_network.nodes {
interpreted_executor::node_registry::push_node(node, &stack);
}
executor.update(proto_network);
use borrow_stack::BorrowStack;
use dyn_any::IntoDynAny;
use graphene_core::Node;
use graph_craft::executor::Executor;
let boxed = unsafe { stack.get().last().unwrap().eval(image.into_dyn()) };
let boxed = executor.execute(image.into_dyn()).map_err(|e| e.to_string())?;
dyn_any::downcast::<T>(boxed).map(|v| *v)
}
/// Computes an input for a node in the graph
fn compute_input<T: dyn_any::StaticType>(old_network: &NodeNetwork, node_path: &[NodeId], mut input_index: usize, image: Cow<Image>) -> Result<T, String> {
fn compute_input<T: dyn_any::StaticType>(executor: &mut DynamicExecutor, old_network: &NodeNetwork, node_path: &[NodeId], mut input_index: usize, image: Cow<Image>) -> Result<T, String> {
let mut network = old_network.clone();
// Adjust the output of the graph so we find the relevant output
'outer: for end in (0..node_path.len()).rev() {
let mut inner_network = &mut network;
for node_id in node_path.iter().take(end) {
inner_network.output = *node_id;
for &node_id in &node_path[..end] {
inner_network.output = node_id;
let Some(new_inner) = inner_network.nodes.get_mut(node_id).and_then(|node| node.implementation.get_network_mut()) else {
let Some(new_inner) = inner_network.nodes.get_mut(&node_id).and_then(|node| node.implementation.get_network_mut()) else {
return Err("Failed to find network".to_string());
};
inner_network = new_inner;
@ -730,7 +725,7 @@ impl PortfolioMessageHandler {
.0;
}
// If the input is just a value, return that value
NodeInput::Value { tagged_value, .. } => return dyn_any::downcast::<T>(tagged_value.clone().to_value().up_box()).map(|v| *v),
NodeInput::Value { tagged_value, .. } => return dyn_any::downcast::<T>(tagged_value.clone().to_any()).map(|v| *v),
// If the input is from a node, set the node to be the output (so that is what is evaluated)
NodeInput::Node(n) => {
inner_network.output = *n;
@ -739,7 +734,7 @@ impl PortfolioMessageHandler {
}
}
Self::execute_network(network, image.into_owned())
Self::execute_network(executor, network, image.into_owned())
}
/// Encodes an image into a format using the image crate
@ -793,7 +788,7 @@ impl PortfolioMessageHandler {
let get = |name: &str| IMAGINATE_NODE.inputs.iter().position(|input| input.name == name).unwrap_or_else(|| panic!("Input {name} not found"));
let resolution: Option<glam::DVec2> = Self::compute_input(&network, &imaginate_node, get("Resolution"), Cow::Borrowed(&image))?;
let resolution: Option<glam::DVec2> = Self::compute_input(&mut self.executor, &network, &imaginate_node, get("Resolution"), Cow::Borrowed(&image))?;
let resolution = resolution.unwrap_or_else(|| {
let transform = document.document_legacy.root.transform.inverse() * document.document_legacy.multiply_transforms(&layer_path).unwrap();
let (x, y) = pick_safe_imaginate_resolution((transform.transform_vector2(DVec2::new(1., 0.)).length(), transform.transform_vector2(DVec2::new(0., 1.)).length()));
@ -802,23 +797,23 @@ impl PortfolioMessageHandler {
let transform = document.document_legacy.root.transform.inverse() * document.document_legacy.multiply_transforms(&layer_path).unwrap();
let parameters = ImaginateGenerationParameters {
seed: Self::compute_input::<f64>(&network, &imaginate_node, get("Seed"), Cow::Borrowed(&image))? as u64,
seed: Self::compute_input::<f64>(&mut self.executor, &network, &imaginate_node, get("Seed"), Cow::Borrowed(&image))? as u64,
resolution: resolution.as_uvec2().into(),
samples: Self::compute_input::<f64>(&network, &imaginate_node, get("Samples"), Cow::Borrowed(&image))? as u32,
sampling_method: Self::compute_input::<ImaginateSamplingMethod>(&network, &imaginate_node, get("Sampling Method"), Cow::Borrowed(&image))?
samples: Self::compute_input::<f64>(&mut self.executor, &network, &imaginate_node, get("Samples"), Cow::Borrowed(&image))? as u32,
sampling_method: Self::compute_input::<ImaginateSamplingMethod>(&mut self.executor, &network, &imaginate_node, get("Sampling Method"), Cow::Borrowed(&image))?
.api_value()
.to_string(),
text_guidance: Self::compute_input(&network, &imaginate_node, get("Prompt Guidance"), Cow::Borrowed(&image))?,
text_prompt: Self::compute_input(&network, &imaginate_node, get("Prompt"), Cow::Borrowed(&image))?,
negative_prompt: Self::compute_input(&network, &imaginate_node, get("Negative Prompt"), Cow::Borrowed(&image))?,
image_creativity: Some(Self::compute_input::<f64>(&network, &imaginate_node, get("Image Creativity"), Cow::Borrowed(&image))? / 100.),
restore_faces: Self::compute_input(&network, &imaginate_node, get("Improve Faces"), Cow::Borrowed(&image))?,
tiling: Self::compute_input(&network, &imaginate_node, get("Tiling"), Cow::Borrowed(&image))?,
text_guidance: Self::compute_input(&mut self.executor, &network, &imaginate_node, get("Prompt Guidance"), Cow::Borrowed(&image))?,
text_prompt: Self::compute_input(&mut self.executor, &network, &imaginate_node, get("Prompt"), Cow::Borrowed(&image))?,
negative_prompt: Self::compute_input(&mut self.executor, &network, &imaginate_node, get("Negative Prompt"), Cow::Borrowed(&image))?,
image_creativity: Some(Self::compute_input::<f64>(&mut self.executor, &network, &imaginate_node, get("Image Creativity"), Cow::Borrowed(&image))? / 100.),
restore_faces: Self::compute_input(&mut self.executor, &network, &imaginate_node, get("Improve Faces"), Cow::Borrowed(&image))?,
tiling: Self::compute_input(&mut self.executor, &network, &imaginate_node, get("Tiling"), Cow::Borrowed(&image))?,
};
let use_base_image = Self::compute_input::<bool>(&network, &imaginate_node, get("Adapt Input Image"), Cow::Borrowed(&image))?;
let use_base_image = Self::compute_input::<bool>(&mut self.executor, &network, &imaginate_node, get("Adapt Input Image"), Cow::Borrowed(&image))?;
let base_image = if use_base_image {
let image: Image = Self::compute_input(&network, &imaginate_node, get("Input Image"), Cow::Borrowed(&image))?;
let image: Image = Self::compute_input(&mut self.executor, &network, &imaginate_node, get("Input Image"), Cow::Borrowed(&image))?;
// Only use if has size
if image.width > 0 && image.height > 0 {
let (image_data, size) = Self::encode_img(image, Some(resolution), image::ImageOutputFormat::Png)?;
@ -834,7 +829,7 @@ impl PortfolioMessageHandler {
let mask_image =
if base_image.is_some() {
let mask_path: Option<Vec<LayerId>> = Self::compute_input(&network, &imaginate_node, get("Masking Layer"), Cow::Borrowed(&image))?;
let mask_path: Option<Vec<LayerId>> = Self::compute_input(&mut self.executor, &network, &imaginate_node, get("Masking Layer"), Cow::Borrowed(&image))?;
// Calculate the size of the node graph frame
let size = DVec2::new(transform.transform_vector2(DVec2::new(1., 0.)).length(), transform.transform_vector2(DVec2::new(0., 1.)).length());
@ -864,13 +859,13 @@ impl PortfolioMessageHandler {
parameters: Box::new(parameters),
base_image: base_image.map(Box::new),
mask_image: mask_image.map(Box::new),
mask_paint_mode: if Self::compute_input::<bool>(&network, &imaginate_node, get("Inpaint"), Cow::Borrowed(&image))? {
mask_paint_mode: if Self::compute_input::<bool>(&mut self.executor, &network, &imaginate_node, get("Inpaint"), Cow::Borrowed(&image))? {
ImaginateMaskPaintMode::Inpaint
} else {
ImaginateMaskPaintMode::Outpaint
},
mask_blur_px: Self::compute_input::<f64>(&network, &imaginate_node, get("Mask Blur"), Cow::Borrowed(&image))? as u32,
imaginate_mask_starting_fill: Self::compute_input(&network, &imaginate_node, get("Mask Starting Fill"), Cow::Borrowed(&image))?,
mask_blur_px: Self::compute_input::<f64>(&mut self.executor, &network, &imaginate_node, get("Mask Blur"), Cow::Borrowed(&image))? as u32,
imaginate_mask_starting_fill: Self::compute_input(&mut self.executor, &network, &imaginate_node, get("Mask Starting Fill"), Cow::Borrowed(&image))?,
hostname: preferences.imaginate_server_hostname.clone(),
refresh_frequency: preferences.imaginate_refresh_frequency,
document_id,
@ -880,7 +875,7 @@ impl PortfolioMessageHandler {
.into(),
);
} else {
let mut image: Image = Self::execute_network(network, image)?;
let mut image: Image = Self::execute_network(&mut self.executor, network, image)?;
// If no image was generated, use the input image
if image.width == 0 || image.height == 0 {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -68,7 +68,7 @@ impl DocumentNode {
let (input, mut args) = match first {
NodeInput::Value { tagged_value, .. } => {
assert_eq!(self.inputs.len(), 0);
(ProtoNodeInput::None, ConstructionArgs::Value(tagged_value.to_value()))
(ProtoNodeInput::None, ConstructionArgs::Value(tagged_value))
}
NodeInput::Node(id) => (ProtoNodeInput::Node(id), ConstructionArgs::Nodes(vec![])),
NodeInput::Network => (ProtoNodeInput::Network, ConstructionArgs::Nodes(vec![])),
@ -266,7 +266,7 @@ impl NodeNetwork {
) {
"Value".to_string()
} else {
format!("Value: {:?}", tagged_value.clone().to_value())
format!("Value: {:?}", tagged_value)
};
let new_id = map_ids(id, gen_id());
let value_node = DocumentNode {
@ -409,7 +409,6 @@ impl NodeNetwork {
mod test {
use super::*;
use crate::proto::{ConstructionArgs, NodeIdentifier, ProtoNetwork, ProtoNode, ProtoNodeInput};
use value::IntoValue;
fn gen_node_id() -> NodeId {
static mut NODE_ID: NodeId = 3;
@ -563,7 +562,7 @@ mod test {
construction_args: ConstructionArgs::Nodes(vec![]),
},
),
(14, ProtoNode::value(ConstructionArgs::Value(2_u32.into_any()))),
(14, ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2)))),
]
.into_iter()
.collect(),
@ -602,7 +601,7 @@ mod test {
(
14,
DocumentNode {
name: "Value: 2".into(),
name: "Value: U32(2)".into(),
inputs: vec![NodeInput::Value {
tagged_value: value::TaggedValue::U32(2),
exposed: false,

View file

@ -2,8 +2,11 @@ pub use dyn_any::StaticType;
use dyn_any::{DynAny, Upcast};
use dyn_clone::DynClone;
pub use glam::DVec2;
use graphene_core::Node;
use std::hash::Hash;
pub use std::sync::Arc;
use crate::executor::Any;
pub use crate::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod, ImaginateStatus};
/// A type that is known, allowing serialization (serde::Deserialize is not object safe)
@ -29,9 +32,83 @@ pub enum TaggedValue {
LayerPath(Option<Vec<u64>>),
}
impl TaggedValue {
#[allow(clippy::derive_hash_xor_eq)]
impl Hash for TaggedValue {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Self::None => 0.hash(state),
Self::String(s) => {
1.hash(state);
s.hash(state)
}
Self::U32(u) => {
2.hash(state);
u.hash(state)
}
Self::F32(f) => {
3.hash(state);
f.to_bits().hash(state)
}
Self::F64(f) => {
4.hash(state);
f.to_bits().hash(state)
}
Self::Bool(b) => {
5.hash(state);
b.hash(state)
}
Self::DVec2(v) => {
6.hash(state);
v.to_array().iter().for_each(|x| x.to_bits().hash(state))
}
Self::OptionalDVec2(None) => 7.hash(state),
Self::OptionalDVec2(Some(v)) => {
8.hash(state);
Self::DVec2(*v).hash(state)
}
Self::Image(i) => {
9.hash(state);
i.hash(state)
}
Self::RcImage(i) => {
10.hash(state);
i.hash(state)
}
Self::Color(c) => {
11.hash(state);
c.hash(state)
}
Self::Subpath(s) => {
12.hash(state);
s.hash(state)
}
Self::RcSubpath(s) => {
13.hash(state);
s.hash(state)
}
Self::ImaginateSamplingMethod(m) => {
14.hash(state);
m.hash(state)
}
Self::ImaginateMaskStartingFill(f) => {
15.hash(state);
f.hash(state)
}
Self::ImaginateStatus(s) => {
16.hash(state);
s.hash(state)
}
Self::LayerPath(p) => {
17.hash(state);
p.hash(state)
}
}
}
}
impl<'a> TaggedValue {
/// Converts to a Box<dyn DynAny> - this isn't very neat but I'm not sure of a better approach
pub fn to_value(self) -> Value {
pub fn to_any(self) -> Any<'a> {
match self {
TaggedValue::None => Box::new(()),
TaggedValue::String(x) => Box::new(x),
@ -54,19 +131,35 @@ impl TaggedValue {
}
}
pub type Value = Box<dyn ValueTrait>;
pub struct UpcastNode {
value: TaggedValue,
}
impl<'input> Node<'input, Box<dyn DynAny<'input> + 'input>> for UpcastNode {
type Output = Box<dyn DynAny<'input> + 'input>;
pub trait ValueTrait: DynAny<'static> + Upcast<dyn DynAny<'static>> + std::fmt::Debug + DynClone {}
fn eval<'s: 'input>(&'s self, _: Box<dyn DynAny<'input> + 'input>) -> Self::Output {
self.value.clone().to_any()
}
}
impl UpcastNode {
pub fn new(value: TaggedValue) -> Self {
Self { value }
}
}
pub trait IntoValue: Sized + ValueTrait + 'static {
fn into_any(self) -> Value {
pub type Value<'a> = Box<dyn for<'i> ValueTrait<'i> + 'a>;
pub trait ValueTrait<'a>: DynAny<'a> + Upcast<dyn DynAny<'a> + 'a> + std::fmt::Debug + DynClone + Sync + Send + 'a {}
pub trait IntoValue<'a>: Sized + for<'i> ValueTrait<'i> + 'a {
fn into_any(self) -> Value<'a> {
Box::new(self)
}
}
impl<T: 'static + StaticType + Upcast<dyn DynAny<'static>> + std::fmt::Debug + PartialEq + Clone> ValueTrait for T {}
impl<'a, T: 'a + StaticType + Upcast<dyn DynAny<'a> + 'a> + std::fmt::Debug + PartialEq + Clone + Sync + Send + 'a> ValueTrait<'a> for T {}
impl<T: 'static + ValueTrait> IntoValue for T {}
impl<'a, T: for<'i> ValueTrait<'i> + 'a> IntoValue<'a> for T {}
#[repr(C)]
pub(crate) struct Vtable {
@ -81,7 +174,7 @@ pub(crate) struct TraitObject {
pub(crate) vtable: &'static Vtable,
}
impl PartialEq for Box<dyn ValueTrait> {
impl<'a> PartialEq for Box<dyn for<'i> ValueTrait<'i> + 'a> {
#[cfg_attr(miri, ignore)]
fn eq(&self, other: &Self) -> bool {
if self.type_id() != other.type_id() {
@ -96,7 +189,16 @@ impl PartialEq for Box<dyn ValueTrait> {
}
}
impl Clone for Value {
impl<'a> Hash for Value<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) };
let size = self_trait_object.vtable.size;
let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) };
self_mem.hash(state);
}
}
impl<'a> Clone for Value<'a> {
fn clone(&self) -> Self {
let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) };
let size = self_trait_object.vtable.size;
@ -116,6 +218,7 @@ mod test {
use super::*;
#[test]
#[cfg_attr(miri, ignore)]
fn test_any_src() {
assert!(2_u32.into_any() == 2_u32.into_any());
assert!(2_u32.into_any() != 3_u32.into_any());

View file

@ -9,10 +9,10 @@ pub struct Compiler {}
impl Compiler {
pub fn compile(&self, mut network: NodeNetwork, resolve_inputs: bool) -> ProtoNetwork {
let node_count = network.nodes.len();
let node_ids = network.nodes.keys().copied().collect::<Vec<_>>();
println!("flattening");
for id in 0..node_count {
network.flatten(id as u64);
for id in node_ids {
network.flatten(id);
}
let mut proto_network = network.into_proto_network();
if resolve_inputs {
@ -21,11 +21,12 @@ impl Compiler {
}
println!("reordering ids");
proto_network.reorder_ids();
proto_network.generate_stable_node_ids();
proto_network
}
}
pub type Any<'a> = Box<dyn DynAny<'a> + 'a>;
pub trait Executor {
fn execute(&self, input: Any<'static>) -> Result<Any<'static>, Box<dyn Error>>;
fn execute<'a, 's: 'a>(&'s self, input: Any<'a>) -> Result<Any<'a>, Box<dyn Error>>;
}

View file

@ -14,6 +14,23 @@ pub enum ImaginateStatus {
Terminated,
}
#[allow(clippy::derive_hash_xor_eq)]
impl core::hash::Hash for ImaginateStatus {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
match self {
Self::Idle => 0.hash(state),
Self::Beginning => 1.hash(state),
Self::Uploading(f) => {
2.hash(state);
f.to_bits().hash(state);
}
Self::Generating => 3.hash(state),
Self::Terminating => 4.hash(state),
Self::Terminated => 5.hash(state),
}
}
}
#[derive(Debug, Clone, PartialEq, specta::Type)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ImaginateBaseImage {
@ -31,7 +48,7 @@ pub struct ImaginateMaskImage {
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, specta::Type)]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, specta::Type, Hash)]
pub enum ImaginateMaskPaintMode {
#[default]
Inpaint,
@ -39,7 +56,7 @@ pub enum ImaginateMaskPaintMode {
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, DynAny, specta::Type)]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, DynAny, specta::Type, Hash)]
pub enum ImaginateMaskStartingFill {
#[default]
Fill,
@ -70,7 +87,7 @@ impl std::fmt::Display for ImaginateMaskStartingFill {
}
}
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, DynAny, specta::Type)]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, DynAny, specta::Type, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ImaginateSamplingMethod {
#[default]

View file

@ -1,5 +1,6 @@
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use crate::document::value;
use crate::document::NodeId;
@ -87,6 +88,7 @@ impl NodeIdentifier {
#[derive(Debug, Default, PartialEq)]
pub struct ProtoNetwork {
// Should a proto Network even allow inputs? Don't think so
pub inputs: Vec<NodeId>,
pub output: NodeId,
pub nodes: Vec<(NodeId, ProtoNode)>,
@ -94,7 +96,7 @@ pub struct ProtoNetwork {
#[derive(Debug)]
pub enum ConstructionArgs {
Value(value::Value),
Value(value::TaggedValue),
Nodes(Vec<NodeId>),
}
@ -108,6 +110,20 @@ impl PartialEq for ConstructionArgs {
}
}
impl Hash for ConstructionArgs {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Self::Nodes(nodes) => {
"nodes".hash(state);
for node in nodes {
node.hash(state);
}
}
Self::Value(value) => value.hash(state),
}
}
}
impl ConstructionArgs {
pub fn new_function_args(&self) -> Vec<String> {
match self {
@ -142,6 +158,19 @@ impl ProtoNodeInput {
}
impl ProtoNode {
pub fn stable_node_id(&self) -> Option<NodeId> {
use std::hash::Hasher;
let mut hasher = std::collections::hash_map::DefaultHasher::new();
self.identifier.fully_qualified_name().hash(&mut hasher);
self.construction_args.hash(&mut hasher);
match self.input {
ProtoNodeInput::None => "none".hash(&mut hasher),
ProtoNodeInput::Network => "network".hash(&mut hasher),
ProtoNodeInput::Node(id) => id.hash(&mut hasher),
};
Some(hasher.finish() as NodeId)
}
pub fn value(value: ConstructionArgs) -> Self {
Self {
identifier: NodeIdentifier::new("graphene_core::value::ValueNode", &[Type::Generic(Cow::Borrowed("T"))]),
@ -195,6 +224,24 @@ impl ProtoNetwork {
edges
}
pub fn generate_stable_node_ids(&mut self) {
for i in 0..self.nodes.len() {
self.generate_stable_node_id(i);
}
}
pub fn generate_stable_node_id(&mut self, index: usize) -> NodeId {
let mut lookup = self.nodes.iter().map(|(id, _)| (*id, *id)).collect::<HashMap<_, _>>();
if let Some(sni) = self.nodes[index].1.stable_node_id() {
lookup.insert(self.nodes[index].0, sni);
self.replace_node_references(&lookup);
self.nodes[index].0 = sni;
sni
} else {
panic!("failed to generate stable node id for node {:#?}", self.nodes[index].1);
}
}
pub fn collect_inwards_edges(&self) -> HashMap<NodeId, Vec<NodeId>> {
let mut edges: HashMap<NodeId, Vec<NodeId>> = HashMap::new();
for (id, node) in &self.nodes {
@ -236,7 +283,7 @@ impl ProtoNetwork {
self.nodes.push((
compose_node_id,
ProtoNode {
identifier: NodeIdentifier::new("graphene_core::structural::ComposeNode", &[generic!("T"), Type::Generic(Cow::Borrowed("U"))]),
identifier: NodeIdentifier::new("graphene_core::structural::ComposeNode<_, _, _>", &[generic!("T"), generic!("U")]),
construction_args: ConstructionArgs::Nodes(vec![input_node, id]),
input,
},
@ -330,7 +377,6 @@ impl ProtoNetwork {
mod test {
use super::*;
use crate::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, ProtoNodeInput};
use value::IntoValue;
#[test]
fn topological_sort() {
@ -378,8 +424,30 @@ mod test {
assert_eq!(construction_network.nodes[5].1.construction_args, ConstructionArgs::Nodes(vec![3, 4]));
}
#[test]
fn stable_node_id_generation() {
let mut construction_network = test_network();
construction_network.reorder_ids();
construction_network.generate_stable_node_ids();
construction_network.resolve_inputs();
construction_network.generate_stable_node_ids();
assert_eq!(construction_network.nodes[0].1.identifier.name.as_ref(), "value");
let ids: Vec<_> = construction_network.nodes.iter().map(|(id, _)| *id).collect();
assert_eq!(
ids,
vec![
17495035641492238530,
14931179783740213471,
2268573767208263092,
14616574692620381527,
12110007198416821768,
11185814750012198757
]
);
}
fn test_network() -> ProtoNetwork {
let construction_network = ProtoNetwork {
ProtoNetwork {
inputs: vec![10],
output: 1,
nodes: [
@ -420,13 +488,12 @@ mod test {
ProtoNode {
identifier: "value".into(),
input: ProtoNodeInput::None,
construction_args: ConstructionArgs::Value(2_u32.into_any()),
construction_args: ConstructionArgs::Value(value::TaggedValue::U32(2)),
},
),
]
.into_iter()
.collect(),
};
construction_network
}
}
}

View file

@ -1,323 +1,199 @@
use dyn_any::{DynAny, StaticType, StaticTypeSized};
pub use graphene_core::{generic, ops /*, structural*/, Node, RefNode};
use std::marker::PhantomData;
use dyn_any::{DynAny, StaticType};
pub use graphene_core::{generic, ops, Node};
use std::{marker::PhantomData, pin::Pin};
pub struct DynAnyNode<N, I: StaticType, O: StaticType, ORef: StaticType>(pub N, pub PhantomData<(I, O, ORef)>);
/*impl<'n, I: StaticType, N: RefNode<'n, &'n I, Output = O> + 'n, O: 'n + StaticType> Node<&'n dyn DynAny<'n>> for DynAnyNode<'n, N, I> {
type Output = Box<dyn dyn_any::DynAny<'n> + 'n>;
fn eval(self, input: &'n dyn DynAny<'n>) -> Self::Output {
let output = self.0.eval_ref(dyn_any::downcast_ref(input).expect(fmt_error::<I>().as_str()));
Box::new(output)
}
}*/
/*
impl<'n, I: StaticType, N: RefNode<&'n I, Output = O> + Copy + 'n, O: 'n + StaticType> Node<&'n dyn DynAny<'n>> for &'n DynAnyNode<'n, N, I> {
type Output = Box<dyn dyn_any::DynAny<'n> + 'n>;
fn eval(self, input: &'n dyn DynAny<'n>) -> Self::Output {
let output = self.0.eval_ref(dyn_any::downcast_ref(input).unwrap_or_else(|| panic!("{}", fmt_error::<I>())));
Box::new(output)
}
pub struct DynAnyNode<I, O, Node> {
node: Node,
_i: PhantomData<I>,
_o: PhantomData<O>,
}
impl<'n, I: StaticType, N: RefNode<'n, I, Output = O> + 'n, O: 'n + StaticType> Node<Box<dyn DynAny<'n>>> for DynAnyNode<'n, N, I> {
type Output = Box<dyn dyn_any::DynAny<'n> + 'n>;
fn eval(self, input: Box<dyn DynAny<'n>>) -> Self::Output {
let input: Box<I> = dyn_any::downcast(input).unwrap_or_else(|| panic!("{}", fmt_error::<I>()));
Box::new(self.0.eval_ref(*input))
}
}*/
impl<'n, I: StaticType, N: 'n, O: 'n + StaticType, ORef: 'n + StaticType> Node<Any<'n>> for DynAnyNode<N, I, O, ORef>
#[node_macro::node_fn(DynAnyNode<_I, _O>)]
fn any_node<_I: StaticType, _O: StaticType, N>(input: Any<'input>, node: &'any_input N) -> Any<'input>
where
N: Node<I, Output = O>,
N: for<'any_input> Node<'any_input, _I, Output = _O>,
{
type Output = Any<'n>;
fn eval(self, input: Any<'n>) -> Self::Output {
let node = core::any::type_name::<N>();
let input: Box<I> = dyn_any::downcast(input).unwrap_or_else(|_| panic!("DynAnyNode Input in:\n{node}"));
Box::new(self.0.eval(*input))
}
let node_name = core::any::type_name::<N>();
let input: Box<_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyNode Input, {e} in:\n{node_name}"));
Box::new(node.eval(*input))
}
impl<'n, I: StaticType, N: 'n, O: 'n + StaticType, ORef: 'n + StaticType> Node<Any<'n>> for &'n DynAnyNode<N, I, O, ORef>
pub struct DynAnyRefNode<I, O, Node> {
node: Node,
_i: PhantomData<(I, O)>,
}
impl<'input, _I: 'input + StaticType, _O: 'input + StaticType, N: 'input> Node<'input, Any<'input>> for DynAnyRefNode<_I, _O, N>
where
&'n N: Node<I, Output = ORef>,
N: for<'any_input> Node<'any_input, _I, Output = &'any_input _O>,
{
type Output = Any<'n>;
fn eval(self, input: Any<'n>) -> Self::Output {
let node = core::any::type_name::<N>();
let input: Box<I> = dyn_any::downcast(input).unwrap_or_else(|_| panic!("DynAnyNode Input in:\n{node}"));
Box::new((&self.0).eval_ref(*input))
type Output = Any<'input>;
fn eval<'node: 'input>(&'node self, input: Any<'input>) -> Self::Output {
{
let node_name = core::any::type_name::<N>();
let input: Box<_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyNode Input, {e} in:\n{node_name}"));
Box::new(self.node.eval(*input))
}
}
}
pub struct TypeErasedNode<'n>(pub Box<dyn AsRefNode<'n, Any<'n>, Output = Any<'n>> + 'n>);
impl<'n> Node<Any<'n>> for &'n TypeErasedNode<'n> {
type Output = Any<'n>;
fn eval(self, input: Any<'n>) -> Self::Output {
self.0.eval_box(input)
}
}
impl<'n> Node<Any<'n>> for &'n &'n TypeErasedNode<'n> {
type Output = Any<'n>;
fn eval(self, input: Any<'n>) -> Self::Output {
self.0.eval_box(input)
impl<_I, _O, S0> DynAnyRefNode<_I, _O, S0> {
pub const fn new(node: S0) -> Self {
Self { node, _i: core::marker::PhantomData }
}
}
pub type TypeErasedNode<'n> = dyn for<'i> Node<'i, Any<'i>, Output = Any<'i>> + 'n + Send + Sync;
pub type TypeErasedPinnedRef<'n> = Pin<&'n (dyn for<'i> Node<'i, Any<'i>, Output = Any<'i>> + 'n + Send + Sync)>;
pub type TypeErasedPinned<'n> = Pin<Box<dyn for<'i> Node<'i, Any<'i>, Output = Any<'i>> + 'n + Send + Sync>>;
pub trait IntoTypeErasedNode<'n> {
fn into_type_erased(self) -> TypeErasedNode<'n>;
}
impl<'n> StaticTypeSized for TypeErasedNode<'n> {
type Static = TypeErasedNode<'static>;
fn into_type_erased(self) -> TypeErasedPinned<'n>;
}
impl<'n, N: 'n> IntoTypeErasedNode<'n> for N
where
N: AsRefNode<'n, Any<'n>, Output = Any<'n>>,
&'n N: Node<Any<'n>, Output = Any<'n>>,
N: for<'i> Node<'i, Any<'i>, Output = Any<'i>> + Send + Sync + 'n,
{
fn into_type_erased(self) -> TypeErasedNode<'n> {
TypeErasedNode(Box::new(self))
fn into_type_erased(self) -> TypeErasedPinned<'n> {
Box::pin(self)
}
}
impl<'n, I: StaticType + 'n, N: 'n, O: 'n + StaticType, ORef: 'n + StaticType> DynAnyNode<N, I, O, ORef>
where
&'n N: Node<I, Output = ORef>,
{
pub fn new(n: N) -> Self {
DynAnyNode(n, PhantomData)
}
pub fn into_impl(&'n self) -> impl RefNode<Any<'n>, Output = Any<'n>> {
self
}
/*pub fn as_ref(&'n self) -> &'n AnyNode<'n> {
self
}
pub fn into_ref_box(self) -> Box<dyn RefNode<Box<(dyn DynAny<'n> + 'n)>, Output = Box<(dyn DynAny<'n> + 'n)>> + 'n> {
Box::new(self)
}*/
pub fn as_ref(self: &'n &'n Self) -> &'n (dyn RefNode<Any<'n>, Output = Any<'n>> + 'n) {
self
}
pub fn into_box<'a: 'n>(self) -> TypeErasedNode<'n>
where
Self: 'a,
N: Node<I, Output = O>,
{
self.into_type_erased()
}
pub struct DowncastNode<O, Node> {
node: Node,
_o: PhantomData<O>,
}
impl<'n, I: StaticType + 'n, N: 'n, O: 'n + StaticType, ORef: 'n + StaticType> DynAnyNode<&'n N, I, O, ORef>
where
N: Node<I, Output = ORef>,
{
pub fn new_from_ref(n: &'n N) -> Self {
DynAnyNode(n, PhantomData)
}
}
pub struct DowncastNode<N, I: StaticType>(pub N, pub PhantomData<I>);
impl<N: Copy + Clone, I: StaticType> Clone for DowncastNode<N, I> {
impl<N: Clone, O: StaticType> Clone for DowncastNode<O, N> {
fn clone(&self) -> Self {
Self(self.0, self.1)
Self { node: self.node.clone(), _o: self._o }
}
}
impl<N: Copy + Clone, I: StaticType> Copy for DowncastNode<N, I> {}
impl<N: Copy, O: StaticType> Copy for DowncastNode<O, N> {}
impl<'n, N, O: 'n + StaticType> Node<Any<'n>> for DowncastNode<N, O>
#[node_macro::node_fn(DowncastNode<_O>)]
fn downcast<N, _O: StaticType>(input: Any<'input>, node: &'input N) -> _O
where
N: Node<Any<'n>, Output = Any<'n>>,
N: Node<'input, Any<'input>, Output = Any<'input>>,
{
type Output = O;
fn eval(self, input: Any<'n>) -> Self::Output {
let output = self.0.eval(input);
*dyn_any::downcast(output).expect("DowncastNode Output")
}
}
impl<'n, N, I: StaticType> DowncastNode<N, I>
where
N: Node<Any<'n>>,
{
pub fn new(n: N) -> Self {
DowncastNode(n, PhantomData)
}
let node_name = core::any::type_name::<N>();
let out = dyn_any::downcast(node.eval(input)).unwrap_or_else(|e| panic!("DynAnyNode Input {e} in:\n{node_name}"));
*out
}
/// Boxes the input and downcasts the output.
/// Wraps around a node taking Box<dyn DynAny> and returning Box<dyn DynAny>
pub struct DowncastBothNode<N, I: StaticType, O: StaticType>(pub N, pub PhantomData<(I, O)>);
impl<N: Copy + Clone, I: StaticType, O: StaticType> Clone for DowncastBothNode<N, I, O> {
fn clone(&self) -> Self {
Self(self.0, self.1)
}
#[derive(Clone, Copy)]
pub struct DowncastBothNode<'a, I, O> {
node: TypeErasedPinnedRef<'a>,
_i: PhantomData<I>,
_o: PhantomData<O>,
}
impl<N: Copy + Clone, I: StaticType, O: StaticType> Copy for DowncastBothNode<N, I, O> {}
impl<'n, N, I: 'n + StaticType, O: 'n + StaticType> Node<I> for DowncastBothNode<N, I, O>
where
N: Node<Any<'n>, Output = Any<'n>>,
{
impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'input, I> for DowncastBothNode<'n, I, O> {
type Output = O;
fn eval(self, input: I) -> Self::Output {
let input = Box::new(input) as Box<dyn DynAny>;
let output = self.0.eval(input);
*dyn_any::downcast(output).expect("DowncastBothNode Output")
#[inline]
fn eval<'node: 'input>(&'node self, input: I) -> Self::Output {
{
let input = Box::new(input);
let out = dyn_any::downcast(self.node.eval(input)).unwrap_or_else(|e| panic!("DynAnyNode Input {e}"));
*out
}
}
}
impl<'n, N, I: 'n + StaticType, O: 'n + StaticType> Node<I> for &DowncastBothNode<N, I, O>
where
N: Node<Any<'n>, Output = Any<'n>> + Copy,
{
type Output = O;
fn eval(self, input: I) -> Self::Output {
let input = Box::new(input) as Box<dyn DynAny>;
let output = self.0.eval(input);
*dyn_any::downcast(output).expect("DowncastBothNode Output")
impl<'n, I, O> DowncastBothNode<'n, I, O> {
pub const fn new(node: TypeErasedPinnedRef<'n>) -> Self {
Self {
node,
_i: core::marker::PhantomData,
_o: core::marker::PhantomData,
}
}
}
impl<'n, N, I: StaticType, O: StaticType> DowncastBothNode<N, I, O>
where
N: Node<Any<'n>>,
{
pub fn new(n: N) -> Self {
DowncastBothNode(n, PhantomData)
/// Boxes the input and downcasts the output.
/// Wraps around a node taking Box<dyn DynAny> and returning Box<dyn DynAny>
#[derive(Clone, Copy)]
pub struct DowncastBothRefNode<'a, I, O> {
node: TypeErasedPinnedRef<'a>,
_i: PhantomData<(I, O)>,
}
impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'input, I> for DowncastBothRefNode<'n, I, O> {
type Output = &'input O;
#[inline]
fn eval<'node: 'input>(&'node self, input: I) -> Self::Output {
{
let input = Box::new(input);
let out: Box<&_> = dyn_any::downcast::<&O>(self.node.eval(input)).unwrap_or_else(|e| panic!("DynAnyNode Input {e}"));
*out
}
}
}
impl<'n, I, O> DowncastBothRefNode<'n, I, O> {
pub const fn new(node: TypeErasedPinnedRef<'n>) -> Self {
Self { node, _i: core::marker::PhantomData }
}
}
/*
/// If we store a `Box<dyn RefNode>` in the stack then the origional DynAnyNode is dropped (because it is not stored by reference)
/// This trait is implemented directly by `DynAnyNode` so this means the borrow stack will hold by value
pub trait DynAnyNodeTrait<'n> {
fn eval_ref_dispatch(&'n self, input: Any<'n>) -> Any<'n>;
}
impl<'n, I: StaticType, O: 'n + StaticType, Node: 'n> DynAnyNodeTrait<'n> for DynAnyNode<Node, I, O>
where
&'n Node: RefNode<I>,
{
fn eval_ref_dispatch(&'n self, input: Any<'n>) -> Any<'n> {
self.eval_ref(input)
}
}*/
use graphene_core::ops::dynamic::Dynamic;
use graphene_core::AsRefNode;
pub struct BoxedComposition<'a, Second> {
pub first: Box<dyn Node<(), Output = Dynamic<'a>>>,
pub second: Second,
pub struct ComposeTypeErased<'a> {
first: TypeErasedPinnedRef<'a>,
second: TypeErasedPinnedRef<'a>,
}
// I can't see to get this to work
// We can't use the existing thing in any as it breaks lifetimes
// impl<'a, Second: Node<Dynamic<'a>>> Node<()> for BoxedComposition<'a, Second> {
// type Output = <Second as Node<Dynamic<'a>>>::Output;
// fn eval(self, input: ()) -> Self::Output {
// let x = RefNode::eval_ref(self.first.as_ref(), input);
// let arg: Dynamic<'a> = x.eval_ref(input);
// (self.second).eval(arg)
// }
// }
/*impl<'n: 'static, I: StaticType, N, O: 'n + StaticType> DynAnyNode<'n, N, I>
where
N: RefNode<I, Output = O> + 'n + Copy,
{
/*pub fn into_owned_erased(self) -> impl RefNode<Any<'n>, Output = Any<'n>> + 'n {
self
}*/
pub fn as_owned(&'n self) -> &'n (dyn RefNode<Any<'n>, Output = Any<'n>> + 'n) {
self
impl<'i, 'a: 'i> Node<'i, Any<'i>> for ComposeTypeErased<'a> {
type Output = Any<'i>;
fn eval<'s: 'i>(&'s self, input: Any<'i>) -> Self::Output {
let arg = self.first.eval(input);
self.second.eval(arg)
}
/*pub fn into_owned_box(&self) -> Box<dyn DynNodeOwned<'n>> {
Box::new(self)
}*/
}*/
}
impl<'a> ComposeTypeErased<'a> {
pub const fn new(first: TypeErasedPinnedRef<'a>, second: TypeErasedPinnedRef<'a>) -> Self {
ComposeTypeErased { first, second }
}
}
pub type Any<'n> = Box<dyn DynAny<'n> + 'n>;
pub type AnyNode<'n> = dyn RefNode<Any<'n>, Output = Any<'n>>;
pub trait DynNodeRef<'n>: RefNode<&'n dyn DynAny<'n>, Output = Box<dyn DynAny<'n> + 'n>> + 'n {}
impl<'n, N: RefNode<&'n dyn DynAny<'n>, Output = Box<dyn DynAny<'n> + 'n>> + 'n> DynNodeRef<'n> for N {}
pub trait DynNodeOwned<'n>: RefNode<Any<'n>, Output = Any<'n>> + 'n {}
impl<'n, N: RefNode<Any<'n>, Output = Any<'n>> + 'n> DynNodeOwned<'n> for N {}
/*impl<'n> Node<Box<dyn DynAny<'n>>> for &'n Box<dyn DynNodeOwned<'n>> {
type Output = Box<dyn DynAny<'n> + 'n>;
fn eval(self, input: Box<dyn DynAny<'n>>) -> Self::Output {
(&*self as &dyn Node<Box<dyn DynAny<'n> + 'n>, Output = Box<dyn DynAny<'n> + 'n>>).eval(input)
}
}*/
pub fn input_node<O: StaticType>(n: TypeErasedPinnedRef) -> DowncastBothNode<(), O> {
DowncastBothNode::new(n)
}
#[cfg(test)]
mod test {
use super::*;
use graphene_core::ops::AddNode;
use graphene_core::value::ValueNode;
/*#[test]
pub fn dyn_input_composition() {
use graphene_core::structural::After;
use graphene_core::structural::ComposeNode;
let id: DynAnyNode<_, u32> = DynAnyNode::new(IdNode);
let add: DynAnyNode<_, (u32, u32)> = DynAnyNode::new(AddNode);
let value: DynAnyNode<_, ()> = DynAnyNode::new(ValueNode((3u32, 4u32)));
let id = &id.as_owned();
let add = add.as_owned();
let value = value.as_owned();
use graphene_core::{ops::AddNode, ops::IdNode, value::ValueNode};
/*let computation = ComposeNode::new(value, add);
let computation = value.then(add).then(id);
let result: u32 = *dyn_any::downcast(computation.eval(&())).unwrap();*/
}*/
#[test]
#[should_panic]
pub fn dyn_input_invalid_eval_panic() {
static ADD: &DynAnyNode<AddNode, (u32, u32), u32, u32> = &DynAnyNode(AddNode, PhantomData);
let add = ADD.as_ref();
add.eval_ref(Box::new(&("32", 32u32)));
//let add = DynAnyNode::new(AddNode::new()).into_type_erased();
//add.eval(Box::new(&("32", 32u32)));
let dyn_any = DynAnyNode::<(u32, u32), u32, _>::new(ValueNode::new(AddNode::new()));
let type_erased = dyn_any.into_type_erased();
let _ref_type_erased = type_erased.as_ref();
//let type_erased = Box::pin(dyn_any) as TypeErasedPinned<'_>;
type_erased.eval(Box::new(&("32", 32u32)));
}
/*#[test]
pub fn dyn_input_storage() {
let mut vec: Vec<Box<dyn DynNodeRef>> = vec![];
let id: DynAnyNode<_, u32> = DynAnyNode::new(IdNode);
let add: DynAnyNode<_, (u32, u32)> = DynAnyNode::new(AddNode);
let value: DynAnyNode<_, ()> = DynAnyNode::new(ValueNode((3u32, 4u32)));
vec.push(add.into_ref_box());
vec.push(id.into_ref_box());
vec.push(value.into_ref_box());
}*/
#[test]
pub fn dyn_input_invalid_eval_panic_() {
//let add = DynAnyNode::new(AddNode::new()).into_type_erased();
//add.eval(Box::new(&("32", 32u32)));
let dyn_any = DynAnyNode::<(u32, u32), u32, _>::new(ValueNode::new(AddNode::new()));
let type_erased = Box::pin(dyn_any) as TypeErasedPinned<'_>;
type_erased.eval(Box::new((4u32, 2u32)));
let id_node = IdNode::new();
let type_erased_id = Box::pin(id_node) as TypeErasedPinned;
let type_erased = ComposeTypeErased::new(type_erased.as_ref(), type_erased_id.as_ref());
type_erased.eval(Box::new((4u32, 2u32)));
//let downcast: DowncastBothNode<(u32, u32), u32> = DowncastBothNode::new(type_erased.as_ref());
//downcast.eval((4u32, 2u32));
}
// TODO: Fix this test
/*
#[test]
pub fn dyn_input_storage_composition() {
let mut vec: Vec<&(dyn RefNode<Any, Output = Any>)> = vec![];
//let id: DynAnyNode<_, u32> = DynAnyNode::new(IdNode);
// If we put this until the push in a new scope then it failes to compile due to lifetime errors which I'm struggling to fix.
let value: &DynAnyNode<ValueNode<(u32, u32)>, (), &(u32, u32), _> = &DynAnyNode(ValueNode((3u32, 4u32)), PhantomData);
let add: &DynAnyNode<AddNode, &(u32, u32), u32, _> = &DynAnyNode(AddNode, PhantomData);
let value_ref = value.as_ref();
let add_ref = add.as_ref();
vec.push(value_ref);
vec.push(add_ref);
//vec.push(add.as_owned());
//vec.push(id.as_owned());
//let vec = vec.leak();
let n_value = vec[0];
let n_add = vec[1];
//let id = vec[2];
assert_eq!(*(dyn_any::downcast::<&(u32, u32)>(n_value.eval_ref(Box::new(()))).unwrap()), &(3u32, 4u32));
fn compose<'n>(
first: &'n (dyn RefNode<Box<(dyn DynAny<'n> + 'n)>, Output = Box<(dyn DynAny<'n> + 'n)>> + 'n),
second: &'n (dyn RefNode<Box<(dyn DynAny<'n> + 'n)>, Output = Box<(dyn DynAny<'n> + 'n)>> + 'n),
input: Any<'n>,
) -> Any<'n> {
second.eval_ref(first.eval_ref(input))
}
let result = compose(n_value, n_add, Box::new(()));
assert_eq!(*dyn_any::downcast::<u32>(result).unwrap(), 7u32);
//let result: u32 = *dyn_any::downcast(computation.eval(Box::new(()))).unwrap();
// todo readd test
let node = <graphene_core::ops::IdNode>::new();
let any: DynAnyNode<Any<'_>, Any<'_>, _> = DynAnyNode::new(ValueNode::new(node));
any.into_type_erased();
}
*/
}

View file

@ -1,38 +1,23 @@
use graphene_core::{Cache, Node};
use graphene_core::Node;
use once_cell::sync::OnceCell;
/// Caches the output of a given Node and acts as a proxy
#[derive(Default)]
pub struct CacheNode<T> {
cache: OnceCell<T>,
}
impl<'n, T> Node<T> for &'n CacheNode<T> {
type Output = &'n T;
fn eval(self, input: T) -> Self::Output {
impl<'i, T: 'i> Node<'i, T> for CacheNode<T> {
type Output = &'i T;
fn eval<'s: 'i>(&'s self, input: T) -> Self::Output {
self.cache.get_or_init(|| {
trace!("Creating new cache node");
input
})
}
}
impl<T> Node<T> for CacheNode<T> {
type Output = T;
fn eval(self, input: T) -> Self::Output {
input
}
}
impl<T> CacheNode<T> {
pub fn new() -> CacheNode<T> {
pub const fn new() -> CacheNode<T> {
CacheNode { cache: OnceCell::new() }
}
}
impl<T> Default for CacheNode<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Cache for CacheNode<T> {
fn clear(&mut self) {
self.cache = OnceCell::new();
}
}

View file

@ -1,59 +1,10 @@
use core::marker::PhantomData;
use dyn_any::{DynAny, StaticType};
use graphene_core::generic::FnNode;
use graphene_core::ops::{FlatMapResultNode, MapResultNode};
use graphene_core::raster::{Color, Image};
use graphene_core::structural::{ComposeNode, ConsNode, Then};
use graphene_core::value::ValueNode;
use graphene_core::Node;
use image::Pixel;
use std::path::Path;
pub struct MapNode<MN: Node<S>, I: IntoIterator<Item = S>, S>(pub MN, PhantomData<(S, I)>);
impl<I: IntoIterator<Item = S>, MN: Node<S> + Copy, S> Node<I> for MapNode<MN, I, S> {
type Output = Vec<MN::Output>;
fn eval(self, input: I) -> Self::Output {
input.into_iter().map(|x| self.0.eval(x)).collect()
}
}
impl<I: IntoIterator<Item = S>, MN: Node<S>, S> MapNode<MN, I, S> {
pub const fn new(mn: MN) -> Self {
MapNode(mn, PhantomData)
}
}
pub struct MapImageNode<MN: Node<Color, Output = Color> + Copy>(pub MN);
impl<MN: Node<Color, Output = Color> + Copy> Node<Image> for MapImageNode<MN> {
type Output = Image;
fn eval(self, input: Image) -> Self::Output {
Image {
width: input.width,
height: input.height,
data: input.data.iter().map(|x| self.0.eval(*x)).collect(),
}
}
}
impl<'n, MN: Node<Color, Output = Color> + Copy> Node<Image> for &'n MapImageNode<MN> {
type Output = Image;
fn eval(self, input: Image) -> Self::Output {
Image {
width: input.width,
height: input.height,
data: input.data.iter().map(|x| self.0.eval(*x)).collect(),
}
}
}
impl<MN: Node<Color, Output = Color> + Copy> MapImageNode<MN> {
pub const fn new(mn: MN) -> Self {
MapImageNode(mn)
}
}
#[derive(Debug, DynAny)]
pub enum Error {
IO(std::io::Error),
@ -79,39 +30,32 @@ impl FileSystem for StdFs {
}
type Reader = Box<dyn std::io::Read>;
pub struct FileNode<P: AsRef<Path>, FS: FileSystem>(PhantomData<(P, FS)>);
impl<P: AsRef<Path>, FS: FileSystem> Node<(P, FS)> for FileNode<P, FS> {
type Output = Result<Reader, Error>;
fn eval(self, input: (P, FS)) -> Self::Output {
let (path, fs) = input;
fs.open(path)
}
pub struct FileNode<FileSystem> {
fs: FileSystem,
}
#[node_macro::node_fn(FileNode)]
fn file_node<P: AsRef<Path>, FS: FileSystem>(path: P, fs: FS) -> Result<Reader, Error> {
fs.open(path)
}
pub struct BufferNode;
impl<Reader: std::io::Read> Node<Reader> for BufferNode {
type Output = Result<Vec<u8>, Error>;
fn eval(self, mut reader: Reader) -> Self::Output {
let mut buffer = Vec::new();
reader.read_to_end(&mut buffer)?;
Ok(buffer)
}
#[node_macro::node_fn(BufferNode)]
fn buffer_node<R: std::io::Read>(reader: R) -> Result<Vec<u8>, Error> {
Ok(std::io::Read::bytes(reader).collect::<Result<Vec<_>, _>>()?)
}
pub fn file_node<'n, P: AsRef<Path> + 'n>() -> impl Node<P, Output = Result<Vec<u8>, Error>> {
let fs = ValueNode(StdFs).clone();
let fs = ConsNode::new(fs);
let file = fs.then(FileNode(PhantomData));
/*
pub fn file_node<'i, 's: 'i, P: AsRef<Path> + 'i>() -> impl Node<'i, 's, P, Output = Result<Vec<u8>, Error>> {
let fs = ValueNode(StdFs).then(CloneNode::new());
let file = FileNode::new(fs);
file.then(FlatMapResultNode::new(BufferNode))
file.then(FlatMapResultNode::new(ValueNode::new(BufferNode)))
}
pub fn image_node<'n, P: AsRef<Path> + 'n>() -> impl Node<P, Output = Result<Image, Error>> {
pub fn image_node<'i, 's: 'i, P: AsRef<Path> + 'i>() -> impl Node<'i, 's, P, Output = Result<Image, Error>> {
let file = file_node();
let image_loader = FnNode::new(|data: Vec<u8>| image::load_from_memory(&data).map_err(Error::Image).map(|image| image.into_rgba32f()));
let image: ComposeNode<_, _, P> = file.then(FlatMapResultNode::new(image_loader));
let image = file.then(FlatMapResultNode::new(ValueNode::new(image_loader)));
let convert_image = FnNode::new(|image: image::ImageBuffer<_, _>| {
let data = image
.enumerate_pixels()
@ -130,7 +74,7 @@ pub fn image_node<'n, P: AsRef<Path> + 'n>() -> impl Node<P, Output = Result<Ima
image.then(MapResultNode::new(convert_image))
}
pub fn export_image_node<'n>() -> impl Node<(Image, &'n str), Output = Result<(), Error>> {
pub fn export_image_node<'i, 's: 'i>() -> impl Node<'i, 's, (Image, &'i str), Output = Result<(), Error>> {
FnNode::new(|input: (Image, &str)| {
let (image, path) = input;
let mut new_image = image::ImageBuffer::new(image.width, image.height);
@ -143,12 +87,14 @@ pub fn export_image_node<'n>() -> impl Node<(Image, &'n str), Output = Result<()
new_image.save(path).map_err(Error::Image)
})
}
*/
#[derive(Debug, Clone, Copy)]
pub struct GrayscaleNode;
#[node_macro::node_fn(GrayscaleNode)]
fn grayscale_image(mut image: Image) -> Image {
fn grayscale_image(image: Image) -> Image {
let mut image = image;
for pixel in &mut image.data {
let avg = (pixel.r() + pixel.g() + pixel.b()) / 3.;
*pixel = Color::from_rgbaf32_unchecked(avg, avg, avg, pixel.a());
@ -156,11 +102,29 @@ fn grayscale_image(mut image: Image) -> Image {
image
}
#[derive(Debug, Clone, Copy)]
pub struct MapImageNode<MapFn> {
map_fn: MapFn,
}
#[node_macro::node_fn(MapImageNode)]
fn grayscale_image<MapFn>(image: Image, map_fn: &'any_input MapFn) -> Image
where
MapFn: for<'any_input> Node<'any_input, Color, Output = Color> + 'input,
{
let mut image = image;
for pixel in &mut image.data {
*pixel = map_fn.eval(*pixel);
}
image
}
#[derive(Debug, Clone, Copy)]
pub struct InvertRGBNode;
#[node_macro::node_fn(InvertRGBNode)]
fn invert_image(mut image: Image) -> Image {
let mut image = image;
for pixel in &mut image.data {
*pixel = Color::from_rgbaf32_unchecked(1. - pixel.r(), 1. - pixel.g(), 1. - pixel.b(), pixel.a());
}
@ -175,7 +139,8 @@ pub struct HueSaturationNode<Hue, Sat, Lit> {
}
#[node_macro::node_fn(HueSaturationNode)]
fn shift_image_hsl(mut image: Image, hue_shift: f64, saturation_shift: f64, lightness_shift: f64) -> Image {
fn shift_image_hsl(image: Image, hue_shift: f64, saturation_shift: f64, lightness_shift: f64) -> Image {
let mut image = image;
let (hue_shift, saturation_shift, lightness_shift) = (hue_shift as f32, saturation_shift as f32, lightness_shift as f32);
for pixel in &mut image.data {
let [hue, saturation, lightness, alpha] = pixel.to_hsla();
@ -197,7 +162,8 @@ pub struct BrightnessContrastNode<Brightness, Contrast> {
// From https://stackoverflow.com/questions/2976274/adjust-bitmap-image-brightness-contrast-using-c
#[node_macro::node_fn(BrightnessContrastNode)]
fn adjust_image_brightness_and_contrast(mut image: Image, brightness: f64, contrast: f64) -> Image {
fn adjust_image_brightness_and_contrast(image: Image, brightness: f64, contrast: f64) -> Image {
let mut image = image;
let (brightness, contrast) = (brightness as f32, contrast as f32);
let factor = (259. * (contrast + 255.)) / (255. * (259. - contrast));
let channel = |channel: f32| ((factor * (channel * 255. + brightness - 128.) + 128.) / 255.).clamp(0., 1.);
@ -215,7 +181,8 @@ pub struct GammaNode<G> {
// https://www.dfstudios.co.uk/articles/programming/image-programming-algorithms/image-processing-algorithms-part-6-gamma-correction/
#[node_macro::node_fn(GammaNode)]
fn image_gamma(mut image: Image, gamma: f64) -> Image {
fn image_gamma(image: Image, gamma: f64) -> Image {
let mut image = image;
let inverse_gamma = 1. / gamma;
let channel = |channel: f32| channel.powf(inverse_gamma as f32);
for pixel in &mut image.data {
@ -230,7 +197,8 @@ pub struct OpacityNode<O> {
}
#[node_macro::node_fn(OpacityNode)]
fn image_opacity(mut image: Image, opacity_multiplier: f64) -> Image {
fn image_opacity(image: Image, opacity_multiplier: f64) -> Image {
let mut image = image;
let opacity_multiplier = opacity_multiplier as f32;
for pixel in &mut image.data {
*pixel = Color::from_rgbaf32_unchecked(pixel.r(), pixel.g(), pixel.b(), pixel.a() * opacity_multiplier)
@ -245,7 +213,8 @@ pub struct PosterizeNode<P> {
// Based on http://www.axiomx.com/posterize.htm
#[node_macro::node_fn(PosterizeNode)]
fn posterize(mut image: Image, posterize_value: f64) -> Image {
fn posterize(image: Image, posterize_value: f64) -> Image {
let mut image = image;
let posterize_value = posterize_value as f32;
let number_of_areas = posterize_value.recip();
let size_of_areas = (posterize_value - 1.).recip();
@ -263,7 +232,8 @@ pub struct ExposureNode<E> {
// Based on https://stackoverflow.com/questions/12166117/what-is-the-math-behind-exposure-adjustment-on-photoshop
#[node_macro::node_fn(ExposureNode)]
fn exposure(mut image: Image, exposure: f64) -> Image {
fn exposure(image: Image, exposure: f64) -> Image {
let mut image = image;
let multiplier = 2f32.powf(exposure as f32);
let channel = |channel: f32| channel * multiplier;
for pixel in &mut image.data {
@ -286,27 +256,18 @@ fn imaginate(image: Image, cached: Option<std::sync::Arc<graphene_core::raster::
#[cfg(test)]
mod test {
use super::*;
use graphene_core::raster::color::Color;
use graphene_core::raster::GrayscaleColorNode;
#[test]
fn map_node() {
let array = [Color::from_rgbaf32(1.0, 0.0, 0.0, 1.0).unwrap()];
let map = MapNode(GrayscaleColorNode, PhantomData);
let values = map.eval(array.into_iter());
assert_eq!(values[0], Color::from_rgbaf32(0.33333334, 0.33333334, 0.33333334, 1.0).unwrap());
}
#[test]
fn load_image() {
// TODO: reenable this test
/*
let image = image_node::<&str>();
let gray = MapImageNode::new(GrayscaleColorNode);
let grayscale_picture = image.then(MapResultNode::new(&gray));
let grayscale_picture = image.then(MapResultNode::new(&image));
let export = export_image_node();
let picture = grayscale_picture.eval("test-image-1.png").expect("Failed to load image");
export.eval((picture, "test-image-1-result.png")).unwrap();
*/
}
}

View file

@ -1,32 +1,170 @@
use crate::node_registry::push_node;
use borrow_stack::{BorrowStack, FixedSizeStack};
use graph_craft::executor::Executor;
use graph_craft::proto::ProtoNetwork;
use graphene_core::Node;
use graphene_std::any::{Any, TypeErasedNode};
use std::collections::HashSet;
use std::error::Error;
use std::{collections::HashMap, sync::Arc};
use dyn_any::StaticType;
use graph_craft::document::value::UpcastNode;
use graph_craft::document::NodeId;
use graph_craft::executor::Executor;
use graph_craft::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, ProtoNodeInput};
use graphene_std::any::{Any, TypeErasedPinned, TypeErasedPinnedRef};
use crate::node_registry::constrcut_node;
#[derive(Default, Debug, Clone)]
pub struct DynamicExecutor {
stack: FixedSizeStack<TypeErasedNode<'static>>,
output: NodeId,
tree: BorrowTree,
}
impl DynamicExecutor {
pub fn new(proto_network: ProtoNetwork) -> Self {
assert_eq!(proto_network.inputs.len(), 1);
let node_count = proto_network.nodes.len();
let stack = FixedSizeStack::new(node_count);
for (_id, node) in proto_network.nodes {
push_node(node, &stack);
}
Self { stack }
let output = proto_network.output;
let tree = BorrowTree::new(proto_network);
Self { tree, output }
}
pub fn update(&mut self, proto_network: ProtoNetwork) {
self.output = proto_network.output;
info!("setting output to {}", self.output);
self.tree.update(proto_network);
}
}
impl Executor for DynamicExecutor {
fn execute(&self, input: Any<'static>) -> Result<Any<'static>, Box<dyn Error>> {
let result = unsafe { self.stack.get().last().unwrap().eval(input) };
Ok(result)
fn execute<'a, 's: 'a>(&'s self, input: Any<'a>) -> Result<Any<'a>, Box<dyn Error>> {
self.tree.eval_any(self.output, input).ok_or_else(|| "Failed to execute".into())
}
}
pub struct NodeContainer<'n> {
node: TypeErasedPinned<'n>,
// the dependencies are only kept to ensure that the nodes are not dropped while still in use
_dependencies: Vec<Arc<NodeContainer<'static>>>,
}
impl<'a> core::fmt::Debug for NodeContainer<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NodeContainer").finish()
}
}
impl<'a> NodeContainer<'a> {
/// Return a static reference to the TypeErasedNode
/// # Safety
/// This is unsafe because the returned reference is only valid as long as the NodeContainer is alive
pub unsafe fn erase_lifetime(self) -> NodeContainer<'static> {
std::mem::transmute(self)
}
}
impl NodeContainer<'static> {
unsafe fn static_ref(&self) -> TypeErasedPinnedRef<'static> {
let s = &*(self as *const Self);
*(&s.node.as_ref() as *const TypeErasedPinnedRef<'static>)
}
}
#[derive(Default, Debug, Clone)]
pub struct BorrowTree {
nodes: HashMap<NodeId, Arc<NodeContainer<'static>>>,
}
impl BorrowTree {
pub fn new(proto_network: ProtoNetwork) -> Self {
let mut nodes = BorrowTree::default();
for (id, node) in proto_network.nodes {
nodes.push_node(id, node)
}
nodes
}
/// Pushes new nodes into the tree and return orphaned nodes
pub fn update(&mut self, proto_network: ProtoNetwork) -> Vec<NodeId> {
let mut old_nodes: HashSet<_> = self.nodes.keys().copied().collect();
for (id, node) in proto_network.nodes {
if !self.nodes.contains_key(&id) {
self.push_node(id, node);
old_nodes.remove(&id);
}
}
old_nodes.into_iter().collect()
}
fn node_refs(&self, nodes: &[NodeId]) -> Vec<TypeErasedPinnedRef<'static>> {
self.node_deps(nodes).into_iter().map(|node| unsafe { node.as_ref().static_ref() }).collect()
}
fn node_deps(&self, nodes: &[NodeId]) -> Vec<Arc<NodeContainer<'static>>> {
nodes.iter().map(|node| self.nodes.get(node).unwrap().clone()).collect()
}
fn store_node(&mut self, node: Arc<NodeContainer<'static>>, id: NodeId) -> Arc<NodeContainer<'static>> {
self.nodes.insert(id, node.clone());
node
}
pub fn get(&self, id: NodeId) -> Option<Arc<NodeContainer<'static>>> {
self.nodes.get(&id).cloned()
}
pub fn eval<'i, I: StaticType + 'i, O: StaticType + 'i>(&self, id: NodeId, input: I) -> Option<O> {
let node = self.nodes.get(&id).cloned()?;
let output = node.node.eval(Box::new(input));
dyn_any::downcast::<O>(output).ok().map(|o| *o)
}
pub fn eval_any<'i, 's: 'i>(&'s self, id: NodeId, input: Any<'i>) -> Option<Any<'i>> {
let node = self.nodes.get(&id)?;
Some(node.node.eval(input))
}
pub fn free_node(&mut self, id: NodeId) {
self.nodes.remove(&id);
}
pub fn push_node(&mut self, id: NodeId, proto_node: ProtoNode) {
let ProtoNode { input, construction_args, identifier } = proto_node;
assert!(
!matches!(&input, &ProtoNodeInput::Node(_)),
"Only nodes without inputs are supported. Any inputs should already be resolved by placing ComposeNodes {:?}, {:?}, {:?}",
identifier,
construction_args,
input,
);
match construction_args {
ConstructionArgs::Value(value) => {
let upcasted = UpcastNode::new(value);
let node = Box::pin(upcasted) as TypeErasedPinned<'_>;
let node = NodeContainer { node, _dependencies: vec![] };
let node = unsafe { node.erase_lifetime() };
self.store_node(Arc::new(node), id);
}
ConstructionArgs::Nodes(ids) => {
let construction_nodes = self.node_refs(&ids);
let node = constrcut_node(identifier, construction_nodes);
let node = NodeContainer {
node,
_dependencies: self.node_deps(&ids),
};
let node = unsafe { node.erase_lifetime() };
self.store_node(Arc::new(node), id);
}
}
}
}
#[cfg(test)]
mod test {
use graph_craft::document::value::TaggedValue;
use super::*;
#[test]
fn push_node() {
let mut tree = BorrowTree::default();
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32)));
tree.push_node(0, val_1_protonode);
let _node = tree.get(0).unwrap();
assert_eq!(tree.eval(0, ()), Some(2u32));
}
}

View file

@ -7,16 +7,9 @@ pub mod node_registry;
#[cfg(test)]
mod tests {
use std::marker::PhantomData;
use graphene_core::value::ValueNode;
use graphene_core::{structural::*, RefNode};
use borrow_stack::BorrowStack;
use dyn_any::{downcast, IntoDynAny};
use graphene_std::any::{Any, DowncastNode, DynAnyNode, TypeErasedNode};
use graphene_std::ops::AddNode;
use dyn_any::IntoDynAny;
/*
#[test]
fn borrow_stack() {
let stack = borrow_stack::FixedSizeStack::new(256);
@ -36,7 +29,7 @@ mod tests {
});
stack.push_fn(|nodes| {
let compose_node = nodes[1].after(&nodes[2]);
TypeErasedNode(Box::new(compose_node))
TypeErasedNode(Box::pin(compose_node))
});
let result = unsafe { &stack.get()[0] }.eval_ref(().into_dyn());
@ -48,12 +41,13 @@ mod tests {
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);
}
}*/
#[test]
fn execute_add() {
use graph_craft::document::*;
use graph_craft::proto::*;
use graph_craft::*;
fn add_network() -> NodeNetwork {
NodeNetwork {
@ -65,10 +59,7 @@ mod tests {
DocumentNode {
name: "Cons".into(),
inputs: vec![NodeInput::Network, NodeInput::Network],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new(
"graphene_core::structural::ConsNode",
&[Type::Concrete(std::borrow::Cow::Borrowed("u32")), Type::Concrete(std::borrow::Cow::Borrowed("u32"))],
)),
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode<_, _>", &[concrete!("u32"), concrete!("u32")])),
metadata: DocumentNodeMetadata::default(),
},
),
@ -77,10 +68,7 @@ mod tests {
DocumentNode {
name: "Add".into(),
inputs: vec![NodeInput::Node(0)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new(
"graphene_core::ops::AddNode",
&[Type::Concrete(std::borrow::Cow::Borrowed("u32")), Type::Concrete(std::borrow::Cow::Borrowed("u32"))],
)),
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddNode", &[concrete!("(u32, u32)")])),
metadata: DocumentNodeMetadata::default(),
},
),
@ -118,7 +106,7 @@ mod tests {
use graph_craft::executor::{Compiler, Executor};
let compiler = Compiler {};
let protograph = compiler.compile(network, false);
let protograph = compiler.compile(network, true);
let exec = DynamicExecutor::new(protograph);

View file

@ -1,368 +1,168 @@
use borrow_stack::FixedSizeStack;
use glam::DVec2;
use graphene_core::generic::FnNode;
use graphene_core::ops::{AddNode, CloneNode, IdNode, TypeNode};
use graphene_core::ops::{CloneNode, IdNode, TypeNode};
use graphene_core::raster::color::Color;
use graphene_core::raster::Image;
use graphene_core::structural::{ComposeNode, ConsNode, Then};
use graphene_core::value::ValueNode;
use graphene_core::vector::subpath::Subpath;
use graphene_core::Node;
use graphene_std::any::DowncastBothNode;
use graphene_std::any::{Any, DowncastNode, DynAnyNode, IntoTypeErasedNode, TypeErasedNode};
use graphene_core::raster::*;
use graphene_core::structural::Then;
use graphene_core::value::{ForgetNode, ValueNode};
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DowncastBothRefNode, DynAnyNode, IntoTypeErasedNode, TypeErasedPinned, TypeErasedPinnedRef};
use graph_craft::proto::NodeIdentifier;
use graph_craft::proto::Type;
use graph_craft::proto::{ConstructionArgs, NodeIdentifier, ProtoNode, ProtoNodeInput};
type NodeConstructor = fn(ProtoNode, &FixedSizeStack<TypeErasedNode<'static>>);
type NodeConstructor = for<'a> fn(Vec<TypeErasedPinnedRef<'static>>) -> TypeErasedPinned<'static>;
use graph_craft::{concrete, generic};
use graphene_std::memo::CacheNode;
//TODO: turn into hasmap
macro_rules! register_node {
($path:ty, input: $input:ty, params: [$($type:ty),*]) => {
( {NodeIdentifier::new(stringify!($path), &[concrete!(stringify!($input)), $(concrete!(stringify!($type))),*])},
|args| {
let mut args = args.clone();
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
})
};
}
//TODO: turn into hashmap
static NODE_REGISTRY: &[(NodeIdentifier, NodeConstructor)] = &[
(NodeIdentifier::new("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]), |proto_node, stack| {
stack.push_fn(|nodes| {
if let ProtoNodeInput::Node(pre_id) = proto_node.input {
let pre_node = nodes.get(pre_id as usize).unwrap();
pre_node.into_type_erased()
} else {
IdNode.into_type_erased()
}
})
}),
(NodeIdentifier::new("graphene_core::ops::IdNode", &[generic!("T")]), |proto_node, stack| {
stack.push_fn(|nodes| {
if let ProtoNodeInput::Node(pre_id) = proto_node.input {
let pre_node = nodes.get(pre_id as usize).unwrap();
pre_node.into_type_erased()
} else {
IdNode.into_type_erased()
}
})
}),
(NodeIdentifier::new("graphene_core::ops::AddNode", &[concrete!("&TypeErasedNode")]), |proto_node, stack| {
stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("Add Node constructed with out rhs input node") };
let value_node = nodes.get(construction_nodes[0] as usize).unwrap();
let input_node: DowncastBothNode<_, (), f64> = DowncastBothNode::new(value_node);
let node: DynAnyNode<_, f64, _, _> = DynAnyNode::new(ConsNode::new(input_node).then(graphene_core::ops::AddNode));
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
node.into_type_erased()
}
})
}),
(NodeIdentifier::new("graphene_core::ops::AddNode", &[concrete!("u32"), concrete!("u32")]), |proto_node, stack| {
stack.push_fn(|nodes| {
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
let node: DynAnyNode<AddNode, (u32, u32), _, _> = DynAnyNode::new(graphene_core::ops::AddNode);
let node = (pre_node).then(node);
node.into_type_erased()
})
}),
(NodeIdentifier::new("graphene_core::ops::AddNode", &[concrete!("&u32"), concrete!("&u32")]), |proto_node, stack| {
stack.push_fn(|nodes| {
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
let node: DynAnyNode<AddNode, (&u32, &u32), _, _> = DynAnyNode::new(graphene_core::ops::AddNode);
let node = (pre_node).then(node);
node.into_type_erased()
})
}),
(NodeIdentifier::new("graphene_core::ops::AddNode", &[concrete!("&u32"), concrete!("u32")]), |proto_node, stack| {
stack.push_fn(|nodes| {
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
let node: DynAnyNode<AddNode, (&u32, u32), _, _> = DynAnyNode::new(graphene_core::ops::AddNode);
let node = (pre_node).then(node);
node.into_type_erased()
})
}),
(
NodeIdentifier::new("graphene_core::structural::ConsNode", &[concrete!("&u32"), concrete!("u32")]),
|proto_node, stack| {
if let ConstructionArgs::Nodes(cons_node_arg) = proto_node.construction_args {
stack.push_fn(move |nodes| {
let cons_node_arg = nodes.get(cons_node_arg[0] as usize).unwrap();
let cons_node = ConsNode::new(DowncastNode::<_, &u32>::new(cons_node_arg));
let node: DynAnyNode<_, u32, _, _> = DynAnyNode::new(cons_node);
let node = match proto_node.input {
ProtoNodeInput::Network => node.into_type_erased(),
ProtoNodeInput::Node(node_id) => {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
}
ProtoNodeInput::None => unreachable!(),
};
node
})
} else {
unimplemented!()
}
},
),
(
NodeIdentifier::new("graphene_core::structural::ConsNode", &[concrete!("u32"), concrete!("u32")]),
|proto_node, stack| {
if let ConstructionArgs::Nodes(cons_node_arg) = proto_node.construction_args {
stack.push_fn(move |nodes| {
let cons_node_arg = nodes.get(cons_node_arg[0] as usize).unwrap();
let cons_node = ConsNode::new(DowncastNode::<_, u32>::new(cons_node_arg));
let node: DynAnyNode<_, u32, _, _> = DynAnyNode::new(cons_node);
let node = match proto_node.input {
ProtoNodeInput::Network => node.into_type_erased(),
ProtoNodeInput::Node(node_id) => {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
}
ProtoNodeInput::None => unreachable!(),
};
node
})
} else {
unimplemented!()
}
},
),
//register_node!(graphene_core::ops::IdNode, input: Any<'_>, params: []),
(NodeIdentifier::new("graphene_core::ops::IdNode", &[generic!("T")]), |_| IdNode::new().into_type_erased()),
// TODO: create macro to impl for all types
register_node!(graphene_core::structural::ConsNode<_, _>, input: u32, params: [u32]),
register_node!(graphene_core::structural::ConsNode<_, _>, input: u32, params: [&u32]),
register_node!(graphene_core::structural::ConsNode<_, _>, input: &u32, params: [u32]),
register_node!(graphene_core::structural::ConsNode<_, _>, input: &u32, params: [&u32]),
register_node!(graphene_core::ops::AddNode, input: (u32, u32), params: []),
register_node!(graphene_core::ops::AddParameterNode<_>, input: u32, params: [u32]),
register_node!(graphene_core::ops::AddParameterNode<_>, input: &u32, params: [u32]),
register_node!(graphene_core::ops::AddParameterNode<_>, input: u32, params: [&u32]),
register_node!(graphene_core::ops::AddParameterNode<_>, input: &u32, params: [&u32]),
register_node!(graphene_core::ops::AddParameterNode<_>, input: f64, params: [f64]),
register_node!(graphene_core::ops::AddParameterNode<_>, input: &f64, params: [f64]),
register_node!(graphene_core::ops::AddParameterNode<_>, input: f64, params: [&f64]),
register_node!(graphene_core::ops::AddParameterNode<_>, input: &f64, params: [&f64]),
register_node!(graphene_core::raster::GrayscaleColorNode, input: Color, params: []),
register_node!(graphene_core::raster::BrightenColorNode<_>, input: Color, params: [f32]),
register_node!(graphene_core::raster::HueShiftColorNode<_>, input: Color, params: [f32]),
(NodeIdentifier::new("graphene_core::structural::ComposeNode<_, _, _>", &[generic!("T"), generic!("U")]), |args| {
let node = ComposeTypeErased::new(args[0], args[1]);
node.into_type_erased()
}),
(NodeIdentifier::new("graphene_core::ops::IdNode", &[generic!("T")]), |_| IdNode::new().into_type_erased()),
register_node!(graphene_std::raster::GrayscaleNode, input: Image, params: []),
register_node!(graphene_std::raster::InvertRGBNode, input: Image, params: []),
(NodeIdentifier::new("graphene_core::structural::MapImageNode", &[]), |args| {
let map_fn: DowncastBothNode<Color, Color> = DowncastBothNode::new(args[0]);
let node = graphene_std::raster::MapImageNode::new(ValueNode::new(map_fn));
let any: DynAnyNode<Image, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
any.into_type_erased()
}),
register_node!(graphene_std::raster::HueSaturationNode<_, _, _>, input: Image, params: [f64, f64, f64]),
register_node!(graphene_std::raster::BrightnessContrastNode< _, _>, input: Image, params: [f64, f64]),
register_node!(graphene_std::raster::GammaNode<_>, input: Image, params: [f64]),
register_node!(graphene_std::raster::OpacityNode<_>, input: Image, params: [f64]),
register_node!(graphene_std::raster::PosterizeNode<_>, input: Image, params: [f64]),
register_node!(graphene_std::raster::ExposureNode<_>, input: Image, params: [f64]),
(
NodeIdentifier::new("graphene_core::structural::ConsNode", &[concrete!("&u32"), concrete!("&u32")]),
|proto_node, stack| {
let node_id = proto_node.input.unwrap_node() as usize;
if let ConstructionArgs::Nodes(cons_node_arg) = proto_node.construction_args {
stack.push_fn(move |nodes| {
let pre_node = nodes.get(node_id).unwrap();
let cons_node_arg = nodes.get(cons_node_arg[0] as usize).unwrap();
let cons_node = ConsNode::new(DowncastNode::<_, &u32>::new(cons_node_arg));
let node: DynAnyNode<_, &u32, _, _> = DynAnyNode::new(cons_node);
let node = (pre_node).then(node);
node.into_type_erased()
})
} else {
unimplemented!()
}
NodeIdentifier::new("graphene_std::raster::ImaginateNode<_>", &[concrete!("Image"), concrete!("Option<std::sync::Arc<Image>>")]),
|args| {
let cached = graphene_std::any::input_node::<Option<std::sync::Arc<Image>>>(args[15]);
let node = graphene_std::raster::ImaginateNode::new(cached);
let any = DynAnyNode::new(ValueNode::new(node));
any.into_type_erased()
},
),
(NodeIdentifier::new("graphene_core::any::DowncastNode", &[concrete!("&u32")]), |proto_node, stack| {
stack.push_fn(|nodes| {
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
let node = pre_node.then(graphene_core::ops::IdNode);
node.into_type_erased()
})
}),
(NodeIdentifier::new("graphene_core::value::ValueNode", &[concrete!("Any<'>")]), |proto_node, stack| {
stack.push_fn(|_nodes| {
if let ConstructionArgs::Value(value) = proto_node.construction_args {
let node = FnNode::new(move |_| value.clone().up_box() as Any<'static>);
(NodeIdentifier::new("graphene_core::raster::BlurNode", &[concrete!("Image")]), |args| {
let radius = DowncastBothNode::<(), u32>::new(args[0]);
let sigma = DowncastBothNode::<(), f64>::new(args[1]);
let image = DowncastBothRefNode::<Image, Image>::new(args[2]);
let empty_image: ValueNode<Image> = ValueNode::new(Image::empty());
let empty: TypeNode<_, (), Image> = TypeNode::new(empty_image.then(CloneNode::new()));
//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 node: DynAnyNode<&Image, _, _> = DynAnyNode::new(ValueNode::new(new_image));
node.into_type_erased()
}),
//register_node!(graphene_std::memo::CacheNode<_>, input: Image, params: []),
(NodeIdentifier::new("graphene_std::memo::CacheNode", &[concrete!("Image")]), |_| {
let node: CacheNode<Image> = graphene_std::memo::CacheNode::new();
let any = graphene_std::any::DynAnyRefNode::new(node);
any.into_type_erased()
}),
register_node!(graphene_core::structural::ConsNode<_, _>, input: Image, params: [&str]),
/*
(NodeIdentifier::new("graphene_std::raster::ImageNode", &[concrete!("&str")]), |_proto_node, stack| {
stack.push_fn(|_nodes| {
let image = FnNode::new(|s: &str| graphene_std::raster::image_node::<&str>().eval(s).unwrap());
let node: DynAnyNode<_, &str, _, _> = DynAnyNode::new(image);
node.into_type_erased()
} else {
unreachable!()
}
})
}),
(NodeIdentifier::new("graphene_core::value::ValueNode", &[generic!("T")]), |proto_node, stack| {
stack.push_fn(|_nodes| {
if let ConstructionArgs::Value(value) = proto_node.construction_args {
let node = FnNode::new(move |_| value.clone().up_box() as Any<'static>);
node.into_type_erased()
} else {
unreachable!()
}
})
}),
(NodeIdentifier::new("graphene_core::raster::GrayscaleColorNode", &[]), |proto_node, stack| {
stack.push_fn(|nodes| {
let node = DynAnyNode::new(graphene_core::raster::GrayscaleColorNode);
if let ProtoNodeInput::Node(pre_id) = proto_node.input {
let pre_node = nodes.get(pre_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
node.into_type_erased()
}
})
}),
(NodeIdentifier::new("graphene_core::raster::BrightenColorNode", &[concrete!("&TypeErasedNode")]), |proto_node, stack| {
stack.push_fn(|nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("Brighten Color Node constructed with out brightness input node") };
let value_node = nodes.get(construction_nodes[0] as usize).unwrap();
let input_node: DowncastBothNode<_, (), f32> = DowncastBothNode::new(value_node);
let node = DynAnyNode::new(graphene_core::raster::BrightenColorNode::new(input_node));
if let ProtoNodeInput::Node(pre_id) = proto_node.input {
let pre_node = nodes.get(pre_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
node.into_type_erased()
}
})
}),
(NodeIdentifier::new("graphene_core::raster::HueShiftColorNode", &[concrete!("&TypeErasedNode")]), |proto_node, stack| {
info!("proto node {:?}", proto_node);
stack.push_fn(|nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("Hue Shift Color Node constructed with out shift input node") };
let value_node = nodes.get(construction_nodes[0] as usize).unwrap();
let input_node: DowncastBothNode<_, (), f32> = DowncastBothNode::new(value_node);
let node = DynAnyNode::new(graphene_core::raster::HueShiftColorNode::new(input_node));
if let ProtoNodeInput::Node(pre_id) = proto_node.input {
let pre_node = nodes.get(pre_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
node.into_type_erased()
}
})
}),
#[cfg(feature = "gpu")]
(
NodeIdentifier::new("graphene_std::executor::MapGpuNode", &[concrete!("&TypeErasedNode"), concrete!("Color"), concrete!("Color")]),
|proto_node, stack| {
if let ConstructionArgs::Nodes(operation_node_id) = proto_node.construction_args {
stack.push_fn(move |nodes| {
info!("Map image Depending upon id {:?}", operation_node_id);
let operation_node = nodes.get(operation_node_id[0] as usize).unwrap();
let input_node: DowncastBothNode<_, (), &graph_craft::document::NodeNetwork> = DowncastBothNode::new(operation_node);
let map_node: graphene_std::executor::MapGpuNode<_, Vec<u32>, u32, u32> = graphene_std::executor::MapGpuNode::new(input_node);
let map_node = DynAnyNode::new(map_node);
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(map_node).into_type_erased()
} else {
map_node.into_type_erased()
}
})
} else {
unimplemented!()
}
},
),
#[cfg(feature = "gpu")]
(
NodeIdentifier::new("graphene_std::executor::MapGpuSingleImageNode", &[concrete!("&TypeErasedNode")]),
|proto_node, stack| {
if let ConstructionArgs::Nodes(operation_node_id) = proto_node.construction_args {
stack.push_fn(move |nodes| {
info!("Map image Depending upon id {:?}", operation_node_id);
let operation_node = nodes.get(operation_node_id[0] as usize).unwrap();
let input_node: DowncastBothNode<_, (), String> = DowncastBothNode::new(operation_node);
let map_node = graphene_std::executor::MapGpuSingleImageNode(input_node);
let map_node = DynAnyNode::new(map_node);
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(map_node).into_type_erased()
} else {
map_node.into_type_erased()
}
})
} else {
unimplemented!()
}
},
),
#[cfg(feature = "quantization")]
(
NodeIdentifier::new("graphene_std::quantization::GenerateQuantizationNode", &[concrete!("&TypeErasedNode")]),
|proto_node, stack| {
if let ConstructionArgs::Nodes(operation_node_id) = proto_node.construction_args {
stack.push_fn(move |nodes| {
info!("Quantization Depending upon id {:?}", operation_node_id);
let samples_node = nodes.get(operation_node_id[0] as usize).unwrap();
let index_node = nodes.get(operation_node_id[1] as usize).unwrap();
let samples_node: DowncastBothNode<_, (), u32> = DowncastBothNode::new(samples_node);
let index_node: DowncastBothNode<_, (), u32> = DowncastBothNode::new(index_node);
let map_node = graphene_std::quantization::GenerateQuantizationNode::new(samples_node, index_node);
let map_node = DynAnyNode::new(map_node);
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(map_node).into_type_erased()
} else {
map_node.into_type_erased()
}
})
} else {
unimplemented!()
}
},
),
(NodeIdentifier::new("graphene_std::raster::MapImageNode", &[]), |proto_node, stack| {
if let ConstructionArgs::Nodes(operation_node_id) = proto_node.construction_args {
stack.push_fn(move |nodes| {
let operation_node = nodes.get(operation_node_id[0] as usize).unwrap();
let operation_node: DowncastBothNode<_, Color, Color> = DowncastBothNode::new(operation_node);
let map_node = DynAnyNode::new(graphene_std::raster::MapImageNode::new(operation_node));
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(map_node).into_type_erased()
} else {
map_node.into_type_erased()
}
})
} else {
unimplemented!()
}
}),
(NodeIdentifier::new("graphene_std::raster::GrayscaleNode", &[]), |proto_node, stack| {
stack.push_fn(move |nodes| {
let node = DynAnyNode::new(graphene_std::raster::GrayscaleNode);
}),
(NodeIdentifier::new("graphene_std::raster::ExportImageNode", &[concrete!("&str")]), |proto_node, stack| {
stack.push_fn(|nodes| {
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
let image = FnNode::new(|input: (Image, &str)| graphene_std::raster::export_image_node().eval(input).unwrap());
let node: DynAnyNode<_, (Image, &str), _, _> = DynAnyNode::new(image);
let node = (pre_node).then(node);
node.into_type_erased()
}
})
}),
(NodeIdentifier::new("graphene_std::raster::InvertRGBNode", &[]), |proto_node, stack| {
stack.push_fn(move |nodes| {
let node = DynAnyNode::new(graphene_std::raster::InvertRGBNode);
})
}),
(
NodeIdentifier::new("graphene_core::structural::ConsNode", &[concrete!("Image"), concrete!("&str")]),
|proto_node, stack| {
let node_id = proto_node.input.unwrap_node() as usize;
if let ConstructionArgs::Nodes(cons_node_arg) = proto_node.construction_args {
stack.push_fn(move |nodes| {
let pre_node = nodes.get(node_id).unwrap();
let cons_node_arg = nodes.get(cons_node_arg[0] as usize).unwrap();
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
node.into_type_erased()
}
})
}),
(NodeIdentifier::new("graphene_std::raster::HueSaturationNode", &[concrete!("&TypeErasedNode")]), |proto_node, stack| {
stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("HueSaturationNode Node constructed without inputs") };
let hue: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap());
let saturation: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[1] as usize).unwrap());
let lightness: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[2] as usize).unwrap());
let node = DynAnyNode::new(graphene_std::raster::HueSaturationNode::new(hue, saturation, lightness));
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
node.into_type_erased()
}
})
}),
(
NodeIdentifier::new("graphene_std::raster::BrightnessContrastNode", &[concrete!("&TypeErasedNode")]),
|proto_node, stack| {
let cons_node = ConsNode::new(DowncastNode::<_, &str>::new(cons_node_arg));
let node: DynAnyNode<_, Image, _, _> = DynAnyNode::new(cons_node);
let node = (pre_node).then(node);
node.into_type_erased()
})
} else {
unimplemented!()
}
},
),
(NodeIdentifier::new("graphene_std::vector::generator_nodes::UnitCircleGenerator", &[]), |_proto_node, stack| {
stack.push_fn(|_nodes| DynAnyNode::new(graphene_std::vector::generator_nodes::UnitCircleGenerator).into_type_erased())
}),
(NodeIdentifier::new("graphene_std::vector::generator_nodes::UnitSquareGenerator", &[]), |_proto_node, stack| {
stack.push_fn(|_nodes| DynAnyNode::new(graphene_std::vector::generator_nodes::UnitSquareGenerator).into_type_erased())
}),
(NodeIdentifier::new("graphene_std::vector::generator_nodes::BlitSubpath", &[]), |proto_node, stack| {
stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("BrightnessContrastNode Node constructed without inputs") };
let brightness: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap());
let contrast: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[1] as usize).unwrap());
let node = DynAnyNode::new(graphene_std::raster::BrightnessContrastNode::new(brightness, contrast));
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("BlitSubpath without subpath input") };
let value_node = nodes.get(construction_nodes[0] as usize).unwrap();
let input_node: DowncastBothNode<_, (), Subpath> = DowncastBothNode::new(value_node);
let node = DynAnyNode::new(graphene_std::vector::generator_nodes::BlitSubpath::new(input_node));
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
@ -371,227 +171,112 @@ static NODE_REGISTRY: &[(NodeIdentifier, NodeConstructor)] = &[
node.into_type_erased()
}
})
},
),
(NodeIdentifier::new("graphene_std::raster::GammaNode", &[concrete!("&TypeErasedNode")]), |proto_node, stack| {
stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("GammaNode Node constructed without inputs") };
let gamma: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap());
let node = DynAnyNode::new(graphene_std::raster::GammaNode::new(gamma));
}),
(NodeIdentifier::new("graphene_std::vector::generator_nodes::TransformSubpathNode", &[]), |proto_node, stack| {
stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("TransformSubpathNode without subpath input") };
let translate_node: DowncastBothNode<_, (), DVec2> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap());
let rotate_node: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[1] as usize).unwrap());
let scale_node: DowncastBothNode<_, (), DVec2> = DowncastBothNode::new(nodes.get(construction_nodes[2] as usize).unwrap());
let shear_node: DowncastBothNode<_, (), DVec2> = DowncastBothNode::new(nodes.get(construction_nodes[3] as usize).unwrap());
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
node.into_type_erased()
}
})
}),
(NodeIdentifier::new("graphene_std::raster::OpacityNode", &[concrete!("&TypeErasedNode")]), |proto_node, stack| {
stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("OpacityNode Node constructed without inputs") };
let opacity: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap());
let node = DynAnyNode::new(graphene_std::raster::OpacityNode::new(opacity));
let node = DynAnyNode::new(graphene_std::vector::generator_nodes::TransformSubpathNode::new(translate_node, rotate_node, scale_node, shear_node));
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
node.into_type_erased()
}
})
}),
(NodeIdentifier::new("graphene_std::raster::PosterizeNode", &[concrete!("&TypeErasedNode")]), |proto_node, stack| {
stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("Posterize node constructed without inputs") };
let value: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap());
let node = DynAnyNode::new(graphene_std::raster::PosterizeNode::new(value));
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
node.into_type_erased()
}
})
}),
(NodeIdentifier::new("graphene_std::raster::ExposureNode", &[concrete!("&TypeErasedNode")]), |proto_node, stack| {
stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("ExposureNode constructed without inputs") };
let value: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap());
let node = DynAnyNode::new(graphene_std::raster::ExposureNode::new(value));
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
node.into_type_erased()
}
})
}),
(NodeIdentifier::new("graphene_std::raster::ImaginateNode", &[concrete!("&TypeErasedNode")]), |proto_node, stack| {
stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("ImaginateNode constructed without inputs") };
let value: DowncastBothNode<_, (), Option<std::sync::Arc<graphene_core::raster::Image>>> = DowncastBothNode::new(nodes.get(construction_nodes[15] as usize).unwrap());
let node = DynAnyNode::new(graphene_std::raster::ImaginateNode::new(value));
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
node.into_type_erased()
}
})
}),
(NodeIdentifier::new("graphene_std::raster::ImageNode", &[concrete!("&str")]), |_proto_node, stack| {
stack.push_fn(|_nodes| {
let image = FnNode::new(|s: &str| graphene_std::raster::image_node::<&str>().eval(s).unwrap());
let node: DynAnyNode<_, &str, _, _> = DynAnyNode::new(image);
node.into_type_erased()
})
}),
(NodeIdentifier::new("graphene_std::raster::ExportImageNode", &[concrete!("&str")]), |proto_node, stack| {
stack.push_fn(|nodes| {
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
let image = FnNode::new(|input: (Image, &str)| graphene_std::raster::export_image_node().eval(input).unwrap());
let node: DynAnyNode<_, (Image, &str), _, _> = DynAnyNode::new(image);
let node = (pre_node).then(node);
node.into_type_erased()
})
}),
(
NodeIdentifier::new("graphene_core::structural::ConsNode", &[concrete!("Image"), concrete!("&str")]),
|proto_node, stack| {
let node_id = proto_node.input.unwrap_node() as usize;
if let ConstructionArgs::Nodes(cons_node_arg) = proto_node.construction_args {
stack.push_fn(move |nodes| {
let pre_node = nodes.get(node_id).unwrap();
let cons_node_arg = nodes.get(cons_node_arg[0] as usize).unwrap();
let cons_node = ConsNode::new(DowncastNode::<_, &str>::new(cons_node_arg));
let node: DynAnyNode<_, Image, _, _> = DynAnyNode::new(cons_node);
let node = (pre_node).then(node);
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
node.into_type_erased()
})
} else {
unimplemented!()
}
},
),
(NodeIdentifier::new("graphene_std::memo::CacheNode", &[concrete!("Image")]), |proto_node, stack| {
let node_id = proto_node.input.unwrap_node() as usize;
use graphene_core::raster::*;
if let ConstructionArgs::Nodes(_image_args) = proto_node.construction_args {
stack.push_fn(move |nodes| {
let image = nodes.get(node_id).unwrap();
let node: DynAnyNode<_, Image, Image, &Image> = DynAnyNode::new(CacheNode::new());
let node = image.then(node);
node.into_type_erased()
}
})
} else {
unimplemented!()
}
}),
(NodeIdentifier::new("graphene_core::raster::BlurNode", &[]), |proto_node, stack| {
let node_id = proto_node.input.unwrap_node() as usize;
use graphene_core::raster::*;
}),
#[cfg(feature = "gpu")]
(
NodeIdentifier::new("graphene_std::executor::MapGpuNode", &[concrete!("&TypeErasedNode"), concrete!("Color"), concrete!("Color")]),
|proto_node, stack| {
if let ConstructionArgs::Nodes(operation_node_id) = proto_node.construction_args {
stack.push_fn(move |nodes| {
info!("Map image Depending upon id {:?}", operation_node_id);
let operation_node = nodes.get(operation_node_id[0] as usize).unwrap();
let input_node: DowncastBothNode<_, (), &graph_craft::document::NodeNetwork> = DowncastBothNode::new(operation_node);
let map_node: graphene_std::executor::MapGpuNode<_, Vec<u32>, u32, u32> = graphene_std::executor::MapGpuNode::new(input_node);
let map_node = DynAnyNode::new(map_node);
static EMPTY_IMAGE: ValueNode<Image> = ValueNode::new(Image::empty());
if let ConstructionArgs::Nodes(blur_args) = proto_node.construction_args {
stack.push_fn(move |nodes| {
let pre_node = nodes.get(node_id).unwrap();
let radius = nodes.get(blur_args[0] as usize).unwrap();
let sigma = nodes.get(blur_args[1] as usize).unwrap();
let radius = DowncastBothNode::<_, (), u32>::new(radius);
let sigma = DowncastBothNode::<_, (), f64>::new(sigma);
let image = DowncastBothNode::<_, Image, &Image>::new(pre_node);
// dirty hack: we abuse that the cache node will ignore the input if it is
// evaluated a second time
let empty: TypeNode<_, (), Image> = TypeNode::new((&EMPTY_IMAGE).then(CloneNode));
let image = empty.then(image).then(ImageRefNode::new());
let window = WindowNode::new(radius, image);
let window: TypeNode<_, u32, ImageWindowIterator<'static>> = TypeNode::new(window);
let map_gaussian = MapSndNode::new(DistanceNode.then(GaussianNode::new(sigma)));
let map_distances = MapNode::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(avg);
let blur = ImageIndexIterNode.then(blur_iter);
let blur: TypeNode<_, ImageSlice<'_>, MapFnIterator<_, _>> = TypeNode::new(blur);
let collect = CollectNode {};
let vec = blur.then(collect);
let vec: TypeNode<_, ImageSlice<'_>, Vec<Color>> = TypeNode::new(vec);
let new_image = MapImageSliceNode::new(vec);
let new_image: TypeNode<_, ImageSlice<'_>, Image> = TypeNode::new(new_image);
let node: DynAnyNode<_, &Image, Image, Image> = DynAnyNode::new(ImageRefNode.then(new_image));
let node = ComposeNode::new(pre_node, node);
node.into_type_erased()
})
} else {
unimplemented!()
}
}),
(NodeIdentifier::new("graphene_std::vector::generator_nodes::UnitCircleGenerator", &[]), |_proto_node, stack| {
stack.push_fn(|_nodes| DynAnyNode::new(graphene_std::vector::generator_nodes::UnitCircleGenerator).into_type_erased())
}),
(NodeIdentifier::new("graphene_std::vector::generator_nodes::UnitSquareGenerator", &[]), |_proto_node, stack| {
stack.push_fn(|_nodes| DynAnyNode::new(graphene_std::vector::generator_nodes::UnitSquareGenerator).into_type_erased())
}),
(NodeIdentifier::new("graphene_std::vector::generator_nodes::BlitSubpath", &[]), |proto_node, stack| {
stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("BlitSubpath without subpath input") };
let value_node = nodes.get(construction_nodes[0] as usize).unwrap();
let input_node: DowncastBothNode<_, (), Subpath> = DowncastBothNode::new(value_node);
let node = DynAnyNode::new(graphene_std::vector::generator_nodes::BlitSubpath::new(input_node));
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(map_node).into_type_erased()
} else {
map_node.into_type_erased()
}
})
} else {
unimplemented!()
}
},
),
#[cfg(feature = "gpu")]
(
NodeIdentifier::new("graphene_std::executor::MapGpuSingleImageNode", &[concrete!("&TypeErasedNode")]),
|proto_node, stack| {
if let ConstructionArgs::Nodes(operation_node_id) = proto_node.construction_args {
stack.push_fn(move |nodes| {
info!("Map image Depending upon id {:?}", operation_node_id);
let operation_node = nodes.get(operation_node_id[0] as usize).unwrap();
let input_node: DowncastBothNode<_, (), String> = DowncastBothNode::new(operation_node);
let map_node = graphene_std::executor::MapGpuSingleImageNode(input_node);
let map_node = DynAnyNode::new(map_node);
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
node.into_type_erased()
}
})
}),
(NodeIdentifier::new("graphene_std::vector::generator_nodes::TransformSubpathNode", &[]), |proto_node, stack| {
stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("TransformSubpathNode without subpath input") };
let translate_node: DowncastBothNode<_, (), DVec2> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap());
let rotate_node: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[1] as usize).unwrap());
let scale_node: DowncastBothNode<_, (), DVec2> = DowncastBothNode::new(nodes.get(construction_nodes[2] as usize).unwrap());
let shear_node: DowncastBothNode<_, (), DVec2> = DowncastBothNode::new(nodes.get(construction_nodes[3] as usize).unwrap());
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(map_node).into_type_erased()
} else {
map_node.into_type_erased()
}
})
} else {
unimplemented!()
}
},
),
#[cfg(feature = "quantization")]
(
NodeIdentifier::new("graphene_std::quantization::GenerateQuantizationNode", &[concrete!("&TypeErasedNode")]),
|proto_node, stack| {
if let ConstructionArgs::Nodes(operation_node_id) = proto_node.construction_args {
stack.push_fn(move |nodes| {
info!("Quantization Depending upon id {:?}", operation_node_id);
let samples_node = nodes.get(operation_node_id[0] as usize).unwrap();
let index_node = nodes.get(operation_node_id[1] as usize).unwrap();
let samples_node: DowncastBothNode<_, (), u32> = DowncastBothNode::new(samples_node);
let index_node: DowncastBothNode<_, (), u32> = DowncastBothNode::new(index_node);
let map_node = graphene_std::quantization::GenerateQuantizationNode::new(samples_node, index_node);
let map_node = DynAnyNode::new(map_node);
let node = DynAnyNode::new(graphene_std::vector::generator_nodes::TransformSubpathNode::new(translate_node, rotate_node, scale_node, shear_node));
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(node).into_type_erased()
} else {
node.into_type_erased()
}
})
}),
if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap();
(pre_node).then(map_node).into_type_erased()
} else {
map_node.into_type_erased()
}
})
} else {
unimplemented!()
}
},
),
<<<<<<< HEAD
*/
];
pub fn push_node(proto_node: ProtoNode, stack: &FixedSizeStack<TypeErasedNode<'static>>) {
if let Some((_id, f)) = NODE_REGISTRY.iter().find(|(id, _)| *id == proto_node.identifier) {
f(proto_node, stack);
pub fn constrcut_node<'a>(ident: NodeIdentifier, construction_args: Vec<TypeErasedPinnedRef<'static>>) -> TypeErasedPinned<'a> {
if let Some((_id, f)) = NODE_REGISTRY.iter().find(|(id, _)| *id == ident) {
f(construction_args)
} else {
let other_types = NODE_REGISTRY
.iter()
.map(|(id, _)| id)
.filter(|id| id.name.as_ref() == proto_node.identifier.name.as_ref())
.collect::<Vec<_>>();
panic!(
"NodeImplementation: {:?} not found in Registry. Types for which the node is implemented:\n {:#?}",
proto_node.identifier, other_types
);
let other_types = NODE_REGISTRY.iter().map(|(id, _)| id).filter(|id| id.name.as_ref() == ident.name.as_ref()).collect::<Vec<_>>();
panic!("NodeImplementation: {:?} not found in Registry. Types for which the node is implemented:\n {:#?}", ident, other_types);
}
}
/*
#[cfg(test)]
mod protograph_testing {
use borrow_stack::BorrowStack;
@ -602,24 +287,24 @@ mod protograph_testing {
fn add_values() {
let stack = FixedSizeStack::new(256);
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(Box::new(2u32)));
push_node(val_1_protonode, &stack);
constrcut_node(val_1_protonode, &stack);
let val_2_protonode = ProtoNode::value(ConstructionArgs::Value(Box::new(40u32)));
push_node(val_2_protonode, &stack);
constrcut_node(val_2_protonode, &stack);
let cons_protonode = ProtoNode {
construction_args: ConstructionArgs::Nodes(vec![1]),
input: ProtoNodeInput::Node(0),
identifier: NodeIdentifier::new("graphene_core::structural::ConsNode", &[concrete!("u32"), concrete!("u32")]),
};
push_node(cons_protonode, &stack);
constrcut_node(cons_protonode, &stack);
let add_protonode = ProtoNode {
construction_args: ConstructionArgs::Nodes(vec![]),
input: ProtoNodeInput::Node(2),
identifier: NodeIdentifier::new("graphene_core::ops::AddNode", &[concrete!("u32"), concrete!("u32")]),
};
push_node(add_protonode, &stack);
constrcut_node(add_protonode, &stack);
let result = unsafe { stack.get()[3].eval(Box::new(())) };
let val = *dyn_any::downcast::<u32>(result).unwrap();
@ -630,14 +315,14 @@ mod protograph_testing {
fn grayscale_color() {
let stack = FixedSizeStack::new(256);
let val_protonode = ProtoNode::value(ConstructionArgs::Value(Box::new(Color::from_rgb8(10, 20, 30))));
push_node(val_protonode, &stack);
constrcut_node(val_protonode, &stack);
let grayscale_protonode = ProtoNode {
construction_args: ConstructionArgs::Nodes(vec![]),
input: ProtoNodeInput::Node(0),
identifier: NodeIdentifier::new("graphene_core::raster::GrayscaleColorNode", &[]),
};
push_node(grayscale_protonode, &stack);
constrcut_node(grayscale_protonode, &stack);
let result = unsafe { stack.get()[1].eval(Box::new(())) };
let val = *dyn_any::downcast::<Color>(result).unwrap();
@ -652,7 +337,7 @@ mod protograph_testing {
input: ProtoNodeInput::None,
identifier: NodeIdentifier::new("graphene_std::raster::ImageNode", &[concrete!("&str")]),
};
push_node(image_protonode, &stack);
constrcut_node(image_protonode, &stack);
let result = unsafe { stack.get()[0].eval(Box::new("../gstd/test-image-1.png")) };
let image = *dyn_any::downcast::<Image>(result).unwrap();
@ -667,24 +352,25 @@ mod protograph_testing {
input: ProtoNodeInput::None,
identifier: NodeIdentifier::new("graphene_std::raster::ImageNode", &[concrete!("&str")]),
};
push_node(image_protonode, &stack);
constrcut_node(image_protonode, &stack);
let grayscale_protonode = ProtoNode {
construction_args: ConstructionArgs::Nodes(vec![]),
input: ProtoNodeInput::None,
identifier: NodeIdentifier::new("graphene_core::raster::GrayscaleColorNode", &[]),
};
push_node(grayscale_protonode, &stack);
constrcut_node(grayscale_protonode, &stack);
let image_map_protonode = ProtoNode {
construction_args: ConstructionArgs::Nodes(vec![1]),
input: ProtoNodeInput::Node(0),
identifier: NodeIdentifier::new("graphene_std::raster::MapImageNode", &[]),
};
push_node(image_map_protonode, &stack);
constrcut_node(image_map_protonode, &stack);
let result = unsafe { stack.get()[2].eval(Box::new("../gstd/test-image-1.png")) };
let image = *dyn_any::downcast::<Image>(result).unwrap();
assert!(!image.data.iter().any(|c| c.r() != c.b() || c.b() != c.g()));
}
}
*/

View file

@ -17,4 +17,5 @@ proc-macro = true
[dependencies]
syn = { version = "1.0", features = ["full"] }
proc-macro2 = "1.0"
quote = "1.0"

View file

@ -1,15 +1,45 @@
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::{format_ident, ToTokens};
use syn::{parse_macro_input, FnArg, Ident, ItemFn, Pat, PatIdent, ReturnType};
use syn::{
parse_macro_input, punctuated::Punctuated, token::Comma, FnArg, GenericParam, Ident, ItemFn, Lifetime, Pat, PatIdent, PathArguments, PredicateType, ReturnType, Token, TraitBound, Type, TypeParam,
TypeParamBound, WhereClause, WherePredicate,
};
#[proc_macro_attribute]
pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
let node_name = parse_macro_input!(attr as Ident);
//let node_name = parse_macro_input!(attr as Ident);
let node = parse_macro_input!(attr as syn::PathSegment);
let function = parse_macro_input!(item as ItemFn);
let function_name = &function.sig.ident;
let node = &node;
let node_name = &node.ident;
let mut args = match node.arguments.clone() {
PathArguments::AngleBracketed(args) => args
.args
.into_iter()
.map(|arg| match arg {
syn::GenericArgument::Type(ty) => ty,
_ => panic!("Only types are allowed as arguments"),
})
.collect::<Vec<_>>(),
_ => Default::default(),
};
let arg_idents = args
.iter()
.filter(|x| x.to_token_stream().to_string().starts_with('_'))
.map(|arg| Ident::new(arg.to_token_stream().to_string().to_lowercase().as_str(), Span::call_site()))
.collect::<Vec<_>>();
let mut function_inputs = function.sig.inputs.iter().filter_map(|arg| if let FnArg::Typed(typed_arg) = arg { Some(typed_arg) } else { None });
let mut type_generics = function.sig.generics.params.clone();
let mut where_clause = function.sig.generics.where_clause.clone().unwrap_or(WhereClause {
where_token: Token![where](Span::call_site()),
predicates: Default::default(),
});
// Extract primary input as first argument
let primary_input = function_inputs.next().expect("Primary input required - set to `()` if not needed.");
let Pat::Ident(PatIdent{ident: primary_input_ident,..} ) =&*primary_input.pat else {
@ -17,9 +47,11 @@ pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
};
let primary_input_ty = &primary_input.ty;
let body = function.block;
// Extract secondary inputs as all other arguments
let secondary_inputs = function_inputs.collect::<Vec<_>>();
let secondary_idents = secondary_inputs
let parameter_inputs = function_inputs.collect::<Vec<_>>();
let parameter_idents = parameter_inputs
.iter()
.map(|input| {
let Pat::Ident(PatIdent { ident: primary_input_ident,.. }) = &*input.pat else { panic!("Expected ident for secondary input."); };
@ -34,50 +66,88 @@ pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
quote::quote!(())
};
let struct_generics = (0..parameter_inputs.len())
.map(|x| {
let ident = format_ident!("S{x}");
ident
})
.collect::<Punctuated<_, Comma>>();
let struct_generics_iter = struct_generics.iter();
for ident in struct_generics.iter() {
args.push(Type::Verbatim(quote::quote!(#ident)));
}
// Generics are simply `S0` through to `Sn-1` where n is the number of secondary inputs
let generics = (0..secondary_inputs.len()).map(|x| format_ident!("S{x}")).collect::<Vec<_>>();
// Bindings for all of the above generics to a node with an input of `()` and an output of the type in the function
let where_clause = secondary_inputs
let node_generics = struct_generics
.iter()
.zip(&generics)
.cloned()
.map(|ident| {
GenericParam::Type(TypeParam {
attrs: vec![],
ident,
colon_token: Some(Default::default()),
bounds: Punctuated::from_iter([TypeParamBound::Lifetime(Lifetime::new("'input", Span::call_site()))].iter().cloned()),
eq_token: None,
default: None,
})
})
.collect::<Punctuated<_, Comma>>();
type_generics.iter_mut().for_each(|x| {
if let GenericParam::Type(t) = x {
t.bounds.insert(0, TypeParamBound::Lifetime(Lifetime::new("'input", Span::call_site())));
}
});
let generics = type_generics.into_iter().chain(node_generics.iter().cloned()).collect::<Punctuated<_, Comma>>();
// Bindings for all of the above generics to a node with an input of `()` and an output of the type in the function
let extra_where_clause = parameter_inputs
.iter()
.zip(&node_generics)
.map(|(ty, name)| {
let ty = &ty.ty;
quote::quote!(#name: Node<(), Output = #ty>)
let GenericParam::Type(generic_ty) = name else { panic!("Expected type generic."); };
let ident = &generic_ty.ident;
WherePredicate::Type(PredicateType {
lifetimes: None,
bounded_ty: Type::Verbatim(ident.to_token_stream()),
colon_token: Default::default(),
bounds: Punctuated::from_iter([TypeParamBound::Trait(TraitBound {
paren_token: None,
modifier: syn::TraitBoundModifier::None,
lifetimes: syn::parse_quote!(for<'any_input>),
path: syn::parse_quote!(Node<'any_input, (), Output = #ty>),
})]),
})
})
.collect::<Vec<_>>();
where_clause.predicates.extend(extra_where_clause);
quote::quote! {
#function
impl <#(#generics),*> Node<#primary_input_ty> for #node_name<#(#generics),*>
where
#(#where_clause),* {
impl <'input, #generics> Node<'input, #primary_input_ty> for #node_name<#(#args),*>
#where_clause
{
type Output = #output;
fn eval(self, #primary_input_ident: #primary_input_ty) -> #output{
#function_name(#primary_input_ident #(, self.#secondary_idents.eval(()))*)
#[inline]
fn eval<'node: 'input>(&'node self, #primary_input_ident: #primary_input_ty) -> Self::Output {
#(
let #parameter_idents = self.#parameter_idents.eval(());
)*
#body
}
}
impl <#(#generics),*> Node<#primary_input_ty> for &#node_name<#(#generics),*>
where
#(#where_clause + Copy),* {
type Output = #output;
fn eval(self, #primary_input_ident: #primary_input_ty) -> #output{
#function_name(#primary_input_ident #(, self.#secondary_idents.eval(()))*)
}
}
impl <#(#generics),*> #node_name<#(#generics),*>
where
#(#where_clause + Copy),* {
pub fn new(#(#secondary_idents: #generics),*) -> Self{
Self{
#(#secondary_idents),*
}
impl <#(#args),*> #node_name<#(#args),*>
{
pub const fn new(#(#parameter_idents: #struct_generics_iter),*) -> Self{
Self{
#(#parameter_idents,)*
#(#arg_idents: core::marker::PhantomData,)*
}
}
}
}
.into()
}

View file

@ -38,7 +38,7 @@ impl<I: StaticTypeSized, O> GpuExecutor<I, O> {
}
impl<I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync + Pod> Executor for GpuExecutor<I, O> {
fn execute(&self, input: Any<'static>) -> Result<Any<'static>, Box<dyn std::error::Error>> {
fn execute<'i, 's: 'i>(&'s self, input: Any<'i>) -> Result<Any<'i>, Box<dyn std::error::Error>> {
let input = dyn_any::downcast::<Vec<I>>(input).expect("Wrong input type");
let context = &self.context;
let result: Vec<O> = execute_shader(

View file

@ -27,7 +27,7 @@ impl<'a, I: StaticTypeSized, O> GpuExecutor<'a, I, O> {
}
impl<'a, I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync + Pod> Executor for GpuExecutor<'a, I, O> {
fn execute(&self, input: Any<'static>) -> Result<Any<'static>, Box<dyn std::error::Error>> {
fn execute<'i, 's: 'i>(&'s self, input: Any<'i>) -> Result<Any<'i>, Box<dyn std::error::Error>> {
let input = dyn_any::downcast::<Vec<I>>(input).expect("Wrong input type");
let context = &self.context;
let future = execute_shader(context.device.clone(), context.queue.clone(), self.shader.to_vec(), *input, self.entry_point.clone());