Make the dynamic node graph execution asynchronous (#1218)

* Make node graph execution async

Make node macro generate async node implementations

Start propagating async through the node system

Async checkpoint

Make Any<'i> Send + Sync

Determine node io type using panic node

Fix types for raster_node macro

Finish porting node registry?

Fix lifetime errors

Remove Send + Sync requirements and start making node construction async

Async MVP

Fix tests

Clippy fix

* Fix nodes

* Simplify lifetims for node macro + make node macro more modular

* Reenable more nodes

* Fix pasting images

* Remove http test from brush node

* Fix output type for cache node

* Fix types for let scope

* Fix formatting
This commit is contained in:
Dennis Kobert 2023-05-27 11:48:57 +02:00 committed by Keavon Chambers
parent 5c7211cb30
commit 4bd9fbd073
40 changed files with 834 additions and 471 deletions

4
Cargo.lock generated
View file

@ -1659,6 +1659,7 @@ dependencies = [
"compilation-client", "compilation-client",
"dyn-any", "dyn-any",
"dyn-clone", "dyn-clone",
"futures",
"glam", "glam",
"gpu-compiler-bin-wrapper", "gpu-compiler-bin-wrapper",
"gpu-executor", "gpu-executor",
@ -1671,6 +1672,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"reqwest",
"serde", "serde",
"serde_json", "serde_json",
"syn 1.0.109", "syn 1.0.109",
@ -2140,6 +2142,7 @@ dependencies = [
"borrow_stack", "borrow_stack",
"dyn-any", "dyn-any",
"dyn-clone", "dyn-clone",
"futures",
"glam", "glam",
"graph-craft", "graph-craft",
"graphene-core", "graphene-core",
@ -2148,6 +2151,7 @@ dependencies = [
"num-traits", "num-traits",
"once_cell", "once_cell",
"serde", "serde",
"tokio",
] ]
[[package]] [[package]]

View file

@ -1505,7 +1505,7 @@ impl DocumentMessageHandler {
/// When working with an insert index, deleting the layers may cause the insert index to point to a different location (if the layer being deleted was located before the insert index). /// When working with an insert index, deleting the layers may cause the insert index to point to a different location (if the layer being deleted was located before the insert index).
/// ///
/// This function updates the insert index so that it points to the same place after the specified `layers` are deleted. /// This function updates the insert index so that it points to the same place after the specified `layers` are deleted.
fn update_insert_index<'a>(&self, layers: &[&'a [LayerId]], path: &[LayerId], insert_index: isize, reverse_index: bool) -> Result<isize, DocumentError> { fn update_insert_index(&self, layers: &[&[LayerId]], path: &[LayerId], insert_index: isize, reverse_index: bool) -> Result<isize, DocumentError> {
let folder = self.document_legacy.folder(path)?; let folder = self.document_legacy.folder(path)?;
let insert_index = if reverse_index { folder.layer_ids.len() as isize - insert_index } else { insert_index }; let insert_index = if reverse_index { folder.layer_ids.len() as isize - insert_index } else { insert_index };
let layer_ids_above = if insert_index < 0 { &folder.layer_ids } else { &folder.layer_ids[..(insert_index as usize)] }; let layer_ids_above = if insert_index < 0 { &folder.layer_ids } else { &folder.layer_ids[..(insert_index as usize)] };

View file

@ -96,7 +96,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
vec![ vec![
DocumentNodeType { DocumentNodeType {
name: "Identity", name: "Identity",
category: "General", category: "Structural",
identifier: NodeImplementation::proto("graphene_core::ops::IdNode"), identifier: NodeImplementation::proto("graphene_core::ops::IdNode"),
inputs: vec![DocumentInputType { inputs: vec![DocumentInputType {
name: "In", name: "In",
@ -108,7 +108,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
}, },
DocumentNodeType { DocumentNodeType {
name: "Monitor", name: "Monitor",
category: "General", category: "Structural",
identifier: NodeImplementation::proto("graphene_core::ops::IdNode"), identifier: NodeImplementation::proto("graphene_core::ops::IdNode"),
inputs: vec![DocumentInputType { inputs: vec![DocumentInputType {
name: "In", name: "In",
@ -186,7 +186,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
category: "Ignore", category: "Ignore",
identifier: NodeImplementation::DocumentNode(NodeNetwork { identifier: NodeImplementation::DocumentNode(NodeNetwork {
inputs: vec![0], inputs: vec![0],
outputs: vec![NodeOutput::new(2, 0)], outputs: vec![NodeOutput::new(1, 0)],
nodes: [ nodes: [
DocumentNode { DocumentNode {
name: "Downres".to_string(), name: "Downres".to_string(),
@ -200,12 +200,13 @@ fn static_nodes() -> Vec<DocumentNodeType> {
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")), implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
..Default::default() ..Default::default()
}, },
DocumentNode { // We currently just clone by default
/*DocumentNode {
name: "Clone".to_string(), name: "Clone".to_string(),
inputs: vec![NodeInput::node(1, 0)], inputs: vec![NodeInput::node(1, 0)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")), implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")),
..Default::default() ..Default::default()
}, },*/
] ]
.into_iter() .into_iter()
.enumerate() .enumerate()
@ -263,10 +264,10 @@ fn static_nodes() -> Vec<DocumentNodeType> {
}, },
DocumentNodeType { DocumentNodeType {
name: "Begin Scope", name: "Begin Scope",
category: "Structural", category: "Ignore",
identifier: NodeImplementation::DocumentNode(NodeNetwork { identifier: NodeImplementation::DocumentNode(NodeNetwork {
inputs: vec![0, 2], inputs: vec![0, 2],
outputs: vec![NodeOutput::new(1, 0), NodeOutput::new(3, 0)], outputs: vec![NodeOutput::new(1, 0), NodeOutput::new(2, 0)],
nodes: [ nodes: [
DocumentNode { DocumentNode {
name: "SetNode".to_string(), name: "SetNode".to_string(),
@ -286,12 +287,6 @@ fn static_nodes() -> Vec<DocumentNodeType> {
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::RefNode<_, _>")), implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::RefNode<_, _>")),
..Default::default() ..Default::default()
}, },
DocumentNode {
name: "CloneNode".to_string(),
inputs: vec![NodeInput::node(2, 0)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")),
..Default::default()
},
] ]
.into_iter() .into_iter()
.enumerate() .enumerate()
@ -319,7 +314,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
}, },
DocumentNodeType { DocumentNodeType {
name: "End Scope", name: "End Scope",
category: "Structural", category: "Ignore",
identifier: NodeImplementation::proto("graphene_std::memo::EndLetNode<_>"), identifier: NodeImplementation::proto("graphene_std::memo::EndLetNode<_>"),
inputs: vec![ inputs: vec![
DocumentInputType { DocumentInputType {
@ -596,7 +591,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
}, },
DocumentNodeType { DocumentNodeType {
name: "Gaussian Blur", name: "Gaussian Blur",
category: "Image Filters", category: "Ignore",
identifier: NodeImplementation::DocumentNode(NodeNetwork { identifier: NodeImplementation::DocumentNode(NodeNetwork {
inputs: vec![0, 1, 1], inputs: vec![0, 1, 1],
outputs: vec![NodeOutput::new(1, 0)], outputs: vec![NodeOutput::new(1, 0)],

View file

@ -24,7 +24,7 @@ struct ManipulatorGroupOverlays {
pub out_line: Option<Vec<LayerId>>, pub out_line: Option<Vec<LayerId>>,
} }
impl ManipulatorGroupOverlays { impl ManipulatorGroupOverlays {
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a Option<Vec<LayerId>>> { pub fn iter(&self) -> impl Iterator<Item = &'_ Option<Vec<LayerId>>> {
[&self.anchor, &self.in_handle, &self.in_line, &self.out_handle, &self.out_line].into_iter() [&self.anchor, &self.in_handle, &self.in_line, &self.out_handle, &self.out_line].into_iter()
} }
} }

View file

@ -145,7 +145,7 @@ impl ShapeState {
} }
/// Provide the currently selected points by reference. /// Provide the currently selected points by reference.
pub fn selected_points<'a>(&'a self) -> impl Iterator<Item = &'a ManipulatorPointId> { pub fn selected_points(&self) -> impl Iterator<Item = &'_ ManipulatorPointId> {
self.selected_shape_state.values().flat_map(|state| &state.selected_points) self.selected_shape_state.values().flat_map(|state| &state.selected_points)
} }

View file

@ -23,6 +23,7 @@ use interpreted_executor::executor::DynamicExecutor;
use glam::{DAffine2, DVec2}; use glam::{DAffine2, DVec2};
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc;
use std::sync::mpsc::{Receiver, Sender}; use std::sync::mpsc::{Receiver, Sender};
use std::sync::Arc; use std::sync::Arc;
@ -58,7 +59,7 @@ pub(crate) struct GenerationResponse {
} }
thread_local! { thread_local! {
static NODE_RUNTIME: RefCell<Option<NodeRuntime>> = RefCell::new(None); pub(crate) static NODE_RUNTIME: Rc<RefCell<Option<NodeRuntime>>> = Rc::new(RefCell::new(None));
} }
impl NodeRuntime { impl NodeRuntime {
@ -72,7 +73,7 @@ impl NodeRuntime {
thumbnails: Default::default(), thumbnails: Default::default(),
} }
} }
pub fn run(&mut self) { pub async fn run(&mut self) {
let mut requests = self.receiver.try_iter().collect::<Vec<_>>(); let mut requests = self.receiver.try_iter().collect::<Vec<_>>();
// TODO: Currently we still render the document after we submit the node graph execution request. // TODO: Currently we still render the document after we submit the node graph execution request.
// This should be avoided in the future. // This should be avoided in the future.
@ -94,7 +95,7 @@ impl NodeRuntime {
}) => { }) => {
let (network, monitor_nodes) = Self::wrap_network(graph); let (network, monitor_nodes) = Self::wrap_network(graph);
let result = self.execute_network(network, image_frame); let result = self.execute_network(network, image_frame).await;
let mut responses = VecDeque::new(); let mut responses = VecDeque::new();
self.update_thumbnails(&path, monitor_nodes, &mut responses); self.update_thumbnails(&path, monitor_nodes, &mut responses);
let response = GenerationResponse { let response = GenerationResponse {
@ -125,7 +126,7 @@ impl NodeRuntime {
(scoped_network, monitor_nodes) (scoped_network, monitor_nodes)
} }
fn execute_network<'a>(&'a mut self, scoped_network: NodeNetwork, image_frame: Option<ImageFrame<Color>>) -> Result<TaggedValue, String> { async fn execute_network<'a>(&'a mut self, scoped_network: NodeNetwork, image_frame: Option<ImageFrame<Color>>) -> Result<TaggedValue, String> {
let editor_api = EditorApi { let editor_api = EditorApi {
font_cache: Some(&self.font_cache), font_cache: Some(&self.font_cache),
image_frame, image_frame,
@ -137,7 +138,7 @@ impl NodeRuntime {
let proto_network = c.compile_single(scoped_network, true)?; let proto_network = c.compile_single(scoped_network, true)?;
assert_ne!(proto_network.nodes.len(), 0, "No protonodes exist?"); assert_ne!(proto_network.nodes.len(), 0, "No protonodes exist?");
if let Err(e) = self.executor.update(proto_network) { if let Err(e) = self.executor.update(proto_network).await {
error!("Failed to update executor:\n{}", e); error!("Failed to update executor:\n{}", e);
return Err(e); return Err(e);
} }
@ -146,8 +147,8 @@ impl NodeRuntime {
use graph_craft::executor::Executor; use graph_craft::executor::Executor;
let result = match self.executor.input_type() { let result = match self.executor.input_type() {
Some(t) if t == concrete!(EditorApi) => self.executor.execute(editor_api.into_dyn()).map_err(|e| e.to_string()), Some(t) if t == concrete!(EditorApi) => self.executor.execute(editor_api.into_dyn()).await.map_err(|e| e.to_string()),
Some(t) if t == concrete!(()) => self.executor.execute(().into_dyn()).map_err(|e| e.to_string()), Some(t) if t == concrete!(()) => self.executor.execute(().into_dyn()).await.map_err(|e| e.to_string()),
_ => Err("Invalid input type".to_string()), _ => Err("Invalid input type".to_string()),
}; };
match result { match result {
@ -200,13 +201,21 @@ impl NodeRuntime {
} }
} }
pub fn run_node_graph() { pub async fn run_node_graph() {
NODE_RUNTIME.with(|runtime| { let result = NODE_RUNTIME.try_with(|runtime| {
let mut runtime = runtime.borrow_mut(); let runtime = runtime.clone();
if let Some(runtime) = runtime.as_mut() { async move {
runtime.run(); let mut runtime = runtime.try_borrow_mut();
if let Ok(ref mut runtime) = runtime {
if let Some(ref mut runtime) = runtime.as_mut() {
runtime.run().await;
}
}
} }
}); });
if let Ok(result) = result {
result.await;
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -231,8 +240,7 @@ impl Default for NodeGraphExecutor {
let (request_sender, request_reciever) = std::sync::mpsc::channel(); let (request_sender, request_reciever) = std::sync::mpsc::channel();
let (response_sender, response_reciever) = std::sync::mpsc::channel(); let (response_sender, response_reciever) = std::sync::mpsc::channel();
NODE_RUNTIME.with(|runtime| { NODE_RUNTIME.with(|runtime| {
let mut runtime = runtime.borrow_mut(); runtime.borrow_mut().replace(NodeRuntime::new(request_reciever, response_sender));
*runtime = Some(NodeRuntime::new(request_reciever, response_sender));
}); });
Self { Self {

View file

@ -12,12 +12,15 @@ use axum::routing::get;
use axum::Router; use axum::Router;
use fern::colors::{Color, ColoredLevelConfig}; use fern::colors::{Color, ColoredLevelConfig};
use http::{Response, StatusCode}; use http::{Response, StatusCode};
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
static IMAGES: Mutex<Option<HashMap<String, FrontendImageData>>> = Mutex::new(None); static IMAGES: Mutex<Option<HashMap<String, FrontendImageData>>> = Mutex::new(None);
static EDITOR: Mutex<Option<Editor>> = Mutex::new(None); thread_local! {
static EDITOR: RefCell<Option<Editor>> = RefCell::new(None);
}
async fn respond_to(id: Path<String>) -> impl IntoResponse { async fn respond_to(id: Path<String>) -> impl IntoResponse {
let builder = Response::builder().header("Access-Control-Allow-Origin", "*").status(StatusCode::OK); let builder = Response::builder().header("Access-Control-Allow-Origin", "*").status(StatusCode::OK);
@ -55,7 +58,7 @@ async fn main() {
*(IMAGES.lock().unwrap()) = Some(HashMap::new()); *(IMAGES.lock().unwrap()) = Some(HashMap::new());
graphite_editor::application::set_uuid_seed(0); graphite_editor::application::set_uuid_seed(0);
*(EDITOR.lock().unwrap()) = Some(Editor::new()); EDITOR.with(|editor| editor.borrow_mut().replace(Editor::new()));
let app = Router::new().route("/", get(|| async { "Hello, World!" })).route("/image/:id", get(respond_to)); let app = Router::new().route("/", get(|| async { "Hello, World!" })).route("/image/:id", get(respond_to));
// run it with hyper on localhost:3000 // run it with hyper on localhost:3000
@ -84,9 +87,10 @@ fn handle_message(message: String) -> String {
let Ok(message) = ron::from_str::<graphite_editor::messages::message::Message>(&message) else { let Ok(message) = ron::from_str::<graphite_editor::messages::message::Message>(&message) else {
panic!("Error parsing message: {}", message) panic!("Error parsing message: {}", message)
}; };
let mut guard = EDITOR.lock().unwrap(); let responses = EDITOR.with(|editor| {
let editor = (*guard).as_mut().unwrap(); let mut editor = editor.borrow_mut();
let responses = editor.handle_message(message); editor.as_mut().unwrap().handle_message(message)
});
// Sends a FrontendMessage to JavaScript // Sends a FrontendMessage to JavaScript
fn send_frontend_message_to_js(message: FrontendMessage) -> FrontendMessage { fn send_frontend_message_to_js(message: FrontendMessage) -> FrontendMessage {

View file

@ -59,16 +59,17 @@ fn window() -> web_sys::Window {
} }
fn request_animation_frame(f: &Closure<dyn FnMut()>) { fn request_animation_frame(f: &Closure<dyn FnMut()>) {
//window().request_idle_callback(f.as_ref().unchecked_ref()).unwrap();
window().request_animation_frame(f.as_ref().unchecked_ref()).expect("should register `requestAnimationFrame` OK"); window().request_animation_frame(f.as_ref().unchecked_ref()).expect("should register `requestAnimationFrame` OK");
} }
// Sends a message to the dispatcher in the Editor Backend // Sends a message to the dispatcher in the Editor Backend
fn poll_node_graph_evaluation() { async fn poll_node_graph_evaluation() {
// Process no further messages after a crash to avoid spamming the console // Process no further messages after a crash to avoid spamming the console
if EDITOR_HAS_CRASHED.load(Ordering::SeqCst) { if EDITOR_HAS_CRASHED.load(Ordering::SeqCst) {
return; return;
} }
editor::node_graph_executor::run_node_graph(); editor::node_graph_executor::run_node_graph().await;
// Get the editor instances, dispatch the message, and store the `FrontendMessage` queue response // Get the editor instances, dispatch the message, and store the `FrontendMessage` queue response
EDITOR_INSTANCES.with(|instances| { EDITOR_INSTANCES.with(|instances| {
@ -218,7 +219,7 @@ impl JsEditorHandle {
let g = f.clone(); let g = f.clone();
*g.borrow_mut() = Some(Closure::new(move || { *g.borrow_mut() = Some(Closure::new(move || {
poll_node_graph_evaluation(); wasm_bindgen_futures::spawn_local(poll_node_graph_evaluation());
// Schedule ourself for another requestAnimationFrame callback. // Schedule ourself for another requestAnimationFrame callback.
request_animation_frame(f.borrow().as_ref().unwrap()); request_animation_frame(f.borrow().as_ref().unwrap());
@ -788,7 +789,7 @@ impl JsEditorHandle {
Some(message_data) Some(message_data)
}) })
}); });
frontend_messages.unwrap().unwrap_or_default().into() frontend_messages.unwrap().unwrap_or_default()
} }
} }

View file

@ -637,7 +637,7 @@ mod tests {
let outline = subpath.outline(10., crate::Join::Round, crate::Cap::Round).0; let outline = subpath.outline(10., crate::Join::Round, crate::Cap::Round).0;
assert!(outline.manipulator_groups.windows(2).all(|pair| !pair[0].anchor.abs_diff_eq(pair[1].anchor, MAX_ABSOLUTE_DIFFERENCE))); assert!(outline.manipulator_groups.windows(2).all(|pair| !pair[0].anchor.abs_diff_eq(pair[1].anchor, MAX_ABSOLUTE_DIFFERENCE)));
assert_eq!(outline.closed(), true); assert!(outline.closed());
} }
#[test] #[test]

View file

@ -193,9 +193,18 @@ unsafe impl<T: StaticTypeSized, const N: usize> StaticType for [T; N] {
type Static = [<T as StaticTypeSized>::Static; N]; type Static = [<T as StaticTypeSized>::Static; N];
} }
unsafe impl<'a> StaticType for dyn DynAny<'a> + '_ { unsafe impl StaticType for dyn for<'i> DynAny<'_> + '_ {
type Static = dyn DynAny<'static>; type Static = dyn DynAny<'static>;
} }
unsafe impl StaticType for dyn for<'i> DynAny<'_> + Send + Sync + '_ {
type Static = dyn DynAny<'static> + Send + Sync;
}
unsafe impl<T: StaticTypeSized> StaticType for dyn core::future::Future<Output = T> + Send + Sync + '_ {
type Static = dyn core::future::Future<Output = T::Static> + Send + Sync;
}
unsafe impl<T: StaticTypeSized> StaticType for dyn core::future::Future<Output = T> + '_ {
type Static = dyn core::future::Future<Output = T::Static>;
}
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub trait IntoDynAny<'n>: Sized + StaticType + 'n { pub trait IntoDynAny<'n>: Sized + StaticType + 'n {
fn into_dyn(self) -> Box<dyn DynAny<'n> + 'n> { fn into_dyn(self) -> Box<dyn DynAny<'n> + 'n> {
@ -228,13 +237,14 @@ use core::{
mem::{ManuallyDrop, MaybeUninit}, mem::{ManuallyDrop, MaybeUninit},
num::Wrapping, num::Wrapping,
ops::Range, ops::Range,
pin::Pin,
time::Duration, time::Duration,
}; };
impl_type!( impl_type!(
Option<T>, Result<T, E>, Cell<T>, UnsafeCell<T>, RefCell<T>, MaybeUninit<T>, Option<T>, Result<T, E>, Cell<T>, UnsafeCell<T>, RefCell<T>, MaybeUninit<T>,
ManuallyDrop<T>, PhantomData<T>, PhantomPinned, Empty<T>, Range<T>, ManuallyDrop<T>, PhantomData<T>, PhantomPinned, Empty<T>, Range<T>,
Wrapping<T>, Duration, bool, f32, f64, char, Wrapping<T>, Pin<T>, Duration, bool, f32, f64, char,
u8, AtomicU8, u16, AtomicU16, u32, AtomicU32, u64, usize, AtomicUsize, u8, AtomicU8, u16, AtomicU16, u32, AtomicU32, u64, usize, AtomicUsize,
i8, AtomicI8, i16, AtomicI16, i32, AtomicI32, i64, isize, AtomicIsize, i8, AtomicI8, i16, AtomicI16, i32, AtomicI32, i64, isize, AtomicIsize,
i128, u128, AtomicBool, AtomicPtr<T> i128, u128, AtomicBool, AtomicPtr<T>

View file

@ -60,6 +60,10 @@ where
Self::Output: 'i + StaticTypeSized, Self::Output: 'i + StaticTypeSized,
Input: 'i + StaticTypeSized, Input: 'i + StaticTypeSized,
{ {
fn node_name(&self) -> &'static str {
core::any::type_name::<Self>()
}
fn input_type(&self) -> TypeId { fn input_type(&self) -> TypeId {
TypeId::of::<Input::Static>() TypeId::of::<Input::Static>()
} }
@ -121,6 +125,13 @@ impl<'i, I: 'i, O: 'i> Node<'i, I> for Pin<Box<dyn for<'a> Node<'a, I, Output =
(**self).eval(input) (**self).eval(input)
} }
} }
impl<'i, I: 'i, O: 'i> Node<'i, I> for Pin<&'i (dyn NodeIO<'i, I, Output = O> + 'i)> {
type Output = O;
fn eval(&'i self, input: I) -> Self::Output {
(**self).eval(input)
}
}
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub use crate::raster::image::{EditorApi, ExtractImageFrame}; pub use crate::raster::image::{EditorApi, ExtractImageFrame};

View file

@ -22,7 +22,7 @@ pub struct AddParameterNode<Second> {
second: Second, second: Second,
} }
#[node_macro::node_fn(AddParameterNode)] #[node_macro::node_new(AddParameterNode)]
fn add_parameter<U, T>(first: U, second: T) -> <U as Add<T>>::Output fn add_parameter<U, T>(first: U, second: T) -> <U as Add<T>>::Output
where where
U: Add<T>, U: Add<T>,
@ -30,6 +30,24 @@ where
first + second first + second
} }
#[automatically_derived]
impl<'input, U: 'input, T: 'input, S0: 'input> Node<'input, U> for AddParameterNode<S0>
where
U: Add<T>,
S0: Node<'input, (), Output = T>,
{
type Output = <U as Add<T>>::Output;
#[inline]
fn eval(&'input self, first: U) -> Self::Output {
let second = self.second.eval(());
{
{
first + second
}
}
}
}
pub struct MulParameterNode<Second> { pub struct MulParameterNode<Second> {
second: Second, second: Second,
} }
@ -181,7 +199,7 @@ pub struct MapResultNode<I, E, Mn> {
} }
#[node_macro::node_fn(MapResultNode<_I, _E>)] #[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> fn flat_map<_I, _E, N>(input: Result<_I, _E>, node: &'input N) -> Result<<N as Node<'input, _I>>::Output, _E>
where where
N: for<'a> Node<'a, _I>, N: for<'a> Node<'a, _I>,
{ {
@ -195,7 +213,7 @@ pub struct FlatMapResultNode<I, O, E, Mn> {
} }
#[node_macro::node_fn(FlatMapResultNode<_I, _O, _E>)] #[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> fn flat_map<_I, _O, _E, N>(input: Result<_I, _E>, node: &'input N) -> Result<_O, _E>
where where
N: for<'a> Node<'a, _I, Output = Result<_O, _E>>, N: for<'a> Node<'a, _I, Output = Result<_O, _E>>,
{ {

View file

@ -221,7 +221,7 @@ pub struct MapNode<MapFn> {
} }
#[node_macro::node_fn(MapNode)] #[node_macro::node_fn(MapNode)]
fn map_node<_Iter: Iterator, MapFnNode>(input: _Iter, map_fn: &'any_input MapFnNode) -> MapFnIterator<'input, _Iter, MapFnNode> fn map_node<_Iter: Iterator, MapFnNode>(input: _Iter, map_fn: &'input MapFnNode) -> MapFnIterator<'input, _Iter, MapFnNode>
where where
MapFnNode: for<'any_input> Node<'any_input, _Iter::Item>, MapFnNode: for<'any_input> Node<'any_input, _Iter::Item>,
{ {
@ -425,7 +425,7 @@ pub struct MapSndNode<First, Second, MapFn> {
} }
#[node_macro::node_fn(MapSndNode< _First, _Second>)] #[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) fn map_snd_node<MapFn, _First, _Second>(input: (_First, _Second), map_fn: &'input MapFn) -> (_First, <MapFn as Node<'input, _Second>>::Output)
where where
MapFn: for<'any_input> Node<'any_input, _Second>, MapFn: for<'any_input> Node<'any_input, _Second>,
{ {
@ -449,7 +449,7 @@ pub struct ForEachNode<MapNode> {
} }
#[node_macro::node_fn(ForEachNode)] #[node_macro::node_fn(ForEachNode)]
fn map_node<_Iter: Iterator, MapNode>(input: _Iter, map_node: &'any_input MapNode) -> () fn map_node<_Iter: Iterator, MapNode>(input: _Iter, map_node: &'input MapNode) -> ()
where where
MapNode: for<'any_input> Node<'any_input, _Iter::Item, Output = ()> + 'input, MapNode: for<'any_input> Node<'any_input, _Iter::Item, Output = ()> + 'input,
{ {

View file

@ -329,12 +329,13 @@ impl<'a> AsRef<EditorApi<'a>> for EditorApi<'a> {
} }
} }
#[derive(Debug, Clone, Copy, Default)]
pub struct ExtractImageFrame; pub struct ExtractImageFrame;
impl<'a: 'input, 'input> Node<'input, EditorApi<'a>> for ExtractImageFrame { impl<'a: 'input, 'input> Node<'input, &'a EditorApi<'a>> for ExtractImageFrame {
type Output = ImageFrame<Color>; type Output = ImageFrame<Color>;
fn eval(&'input self, mut editor_api: EditorApi<'a>) -> Self::Output { fn eval(&'input self, editor_api: &'a EditorApi<'a>) -> Self::Output {
editor_api.image_frame.take().unwrap_or(ImageFrame::identity()) editor_api.image_frame.clone().unwrap_or(ImageFrame::identity())
} }
} }

View file

@ -11,7 +11,7 @@ struct SetNode<S, I, Storage, Index> {
} }
#[node_macro::node_fn(SetNode<_S, _I>)] #[node_macro::node_fn(SetNode<_S, _I>)]
fn set_node<T, _S, _I>(value: T, storage: &'any_input mut _S, index: _I) fn set_node<T, _S, _I>(value: T, storage: &'input mut _S, index: _I)
where where
_S: IndexMut<_I>, _S: IndexMut<_I>,
_S::Output: DerefMut<Target = T> + Sized, _S::Output: DerefMut<Target = T> + Sized,
@ -25,7 +25,7 @@ struct GetNode<S, Storage> {
} }
#[node_macro::node_fn(GetNode<_S>)] #[node_macro::node_fn(GetNode<_S>)]
fn get_node<_S, I>(index: I, storage: &'any_input _S) -> &'input _S::Output fn get_node<_S, I>(index: I, storage: &'input _S) -> &'input _S::Output
where where
_S: Index<I>, _S: Index<I>,
_S::Output: Sized, _S::Output: Sized,

View file

@ -32,6 +32,39 @@ where
} }
} }
#[derive(Clone)]
pub struct AsyncComposeNode<First, Second, I> {
first: First,
second: Second,
phantom: PhantomData<I>,
}
impl<'i, 'f: 'i, 's: 'i, Input: 'static, First, Second> Node<'i, Input> for AsyncComposeNode<First, Second, Input>
where
First: Node<'i, Input>,
First::Output: core::future::Future,
Second: Node<'i, <<First as Node<'i, Input>>::Output as core::future::Future>::Output> + 'i,
{
type Output = core::pin::Pin<Box<dyn core::future::Future<Output = <Second as Node<'i, <<First as Node<'i, Input>>::Output as core::future::Future>::Output>>::Output> + 'i>>;
fn eval(&'i self, input: Input) -> Self::Output {
Box::pin(async move {
let arg = self.first.eval(input).await;
self.second.eval(arg)
})
}
}
impl<'i, First, Second, Input: 'i> AsyncComposeNode<First, Second, Input>
where
First: Node<'i, Input>,
First::Output: core::future::Future,
Second: Node<'i, <<First as Node<'i, Input>>::Output as core::future::Future>::Output> + 'i,
{
pub const fn new(first: First, second: Second) -> Self {
AsyncComposeNode::<First, Second, Input> { first, second, phantom: PhantomData }
}
}
pub trait Then<'i, Input: 'i>: Sized { pub trait Then<'i, Input: 'i>: Sized {
fn then<Second>(self, second: Second) -> ComposeNode<Self, Second, Input> fn then<Second>(self, second: Second) -> ComposeNode<Self, Second, Input>
where where
@ -44,6 +77,19 @@ pub trait Then<'i, Input: 'i>: Sized {
impl<'i, First: Node<'i, Input>, Input: 'i> Then<'i, Input> for First {} impl<'i, First: Node<'i, Input>, Input: 'i> Then<'i, Input> for First {}
pub trait AndThen<'i, Input: 'i>: Sized {
fn and_then<Second>(self, second: Second) -> AsyncComposeNode<Self, Second, Input>
where
Self: Node<'i, Input>,
Self::Output: core::future::Future,
Second: Node<'i, <<Self as Node<'i, Input>>::Output as core::future::Future>::Output> + 'i,
{
AsyncComposeNode::new(self, second)
}
}
impl<'i, First: Node<'i, Input>, Input: 'i> AndThen<'i, Input> for First {}
pub struct ConsNode<I: From<()>, Root>(pub Root, PhantomData<I>); pub struct ConsNode<I: From<()>, Root>(pub Root, PhantomData<I>);
impl<'i, Root, Input: 'i, I: 'i + From<()>> Node<'i, Input> for ConsNode<I, Root> impl<'i, Root, Input: 'i, I: 'i + From<()>> Node<'i, Input> for ConsNode<I, Root>

View file

@ -15,7 +15,7 @@ pub struct TextGenerator<Text, FontName, Size> {
} }
#[node_fn(TextGenerator)] #[node_fn(TextGenerator)]
fn generate_text<'a: 'input>(editor: EditorApi<'a>, text: String, font_name: Font, font_size: f64) -> crate::vector::VectorData { fn generate_text<'a: 'input>(editor: &'a EditorApi<'a>, text: String, font_name: Font, font_size: f64) -> crate::vector::VectorData {
let buzz_face = editor.font_cache.and_then(|cache| cache.get(&font_name)).map(|data| load_face(data)); let buzz_face = editor.font_cache.and_then(|cache| cache.get(&font_name)).map(|data| load_face(data));
crate::vector::VectorData::from_subpaths(to_path(&text, buzz_face, font_size, None)) crate::vector::VectorData::from_subpaths(to_path(&text, buzz_face, font_size, None))
} }

View file

@ -158,6 +158,7 @@ mod test {
assert_eq!(node.eval(()), 0); assert_eq!(node.eval(()), 0);
} }
#[test] #[test]
#[allow(clippy::unit_cmp)]
fn test_unit_node() { fn test_unit_node() {
let node = ForgetNode::new(); let node = ForgetNode::new();
assert_eq!(node.eval(()), ()); assert_eq!(node.eval(()), ());

View file

@ -10,6 +10,7 @@ pub fn compile_spirv(request: &CompileRequest, compile_dir: Option<&str>, manife
io: request.shader_io.clone(), io: request.shader_io.clone(),
})?; })?;
#[cfg(not(feature = "profiling"))]
let features = ""; let features = "";
#[cfg(feature = "profiling")] #[cfg(feature = "profiling")]
let features = "profiling"; let features = "profiling";

View file

@ -168,7 +168,7 @@ pub struct UniformNode<Executor> {
} }
#[node_macro::node_fn(UniformNode)] #[node_macro::node_fn(UniformNode)]
fn uniform_node<T: ToUniformBuffer, E: GpuExecutor>(data: T, executor: &'any_input E) -> ShaderInput<E::BufferHandle> { fn uniform_node<T: ToUniformBuffer, E: GpuExecutor>(data: T, executor: &'input E) -> ShaderInput<E::BufferHandle> {
executor.create_uniform_buffer(data).unwrap() executor.create_uniform_buffer(data).unwrap()
} }
@ -177,7 +177,7 @@ pub struct StorageNode<Executor> {
} }
#[node_macro::node_fn(StorageNode)] #[node_macro::node_fn(StorageNode)]
fn storage_node<T: ToStorageBuffer, E: GpuExecutor>(data: T, executor: &'any_input E) -> ShaderInput<E::BufferHandle> { fn storage_node<T: ToStorageBuffer, E: GpuExecutor>(data: T, executor: &'input E) -> ShaderInput<E::BufferHandle> {
executor executor
.create_storage_buffer( .create_storage_buffer(
data, data,
@ -205,7 +205,7 @@ pub struct CreateOutputBufferNode<Executor, Ty> {
} }
#[node_macro::node_fn(CreateOutputBufferNode)] #[node_macro::node_fn(CreateOutputBufferNode)]
fn create_output_buffer_node<E: GpuExecutor>(size: usize, executor: &'any_input E, ty: Type) -> ShaderInput<E::BufferHandle> { fn create_output_buffer_node<E: GpuExecutor>(size: usize, executor: &'input E, ty: Type) -> ShaderInput<E::BufferHandle> {
executor.create_output_buffer(size, ty, true).unwrap() executor.create_output_buffer(size, ty, true).unwrap()
} }
@ -216,7 +216,7 @@ pub struct CreateComputePassNode<Executor, Output, Instances> {
} }
#[node_macro::node_fn(CreateComputePassNode)] #[node_macro::node_fn(CreateComputePassNode)]
fn create_compute_pass_node<E: GpuExecutor>(layout: PipelineLayout<E>, executor: &'any_input E, output: ShaderInput<E::BufferHandle>, instances: u32) -> E::CommandBuffer { fn create_compute_pass_node<E: GpuExecutor>(layout: PipelineLayout<E>, executor: &'input E, output: ShaderInput<E::BufferHandle>, instances: u32) -> E::CommandBuffer {
executor.create_compute_pass(&layout, Some(output), instances).unwrap() executor.create_compute_pass(&layout, Some(output), instances).unwrap()
} }
@ -242,7 +242,7 @@ pub struct ExecuteComputePipelineNode<Executor> {
} }
#[node_macro::node_fn(ExecuteComputePipelineNode)] #[node_macro::node_fn(ExecuteComputePipelineNode)]
fn execute_compute_pipeline_node<E: GpuExecutor>(encoder: E::CommandBuffer, executor: &'any_input mut E) { fn execute_compute_pipeline_node<E: GpuExecutor>(encoder: E::CommandBuffer, executor: &'input mut E) {
executor.execute_compute_pipeline(encoder).unwrap(); executor.execute_compute_pipeline(encoder).unwrap();
} }
@ -251,6 +251,6 @@ fn execute_compute_pipeline_node<E: GpuExecutor>(encoder: E::CommandBuffer, exec
// executor: Executor, // executor: Executor,
// } // }
// #[node_macro::node_fn(ReadOutputBufferNode)] // #[node_macro::node_fn(ReadOutputBufferNode)]
// fn read_output_buffer_node<E: GpuExecutor>(buffer: E::BufferHandle, executor: &'any_input mut E) -> Vec<u8> { // fn read_output_buffer_node<E: GpuExecutor>(buffer: E::BufferHandle, executor: &'input mut E) -> Vec<u8> {
// executor.read_output_buffer(buffer).await.unwrap() // executor.read_output_buffer(buffer).await.unwrap()
// } // }

View file

@ -295,7 +295,7 @@ impl NodeNetwork {
self.previous_outputs.as_ref().unwrap_or(&self.outputs) self.previous_outputs.as_ref().unwrap_or(&self.outputs)
} }
pub fn input_types<'a>(&'a self) -> impl Iterator<Item = Type> + 'a { pub fn input_types(&self) -> impl Iterator<Item = Type> + '_ {
self.inputs.iter().map(move |id| self.nodes[id].inputs.get(0).map(|i| i.ty()).unwrap_or(concrete!(()))) self.inputs.iter().map(move |id| self.nodes[id].inputs.get(0).map(|i| i.ty()).unwrap_or(concrete!(())))
} }

View file

@ -1,6 +1,7 @@
use super::DocumentNode; use super::DocumentNode;
use crate::executor::Any; use crate::executor::Any;
pub use crate::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod, ImaginateStatus}; pub use crate::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod, ImaginateStatus};
use crate::proto::{Any as DAny, FutureAny};
use graphene_core::raster::{BlendMode, LuminanceCalculation}; use graphene_core::raster::{BlendMode, LuminanceCalculation};
use graphene_core::{Color, Node, Type}; use graphene_core::{Color, Node, Type};
@ -305,11 +306,11 @@ impl<'a> TaggedValue {
pub struct UpcastNode { pub struct UpcastNode {
value: TaggedValue, value: TaggedValue,
} }
impl<'input> Node<'input, Box<dyn DynAny<'input> + 'input>> for UpcastNode { impl<'input> Node<'input, DAny<'input>> for UpcastNode {
type Output = Box<dyn DynAny<'input> + 'input>; type Output = FutureAny<'input>;
fn eval(&'input self, _: Box<dyn DynAny<'input> + 'input>) -> Self::Output { fn eval(&'input self, _: DAny<'input>) -> Self::Output {
self.value.clone().to_any() Box::pin(async move { self.value.clone().to_any() })
} }
} }
impl UpcastNode { impl UpcastNode {

View file

@ -3,7 +3,7 @@ use std::error::Error;
use dyn_any::DynAny; use dyn_any::DynAny;
use crate::document::NodeNetwork; use crate::document::NodeNetwork;
use crate::proto::ProtoNetwork; use crate::proto::{LocalFuture, ProtoNetwork};
pub struct Compiler {} pub struct Compiler {}
@ -37,5 +37,5 @@ impl Compiler {
pub type Any<'a> = Box<dyn DynAny<'a> + 'a>; pub type Any<'a> = Box<dyn DynAny<'a> + 'a>;
pub trait Executor { pub trait Executor {
fn execute<'a, 's: 'a>(&'s self, input: Any<'a>) -> Result<Any<'a>, Box<dyn Error>>; fn execute<'a>(&'a self, input: Any<'a>) -> LocalFuture<Result<Any<'a>, Box<dyn Error>>>;
} }

View file

@ -1,5 +1,6 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::hash::Hash; use std::hash::Hash;
use xxhash_rust::xxh3::Xxh3; use xxhash_rust::xxh3::Xxh3;
@ -11,12 +12,15 @@ use graphene_core::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::pin::Pin; use std::pin::Pin;
pub type DynFuture<'n, T> = Pin<Box<dyn core::future::Future<Output = T> + 'n>>;
pub type LocalFuture<'n, T> = Pin<Box<dyn core::future::Future<Output = T> + 'n>>;
pub type Any<'n> = Box<dyn DynAny<'n> + 'n>; pub type Any<'n> = Box<dyn DynAny<'n> + 'n>;
pub type TypeErasedNode<'n> = dyn for<'i> NodeIO<'i, Any<'i>, Output = Any<'i>> + 'n + Send + Sync; pub type FutureAny<'n> = DynFuture<'n, Any<'n>>;
pub type TypeErasedPinnedRef<'n> = Pin<&'n (dyn for<'i> NodeIO<'i, Any<'i>, Output = Any<'i>> + 'n + Send + Sync)>; pub type TypeErasedNode<'n> = dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n;
pub type TypeErasedPinned<'n> = Pin<Box<dyn for<'i> NodeIO<'i, Any<'i>, Output = Any<'i>> + 'n + Send + Sync>>; pub type TypeErasedPinnedRef<'n> = Pin<&'n (dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n)>;
pub type TypeErasedPinned<'n> = Pin<Box<dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n>>;
pub type NodeConstructor = for<'a> fn(Vec<TypeErasedPinnedRef<'static>>) -> TypeErasedPinned<'static>; pub type NodeConstructor = for<'a> fn(Vec<TypeErasedPinnedRef<'static>>) -> DynFuture<'static, TypeErasedPinned<'static>>;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Default, PartialEq, Clone)] #[derive(Debug, Default, PartialEq, Clone)]

View file

@ -59,6 +59,8 @@ node-macro = { path = "../node-macro" }
boxcar = "0.1.0" boxcar = "0.1.0"
xxhash-rust = { workspace = true } xxhash-rust = { workspace = true }
serde_json = "1.0.96" serde_json = "1.0.96"
reqwest = { version = "0.11.17", features = ["rustls", "rustls-tls"] }
futures = "0.3.28"
[dependencies.serde] [dependencies.serde]
version = "1.0" version = "1.0"

View file

@ -1,5 +1,6 @@
use dyn_any::StaticType; use dyn_any::StaticType;
pub use graph_craft::proto::{Any, TypeErasedNode, TypeErasedPinned, TypeErasedPinnedRef}; pub use graph_craft::proto::{Any, TypeErasedNode, TypeErasedPinned, TypeErasedPinnedRef};
use graph_craft::proto::{DynFuture, FutureAny};
use graphene_core::NodeIO; use graphene_core::NodeIO;
pub use graphene_core::{generic, ops, Node}; pub use graphene_core::{generic, ops, Node};
use std::marker::PhantomData; use std::marker::PhantomData;
@ -12,18 +13,20 @@ pub struct DynAnyNode<I, O, Node> {
impl<'input, _I: 'input + StaticType, _O: 'input + StaticType, N: 'input, S0: 'input> Node<'input, Any<'input>> for DynAnyNode<_I, _O, S0> impl<'input, _I: 'input + StaticType, _O: 'input + StaticType, N: 'input, S0: 'input> Node<'input, Any<'input>> for DynAnyNode<_I, _O, S0>
where where
N: for<'any_input> Node<'any_input, _I, Output = _O>, N: for<'any_input> Node<'any_input, _I, Output = DynFuture<'any_input, _O>>,
S0: for<'any_input> Node<'any_input, (), Output = &'any_input N>, S0: for<'any_input> Node<'any_input, (), Output = &'any_input N>,
{ {
type Output = Any<'input>; type Output = FutureAny<'input>;
#[inline] #[inline]
fn eval(&'input self, input: Any<'input>) -> Self::Output { fn eval(&'input self, input: Any<'input>) -> Self::Output {
let node = self.node.eval(()); let node = self.node.eval(());
{ let node_name = core::any::type_name::<N>();
let node_name = core::any::type_name::<N>(); let input: Box<_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyNode Input, {0} in:\n{1}", e, node_name));
let input: Box<_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyNode Input, {0} in:\n{1}", e, node_name)); let output = async move {
Box::new(node.eval(*input)) let result = node.eval(*input).await;
} Box::new(result) as Any<'input>
};
Box::pin(output)
} }
fn reset(self: std::pin::Pin<&mut Self>) { fn reset(self: std::pin::Pin<&mut Self>) {
@ -56,11 +59,13 @@ impl<'input, _I: 'input + StaticType, _O: 'input + StaticType, N: 'input> Node<'
where where
N: for<'any_input> Node<'any_input, _I, Output = &'any_input _O>, N: for<'any_input> Node<'any_input, _I, Output = &'any_input _O>,
{ {
type Output = Any<'input>; type Output = FutureAny<'input>;
fn eval(&'input self, input: Any<'input>) -> Self::Output { fn eval(&'input self, input: Any<'input>) -> Self::Output {
let node_name = core::any::type_name::<N>(); let node_name = core::any::type_name::<N>();
let input: Box<_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyRefNode Input, {e} in:\n{node_name}")); let input: Box<_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyRefNode Input, {e} in:\n{node_name}"));
Box::new(self.node.eval(*input)) let result = self.node.eval(*input);
let output = async move { Box::new(result) as Any<'input> };
Box::pin(output)
} }
fn reset(self: std::pin::Pin<&mut Self>) { fn reset(self: std::pin::Pin<&mut Self>) {
let wrapped_node = unsafe { self.map_unchecked_mut(|e| &mut e.node) }; let wrapped_node = unsafe { self.map_unchecked_mut(|e| &mut e.node) };
@ -79,14 +84,15 @@ pub struct DynAnyInRefNode<I, O, Node> {
} }
impl<'input, _I: 'input + StaticType, _O: 'input + StaticType, N: 'input> Node<'input, Any<'input>> for DynAnyInRefNode<_I, _O, N> impl<'input, _I: 'input + StaticType, _O: 'input + StaticType, N: 'input> Node<'input, Any<'input>> for DynAnyInRefNode<_I, _O, N>
where where
N: for<'any_input> Node<'any_input, &'any_input _I, Output = _O>, N: for<'any_input> Node<'any_input, &'any_input _I, Output = DynFuture<'any_input, _O>>,
{ {
type Output = Any<'input>; type Output = FutureAny<'input>;
fn eval(&'input self, input: Any<'input>) -> Self::Output { fn eval(&'input self, input: Any<'input>) -> Self::Output {
{ {
let node_name = core::any::type_name::<N>(); let node_name = core::any::type_name::<N>();
let input: Box<&_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyInRefNode Input, {e} in:\n{node_name}")); let input: Box<&_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyInRefNode Input, {e} in:\n{node_name}"));
Box::new(self.node.eval(*input)) let result = self.node.eval(*input);
Box::pin(async move { Box::new(result.await) as Any<'_> })
} }
} }
} }
@ -96,13 +102,37 @@ impl<_I, _O, S0> DynAnyInRefNode<_I, _O, S0> {
} }
} }
pub struct FutureWrapperNode<Node> {
node: Node,
}
impl<'i, T: 'i, N: Node<'i, T>> Node<'i, T> for FutureWrapperNode<N>
where
N: Node<'i, T>,
{
type Output = DynFuture<'i, N::Output>;
fn eval(&'i self, input: T) -> Self::Output {
Box::pin(async move { self.node.eval(input) })
}
fn reset(self: std::pin::Pin<&mut Self>) {
let wrapped_node = unsafe { self.map_unchecked_mut(|e| &mut e.node) };
Node::reset(wrapped_node);
}
}
impl<'i, N> FutureWrapperNode<N> {
pub const fn new(node: N) -> Self {
Self { node }
}
}
pub trait IntoTypeErasedNode<'n> { pub trait IntoTypeErasedNode<'n> {
fn into_type_erased(self) -> TypeErasedPinned<'n>; fn into_type_erased(self) -> TypeErasedPinned<'n>;
} }
impl<'n, N: 'n> IntoTypeErasedNode<'n> for N impl<'n, N: 'n> IntoTypeErasedNode<'n> for N
where where
N: for<'i> NodeIO<'i, Any<'i>, Output = Any<'i>> + Send + Sync + 'n, N: for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n,
{ {
fn into_type_erased(self) -> TypeErasedPinned<'n> { fn into_type_erased(self) -> TypeErasedPinned<'n> {
Box::pin(self) Box::pin(self)
@ -139,13 +169,17 @@ pub struct DowncastBothNode<'a, I, O> {
_o: PhantomData<O>, _o: PhantomData<O>,
} }
impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'input, I> for DowncastBothNode<'n, I, O> { impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'input, I> for DowncastBothNode<'n, I, O> {
type Output = O; type Output = DynFuture<'input, O>;
#[inline] #[inline]
fn eval(&'input self, input: I) -> Self::Output { fn eval(&'input self, input: I) -> Self::Output {
{ {
let node_name = self.node.node_name();
let input = Box::new(input); let input = Box::new(input);
let out = dyn_any::downcast(self.node.eval(input)).unwrap_or_else(|e| panic!("DowncastBothNode Input {e}")); let future = self.node.eval(input);
*out Box::pin(async move {
let out = dyn_any::downcast(future.await).unwrap_or_else(|e| panic!("DowncastBothNode Input {e} in: \n{node_name}"));
*out
})
} }
} }
} }
@ -166,13 +200,15 @@ pub struct DowncastBothRefNode<'a, I, O> {
_i: PhantomData<(I, O)>, _i: PhantomData<(I, O)>,
} }
impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'input, I> for DowncastBothRefNode<'n, I, O> { impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'input, I> for DowncastBothRefNode<'n, I, O> {
type Output = &'input O; type Output = DynFuture<'input, &'input O>;
#[inline] #[inline]
fn eval(&'input self, input: I) -> Self::Output { fn eval(&'input self, input: I) -> Self::Output {
{ {
let input = Box::new(input); let input = Box::new(input);
let out: Box<&_> = dyn_any::downcast::<&O>(self.node.eval(input)).unwrap_or_else(|e| panic!("DowncastBothRefNode Input {e}")); Box::pin(async move {
*out let out: Box<&_> = dyn_any::downcast::<&O>(self.node.eval(input).await).unwrap_or_else(|e| panic!("DowncastBothRefNode Input {e}"));
*out
})
} }
} }
} }
@ -188,10 +224,12 @@ pub struct ComposeTypeErased<'a> {
} }
impl<'i, 'a: 'i> Node<'i, Any<'i>> for ComposeTypeErased<'a> { impl<'i, 'a: 'i> Node<'i, Any<'i>> for ComposeTypeErased<'a> {
type Output = Any<'i>; type Output = DynFuture<'i, Any<'i>>;
fn eval(&'i self, input: Any<'i>) -> Self::Output { fn eval(&'i self, input: Any<'i>) -> Self::Output {
let arg = self.first.eval(input); Box::pin(async move {
self.second.eval(arg) let arg = self.first.eval(input).await;
self.second.eval(arg).await
})
} }
} }
@ -205,6 +243,21 @@ pub fn input_node<O: StaticType>(n: TypeErasedPinnedRef) -> DowncastBothNode<(),
DowncastBothNode::new(n) DowncastBothNode::new(n)
} }
pub struct PanicNode<I, O>(PhantomData<I>, PhantomData<O>);
impl<'i, I: 'i, O: 'i> Node<'i, I> for PanicNode<I, O> {
type Output = O;
fn eval(&'i self, _: I) -> Self::Output {
unimplemented!("This node should never be evaluated")
}
}
impl<I, O> PanicNode<I, O> {
pub const fn new() -> Self {
Self(PhantomData, PhantomData)
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@ -215,8 +268,8 @@ mod test {
pub fn dyn_input_invalid_eval_panic() { pub fn dyn_input_invalid_eval_panic() {
//let add = DynAnyNode::new(AddNode::new()).into_type_erased(); //let add = DynAnyNode::new(AddNode::new()).into_type_erased();
//add.eval(Box::new(&("32", 32u32))); //add.eval(Box::new(&("32", 32u32)));
let dyn_any = DynAnyNode::<(u32, u32), u32, _>::new(ValueNode::new(AddNode::new())); let dyn_any = DynAnyNode::<(u32, u32), u32, _>::new(ValueNode::new(FutureWrapperNode { node: AddNode::new() }));
let type_erased = dyn_any.into_type_erased(); let type_erased = Box::pin(dyn_any) as TypeErasedPinned;
let _ref_type_erased = type_erased.as_ref(); let _ref_type_erased = type_erased.as_ref();
//let type_erased = Box::pin(dyn_any) as TypeErasedPinned<'_>; //let type_erased = Box::pin(dyn_any) as TypeErasedPinned<'_>;
type_erased.eval(Box::new(&("32", 32u32))); type_erased.eval(Box::new(&("32", 32u32)));
@ -226,10 +279,10 @@ mod test {
pub fn dyn_input_invalid_eval_panic_() { pub fn dyn_input_invalid_eval_panic_() {
//let add = DynAnyNode::new(AddNode::new()).into_type_erased(); //let add = DynAnyNode::new(AddNode::new()).into_type_erased();
//add.eval(Box::new(&("32", 32u32))); //add.eval(Box::new(&("32", 32u32)));
let dyn_any = DynAnyNode::<(u32, u32), u32, _>::new(ValueNode::new(AddNode::new())); let dyn_any = DynAnyNode::<(u32, u32), u32, _>::new(ValueNode::new(FutureWrapperNode { node: AddNode::new() }));
let type_erased = Box::pin(dyn_any) as TypeErasedPinned<'_>; let type_erased = Box::pin(dyn_any) as TypeErasedPinned<'_>;
type_erased.eval(Box::new((4u32, 2u32))); type_erased.eval(Box::new((4u32, 2u32)));
let id_node = IdNode::new(); let id_node = FutureWrapperNode::new(IdNode::new());
let type_erased_id = Box::pin(id_node) as TypeErasedPinned; let type_erased_id = Box::pin(id_node) as TypeErasedPinned;
let type_erased = ComposeTypeErased::new(type_erased.as_ref(), type_erased_id.as_ref()); let type_erased = ComposeTypeErased::new(type_erased.as_ref(), type_erased_id.as_ref());
type_erased.eval(Box::new((4u32, 2u32))); type_erased.eval(Box::new((4u32, 2u32)));

View file

@ -14,7 +14,7 @@ pub struct ReduceNode<Initial, Lambda> {
} }
#[node_fn(ReduceNode)] #[node_fn(ReduceNode)]
fn reduce<I: Iterator, Lambda, T>(iter: I, initial: T, lambda: &'any_input Lambda) -> T fn reduce<I: Iterator, Lambda, T>(iter: I, initial: T, lambda: &'input Lambda) -> T
where where
Lambda: for<'a> Node<'a, (T, I::Item), Output = T>, Lambda: for<'a> Node<'a, (T, I::Item), Output = T>,
{ {

View file

@ -17,7 +17,7 @@ pub struct GpuCompiler<TypingContext, ShaderIO> {
// TODO: Move to graph-craft // TODO: Move to graph-craft
#[node_macro::node_fn(GpuCompiler)] #[node_macro::node_fn(GpuCompiler)]
fn compile_gpu(node: &'input DocumentNode, mut typing_context: TypingContext, io: ShaderIO) -> compilation_client::Shader { async fn compile_gpu(node: &'input DocumentNode, mut typing_context: TypingContext, io: ShaderIO) -> compilation_client::Shader {
let compiler = graph_craft::executor::Compiler {}; let compiler = graph_craft::executor::Compiler {};
let DocumentNodeImplementation::Network(network) = node.implementation; let DocumentNodeImplementation::Network(network) = node.implementation;
let proto_network = compiler.compile_single(network, true).unwrap(); let proto_network = compiler.compile_single(network, true).unwrap();
@ -25,7 +25,7 @@ fn compile_gpu(node: &'input DocumentNode, mut typing_context: TypingContext, io
let input_types = proto_network.inputs.iter().map(|id| typing_context.get_type(*id).unwrap()).map(|node_io| node_io.output).collect(); let input_types = proto_network.inputs.iter().map(|id| typing_context.get_type(*id).unwrap()).map(|node_io| node_io.output).collect();
let output_type = typing_context.get_type(proto_network.output).unwrap().output; let output_type = typing_context.get_type(proto_network.output).unwrap().output;
let bytes = compilation_client::compile_sync(proto_network, input_types, output_type, io).unwrap(); let bytes = compilation_client::compile(proto_network, input_types, output_type, io).await.unwrap();
bytes bytes
} }
@ -34,7 +34,7 @@ pub struct MapGpuNode<Shader> {
} }
#[node_macro::node_fn(MapGpuNode)] #[node_macro::node_fn(MapGpuNode)]
fn map_gpu(inputs: Vec<ShaderInput<<NewExecutor as GpuExecutor>::BufferHandle>>, shader: &'any_input compilation_client::Shader) { async fn map_gpu(inputs: Vec<ShaderInput<<NewExecutor as GpuExecutor>::BufferHandle>>, shader: &'any_input compilation_client::Shader) {
use graph_craft::executor::Executor; use graph_craft::executor::Executor;
let executor = NewExecutor::new().unwrap(); let executor = NewExecutor::new().unwrap();
for input in shader.inputs.iter() { for input in shader.inputs.iter() {
@ -42,11 +42,13 @@ fn map_gpu(inputs: Vec<ShaderInput<<NewExecutor as GpuExecutor>::BufferHandle>>,
executor.write_buffer(buffer, input.data).unwrap(); executor.write_buffer(buffer, input.data).unwrap();
} }
todo!(); todo!();
let executor: GpuExecutor = GpuExecutor::new(Context::new_sync().unwrap(), shader.into(), "gpu::eval".into()).unwrap(); /*
let executor: GpuExecutor = GpuExecutor::new(Context::new().await.unwrap(), shader.into(), "gpu::eval".into()).unwrap();
let data: Vec<_> = input.into_iter().collect(); let data: Vec<_> = input.into_iter().collect();
let result = executor.execute(Box::new(data)).unwrap(); let result = executor.execute(Box::new(data)).unwrap();
let result = dyn_any::downcast::<Vec<_O>>(result).unwrap(); let result = dyn_any::downcast::<Vec<_O>>(result).unwrap();
*result *result
*/
} }
pub struct MapGpuSingleImageNode<N> { pub struct MapGpuSingleImageNode<N> {

View file

@ -0,0 +1,32 @@
use std::future::Future;
use crate::Node;
pub struct GetNode;
#[node_macro::node_fn(GetNode)]
async fn get_node(url: String) -> reqwest::Response {
reqwest::get(url).await.unwrap()
}
pub struct PostNode<Body> {
body: Body,
}
#[node_macro::node_fn(PostNode)]
async fn post_node(url: String, body: String) -> reqwest::Response {
reqwest::Client::new().post(url).body(body).send().await.unwrap()
}
#[derive(Clone, Copy, Debug)]
pub struct EvalSyncNode {}
#[node_macro::node_fn(EvalSyncNode)]
fn eval_sync<F: Future + 'input>(future: F) -> F::Output {
let future = futures::future::maybe_done(future);
futures::pin_mut!(future);
match future.as_mut().take_output() {
Some(value) => value,
_ => panic!("Node construction future returned pending"),
}
}

View file

@ -10,6 +10,8 @@ pub mod memo;
pub mod raster; pub mod raster;
pub mod http;
pub mod any; pub mod any;
#[cfg(feature = "gpu")] #[cfg(feature = "gpu")]

View file

@ -1,3 +1,5 @@
use futures::Future;
use graphene_core::Node; use graphene_core::Node;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
@ -15,25 +17,30 @@ pub struct CacheNode<T, CachedNode> {
cache: boxcar::Vec<(u64, T, AtomicBool)>, cache: boxcar::Vec<(u64, T, AtomicBool)>,
node: CachedNode, node: CachedNode,
} }
impl<'i, T: 'i, I: 'i + Hash, CachedNode: 'i> Node<'i, I> for CacheNode<T, CachedNode> impl<'i, T: 'i + Clone, I: 'i + Hash, CachedNode: 'i> Node<'i, I> for CacheNode<T, CachedNode>
where where
CachedNode: for<'any_input> Node<'any_input, I, Output = T>, CachedNode: for<'any_input> Node<'any_input, I>,
for<'a> <CachedNode as Node<'a, I>>::Output: core::future::Future<Output = T> + 'a,
{ {
type Output = &'i T; // TODO: This should return a reference to the cached cached_value
// but that requires a lot of lifetime magic <- This was suggested by copilot but is pretty acurate xD
type Output = Pin<Box<dyn Future<Output = T> + 'i>>;
fn eval(&'i self, input: I) -> Self::Output { fn eval(&'i self, input: I) -> Self::Output {
let mut hasher = Xxh3::new(); Box::pin(async move {
input.hash(&mut hasher); let mut hasher = Xxh3::new();
let hash = hasher.finish(); input.hash(&mut hasher);
let hash = hasher.finish();
if let Some((_, cached_value, keep)) = self.cache.iter().find(|(h, _, _)| *h == hash) { if let Some((_, cached_value, keep)) = self.cache.iter().find(|(h, _, _)| *h == hash) {
keep.store(true, std::sync::atomic::Ordering::Relaxed); keep.store(true, std::sync::atomic::Ordering::Relaxed);
cached_value cached_value.clone()
} else { } else {
trace!("Cache miss"); trace!("Cache miss");
let output = self.node.eval(input); let output = self.node.eval(input).await;
let index = self.cache.push((hash, output, AtomicBool::new(true))); let index = self.cache.push((hash, output, AtomicBool::new(true)));
&self.cache[index].1 self.cache[index].1.clone()
} }
})
} }
fn reset(mut self: Pin<&mut Self>) { fn reset(mut self: Pin<&mut Self>) {
@ -151,11 +158,12 @@ pub struct RefNode<T, Let> {
let_node: Let, let_node: Let,
_t: PhantomData<T>, _t: PhantomData<T>,
} }
impl<'i, T: 'i, Let> Node<'i, ()> for RefNode<T, Let> impl<'i, T: 'i, Let> Node<'i, ()> for RefNode<T, Let>
where where
Let: for<'a> Node<'a, Option<T>, Output = &'a T>, Let: for<'a> Node<'a, Option<T>>,
{ {
type Output = &'i T; type Output = <Let as Node<'i, Option<T>>>::Output;
fn eval(&'i self, _: ()) -> Self::Output { fn eval(&'i self, _: ()) -> Self::Output {
self.let_node.eval(None) self.let_node.eval(None)
} }

View file

@ -12,7 +12,7 @@ pub struct GenerateQuantizationNode<N, M> {
} }
#[node_macro::node_fn(GenerateQuantizationNode)] #[node_macro::node_fn(GenerateQuantizationNode)]
fn generate_quantization_fn(image_frame: ImageFrame, samples: u32, function: u32) -> [Quantization; 4] { fn generate_quantization_fn(image_frame: ImageFrame<Color>, samples: u32, function: u32) -> [Quantization; 4] {
let image = image_frame.image; let image = image_frame.image;
let len = image.data.len().min(10000); let len = image.data.len().min(10000);

View file

@ -85,7 +85,7 @@ pub struct MapImageNode<P, MapFn> {
} }
#[node_macro::node_fn(MapImageNode<_P>)] #[node_macro::node_fn(MapImageNode<_P>)]
fn map_image<MapFn, _P, Img: RasterMut<Pixel = _P>>(image: Img, map_fn: &'any_input MapFn) -> Img fn map_image<MapFn, _P, Img: RasterMut<Pixel = _P>>(image: Img, map_fn: &'input MapFn) -> Img
where where
MapFn: for<'any_input> Node<'any_input, _P, Output = _P> + 'input, MapFn: for<'any_input> Node<'any_input, _P, Output = _P> + 'input,
{ {
@ -282,7 +282,7 @@ pub struct BlendImageTupleNode<P, Fg, MapFn> {
} }
#[node_macro::node_fn(BlendImageTupleNode<_P, _Fg>)] #[node_macro::node_fn(BlendImageTupleNode<_P, _Fg>)]
fn blend_image_tuple<_P: Alpha + Pixel + Debug, MapFn, _Fg: Sample<Pixel = _P> + Transform>(images: (ImageFrame<_P>, _Fg), map_fn: &'any_input MapFn) -> ImageFrame<_P> fn blend_image_tuple<_P: Alpha + Pixel + Debug, MapFn, _Fg: Sample<Pixel = _P> + Transform>(images: (ImageFrame<_P>, _Fg), map_fn: &'input MapFn) -> ImageFrame<_P>
where where
MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'input + Clone, MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'input + Clone,
{ {
@ -299,7 +299,7 @@ pub struct BlendImageNode<P, Background, MapFn> {
} }
#[node_macro::node_fn(BlendImageNode<_P>)] #[node_macro::node_fn(BlendImageNode<_P>)]
fn blend_image_node<_P: Alpha + Pixel + Debug, MapFn, Forground: Sample<Pixel = _P> + Transform>(foreground: Forground, background: ImageFrame<_P>, map_fn: &'any_input MapFn) -> ImageFrame<_P> async fn blend_image_node<_P: Alpha + Pixel + Debug, MapFn, Forground: Sample<Pixel = _P> + Transform>(foreground: Forground, background: ImageFrame<_P>, map_fn: &'input MapFn) -> ImageFrame<_P>
where where
MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'input, MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'input,
{ {
@ -314,7 +314,7 @@ pub struct BlendReverseImageNode<P, Background, MapFn> {
} }
#[node_macro::node_fn(BlendReverseImageNode<_P>)] #[node_macro::node_fn(BlendReverseImageNode<_P>)]
fn blend_image_node<_P: Alpha + Pixel + Debug, MapFn, Background: Transform + Sample<Pixel = _P>>(foreground: ImageFrame<_P>, background: Background, map_fn: &'any_input MapFn) -> ImageFrame<_P> fn blend_image_node<_P: Alpha + Pixel + Debug, MapFn, Background: Transform + Sample<Pixel = _P>>(foreground: ImageFrame<_P>, background: Background, map_fn: &'input MapFn) -> ImageFrame<_P>
where where
MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'input, MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'input,
{ {

View file

@ -24,3 +24,7 @@ log = "0.4"
serde = { version = "1", features = ["derive"], optional = true } serde = { version = "1", features = ["derive"], optional = true }
glam = { version = "0.22" } glam = { version = "0.22" }
once_cell = "1.17.0" once_cell = "1.17.0"
futures = "0.3.28"
[dev-dependencies]
tokio = { version = "1.12", features = ["rt", "macros"] }

View file

@ -6,7 +6,7 @@ use dyn_any::StaticType;
use graph_craft::document::value::UpcastNode; use graph_craft::document::value::UpcastNode;
use graph_craft::document::NodeId; use graph_craft::document::NodeId;
use graph_craft::executor::Executor; use graph_craft::executor::Executor;
use graph_craft::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, TypingContext}; use graph_craft::proto::{ConstructionArgs, LocalFuture, ProtoNetwork, ProtoNode, TypingContext};
use graph_craft::Type; use graph_craft::Type;
use graphene_std::any::{Any, TypeErasedPinned, TypeErasedPinnedRef}; use graphene_std::any::{Any, TypeErasedPinned, TypeErasedPinnedRef};
@ -33,11 +33,11 @@ impl Default for DynamicExecutor {
} }
impl DynamicExecutor { impl DynamicExecutor {
pub fn new(proto_network: ProtoNetwork) -> Result<Self, String> { pub async fn new(proto_network: ProtoNetwork) -> Result<Self, String> {
let mut typing_context = TypingContext::new(&node_registry::NODE_REGISTRY); let mut typing_context = TypingContext::new(&node_registry::NODE_REGISTRY);
typing_context.update(&proto_network)?; typing_context.update(&proto_network)?;
let output = proto_network.output; let output = proto_network.output;
let tree = BorrowTree::new(proto_network, &typing_context)?; let tree = BorrowTree::new(proto_network, &typing_context).await?;
Ok(Self { Ok(Self {
tree, tree,
@ -47,11 +47,11 @@ impl DynamicExecutor {
}) })
} }
pub fn update(&mut self, proto_network: ProtoNetwork) -> Result<(), String> { pub async fn update(&mut self, proto_network: ProtoNetwork) -> Result<(), String> {
self.output = proto_network.output; self.output = proto_network.output;
self.typing_context.update(&proto_network)?; self.typing_context.update(&proto_network)?;
trace!("setting output to {}", self.output); trace!("setting output to {}", self.output);
let mut orphans = self.tree.update(proto_network, &self.typing_context)?; let mut orphans = self.tree.update(proto_network, &self.typing_context).await?;
core::mem::swap(&mut self.orphaned_nodes, &mut orphans); core::mem::swap(&mut self.orphaned_nodes, &mut orphans);
for node_id in orphans { for node_id in orphans {
if self.orphaned_nodes.contains(&node_id) { if self.orphaned_nodes.contains(&node_id) {
@ -75,8 +75,8 @@ impl DynamicExecutor {
} }
impl Executor for DynamicExecutor { impl Executor for DynamicExecutor {
fn execute<'a, 's: 'a>(&'s self, input: Any<'a>) -> Result<Any<'a>, Box<dyn Error>> { fn execute<'a>(&'a self, input: Any<'a>) -> LocalFuture<Result<Any<'a>, Box<dyn Error>>> {
self.tree.eval_any(self.output, input).ok_or_else(|| "Failed to execute".into()) Box::pin(async move { self.tree.eval_any(self.output, input).await.ok_or_else(|| "Failed to execute".into()) })
} }
} }
@ -118,20 +118,20 @@ pub struct BorrowTree {
} }
impl BorrowTree { impl BorrowTree {
pub fn new(proto_network: ProtoNetwork, typing_context: &TypingContext) -> Result<Self, String> { pub async fn new(proto_network: ProtoNetwork, typing_context: &TypingContext) -> Result<Self, String> {
let mut nodes = BorrowTree::default(); let mut nodes = BorrowTree::default();
for (id, node) in proto_network.nodes { for (id, node) in proto_network.nodes {
nodes.push_node(id, node, typing_context)? nodes.push_node(id, node, typing_context).await?
} }
Ok(nodes) Ok(nodes)
} }
/// Pushes new nodes into the tree and return orphaned nodes /// Pushes new nodes into the tree and return orphaned nodes
pub fn update(&mut self, proto_network: ProtoNetwork, typing_context: &TypingContext) -> Result<Vec<NodeId>, String> { pub async fn update(&mut self, proto_network: ProtoNetwork, typing_context: &TypingContext) -> Result<Vec<NodeId>, String> {
let mut old_nodes: HashSet<_> = self.nodes.keys().copied().collect(); let mut old_nodes: HashSet<_> = self.nodes.keys().copied().collect();
for (id, node) in proto_network.nodes { for (id, node) in proto_network.nodes {
if !self.nodes.contains_key(&id) { if !self.nodes.contains_key(&id) {
self.push_node(id, node, typing_context)?; self.push_node(id, node, typing_context).await?;
} else { } else {
let Some(node_container) = self.nodes.get_mut(&id) else { continue }; let Some(node_container) = self.nodes.get_mut(&id) else { continue };
let mut node_container_writer = node_container.write().unwrap(); let mut node_container_writer = node_container.write().unwrap();
@ -168,25 +168,25 @@ impl BorrowTree {
self.nodes.get(&id).cloned() self.nodes.get(&id).cloned()
} }
pub fn eval<'i, I: StaticType + 'i, O: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Option<O> { pub async fn eval<'i, I: StaticType + 'i + Send + Sync, O: StaticType + Send + Sync + 'i>(&'i self, id: NodeId, input: I) -> Option<O> {
let node = self.nodes.get(&id).cloned()?; let node = self.nodes.get(&id).cloned()?;
let reader = node.read().unwrap(); let reader = node.read().unwrap();
let output = reader.node.eval(Box::new(input)); let output = reader.node.eval(Box::new(input));
dyn_any::downcast::<O>(output).ok().map(|o| *o) dyn_any::downcast::<O>(output.await).ok().map(|o| *o)
} }
pub fn eval_any<'i>(&'i self, id: NodeId, input: Any<'i>) -> Option<Any<'i>> { pub async fn eval_any<'i>(&'i self, id: NodeId, input: Any<'i>) -> Option<Any<'i>> {
let node = self.nodes.get(&id)?; let node = self.nodes.get(&id)?;
// TODO: Comments by @TrueDoctor before this was merged: // TODO: Comments by @TrueDoctor before this was merged:
// TODO: Oof I dislike the evaluation being an unsafe operation but I guess its fine because it only is a lifetime extension // TODO: Oof I dislike the evaluation being an unsafe operation but I guess its fine because it only is a lifetime extension
// TODO: We should ideally let miri run on a test that evaluates the nodegraph multiple times to check if this contains any subtle UB but this looks fine for now // TODO: We should ideally let miri run on a test that evaluates the nodegraph multiple times to check if this contains any subtle UB but this looks fine for now
Some(unsafe { (*((&*node.read().unwrap()) as *const NodeContainer)).node.eval(input) }) Some(unsafe { (*((&*node.read().unwrap()) as *const NodeContainer)).node.eval(input).await })
} }
pub fn free_node(&mut self, id: NodeId) { pub fn free_node(&mut self, id: NodeId) {
self.nodes.remove(&id); self.nodes.remove(&id);
} }
pub fn push_node(&mut self, id: NodeId, proto_node: ProtoNode, typing_context: &TypingContext) -> Result<(), String> { pub async fn push_node(&mut self, id: NodeId, proto_node: ProtoNode, typing_context: &TypingContext) -> Result<(), String> {
let ProtoNode { let ProtoNode {
construction_args, construction_args,
identifier, identifier,
@ -207,7 +207,7 @@ impl BorrowTree {
let ids: Vec<_> = ids.iter().map(|(id, _)| *id).collect(); let ids: Vec<_> = ids.iter().map(|(id, _)| *id).collect();
let construction_nodes = self.node_refs(&ids); let construction_nodes = self.node_refs(&ids);
let constructor = typing_context.constructor(id).ok_or(format!("No constructor found for node {:?}", identifier))?; let constructor = typing_context.constructor(id).ok_or(format!("No constructor found for node {:?}", identifier))?;
let node = constructor(construction_nodes); let node = constructor(construction_nodes).await;
let node = NodeContainer { let node = NodeContainer {
node, node,
_dependencies: self.node_deps(&ids), _dependencies: self.node_deps(&ids),
@ -226,12 +226,12 @@ mod test {
use super::*; use super::*;
#[test] #[tokio::test]
fn push_node() { async fn push_node() {
let mut tree = BorrowTree::default(); let mut tree = BorrowTree::default();
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32)), vec![]); let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32)), vec![]);
tree.push_node(0, val_1_protonode, &TypingContext::default()).unwrap(); tree.push_node(0, val_1_protonode, &TypingContext::default()).await.unwrap();
let _node = tree.get(0).unwrap(); let _node = tree.get(0).unwrap();
assert_eq!(tree.eval(0, ()), Some(2u32)); assert_eq!(tree.eval(0, ()).await, Some(2u32));
} }
} }

View file

@ -44,8 +44,8 @@ mod tests {
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32); assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
}*/ }*/
#[test] #[tokio::test]
fn execute_add() { async fn execute_add() {
use graph_craft::document::*; use graph_craft::document::*;
use graph_craft::*; use graph_craft::*;
@ -109,15 +109,15 @@ mod tests {
let compiler = Compiler {}; let compiler = Compiler {};
let protograph = compiler.compile_single(network, true).expect("Graph should be generated"); let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
let exec = DynamicExecutor::new(protograph).unwrap_or_else(|e| panic!("Failed to create executor: {}", e)); let exec = DynamicExecutor::new(protograph).await.unwrap_or_else(|e| panic!("Failed to create executor: {}", e));
let result = exec.execute(32_u32.into_dyn()).unwrap(); let result = exec.execute(32_u32.into_dyn()).await.unwrap();
let val = *dyn_any::downcast::<u32>(result).unwrap(); let val = *dyn_any::downcast::<u32>(result).unwrap();
assert_eq!(val, 33_u32); assert_eq!(val, 33_u32);
} }
#[test] #[tokio::test]
fn double_number() { async fn double_number() {
use graph_craft::document::*; use graph_craft::document::*;
use graph_craft::*; use graph_craft::*;
@ -158,6 +158,6 @@ mod tests {
let compiler = Compiler {}; let compiler = Compiler {};
let protograph = compiler.compile_single(network, true).expect("Graph should be generated"); let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
let _exec = DynamicExecutor::new(protograph).map(|e| panic!("The network should not type check: {:#?}", e)).unwrap_err(); let _exec = DynamicExecutor::new(protograph).await.map(|e| panic!("The network should not type check: {:#?}", e)).unwrap_err();
} }
} }

View file

@ -1,43 +1,46 @@
use glam::{DAffine2, DVec2}; use glam::{DAffine2, DVec2};
use graph_craft::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod, ImaginateStatus};
use graphene_core::ops::{CloneNode, IdNode, TypeNode}; use graphene_core::ops::IdNode;
use graphene_core::vector::VectorData; use graphene_core::vector::VectorData;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::collections::HashMap; use std::collections::HashMap;
use graphene_core::raster::color::Color; use graphene_core::raster::color::Color;
use graphene_core::raster::*;
use graphene_core::structural::Then; use graphene_core::structural::Then;
use graphene_core::value::{ClonedNode, CopiedNode, ForgetNode, ValueNode}; use graphene_core::value::{ClonedNode, CopiedNode, ValueNode};
use graphene_core::{fn_type, raster::*};
use graphene_core::{Node, NodeIO, NodeIOTypes}; use graphene_core::{Node, NodeIO, NodeIOTypes};
use graphene_std::brush::*; use graphene_std::brush::*;
use graphene_std::raster::*; use graphene_std::raster::*;
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DowncastBothRefNode, DynAnyInRefNode, DynAnyNode, DynAnyRefNode, IntoTypeErasedNode, TypeErasedPinnedRef}; use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyInRefNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode, TypeErasedPinnedRef};
use graphene_core::{Cow, NodeIdentifier, Type, TypeDescriptor}; use graphene_core::{Cow, NodeIdentifier, Type, TypeDescriptor};
use graph_craft::proto::NodeConstructor; use graph_craft::proto::{NodeConstructor, TypeErasedPinned};
use graphene_core::{concrete, fn_type, generic, value_fn}; use graphene_core::{concrete, generic, value_fn};
use graphene_std::memo::{CacheNode, LetNode}; use graphene_std::memo::{CacheNode, LetNode};
use graphene_std::raster::BlendImageTupleNode; use graphene_std::raster::BlendImageTupleNode;
use crate::executor::NodeContainer;
use dyn_any::StaticType; use dyn_any::StaticType;
use graphene_core::quantization::QuantizationChannels; use graphene_core::quantization::QuantizationChannels;
macro_rules! construct_node { macro_rules! construct_node {
($args: ident, $path:ty, [$($type:tt),*]) => {{ ($args: ident, $path:ty, [$($type:tt),*]) => { async move {
let mut args: Vec<TypeErasedPinnedRef<'static>> = $args.clone(); let mut args: Vec<TypeErasedPinnedRef<'static>> = $args.clone();
args.reverse(); args.reverse();
<$path>::new($(graphene_core::value::ClonedNode::new( let node = <$path>::new($(
graphene_std::any::input_node::<$type>(args.pop() {
.expect("Not enough arguments provided to construct node")).eval(())) let node = graphene_std::any::input_node::<$type>(args.pop().expect("Not enough arguments provided to construct node"));
let value = node.eval(()).await;
graphene_core::value::ClonedNode::new(value)
}
),* ),*
) );
node
}} }}
} }
@ -47,16 +50,16 @@ macro_rules! register_node {
( (
NodeIdentifier::new(stringify!($path)), NodeIdentifier::new(stringify!($path)),
|args| { |args| {
let node = construct_node!(args, $path, [$($type),*]); Box::pin(async move {
let node = construct_node!(args, $path, [$($type),*]).await;
let node = graphene_std::any::FutureWrapperNode::new(node);
let any: DynAnyNode<$input, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node)); let any: DynAnyNode<$input, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
Box::pin(any) Box::pin(any) as TypeErasedPinned
})
}, },
{ {
let node = IdNode::new().into_type_erased();
let node = NodeContainer::new(node, vec![]);
let _node = unsafe { node.erase_lifetime().static_ref() };
let node = <$path>::new($( let node = <$path>::new($(
graphene_std::any::input_node::<$type>(_node) graphene_std::any::PanicNode::<(), $type>::new()
),*); ),*);
let params = vec![$(value_fn!($type)),*]; let params = vec![$(value_fn!($type)),*];
let mut node_io = <$path as NodeIO<'_, $input>>::to_node_io(&node, params); let mut node_io = <$path as NodeIO<'_, $input>>::to_node_io(&node, params);
@ -82,9 +85,12 @@ macro_rules! raster_node {
( (
NodeIdentifier::new(stringify!($path)), NodeIdentifier::new(stringify!($path)),
|args| { |args| {
let node = construct_node!(args, $path, [$($type),*]); Box::pin(async move {
let any: DynAnyNode<Color, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node)); let node = construct_node!(args, $path, [$($type),*]).await;
Box::pin(any) let node = graphene_std::any::FutureWrapperNode::new(node);
let any: DynAnyNode<Color, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
}, },
{ {
let params = vec![$(value_fn!($type)),*]; let params = vec![$(value_fn!($type)),*];
@ -94,10 +100,13 @@ macro_rules! raster_node {
( (
NodeIdentifier::new(stringify!($path)), NodeIdentifier::new(stringify!($path)),
|args| { |args| {
let node = construct_node!(args, $path, [$($type),*]); Box::pin(async move {
let map_node = graphene_std::raster::MapImageNode::new(graphene_core::value::ValueNode::new(node)); let node = construct_node!(args, $path, [$($type),*]).await;
let any: DynAnyNode<Image<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(map_node)); let map_node = graphene_std::raster::MapImageNode::new(graphene_core::value::ValueNode::new(node));
Box::pin(any) let map_node = graphene_std::any::FutureWrapperNode::new(map_node);
let any: DynAnyNode<Image<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(map_node));
Box::pin(any) as TypeErasedPinned
})
}, },
{ {
let params = vec![$(value_fn!($type)),*]; let params = vec![$(value_fn!($type)),*];
@ -107,10 +116,13 @@ macro_rules! raster_node {
( (
NodeIdentifier::new(stringify!($path)), NodeIdentifier::new(stringify!($path)),
|args| { |args| {
let node = construct_node!(args, $path, [$($type),*]); Box::pin(async move {
let map_node = graphene_std::raster::MapImageNode::new(graphene_core::value::ValueNode::new(node)); let node = construct_node!(args, $path, [$($type),*]).await;
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(map_node)); let map_node = graphene_std::raster::MapImageNode::new(graphene_core::value::ValueNode::new(node));
Box::pin(any) let map_node = graphene_std::any::FutureWrapperNode::new(map_node);
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(map_node));
Box::pin(any) as TypeErasedPinned
})
}, },
{ {
let params = vec![$(value_fn!($type)),*]; let params = vec![$(value_fn!($type)),*];
@ -129,7 +141,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
//register_node!(graphene_core::ops::IdNode, input: Any<'_>, params: []), //register_node!(graphene_core::ops::IdNode, input: Any<'_>, params: []),
vec![( vec![(
NodeIdentifier::new("graphene_core::ops::IdNode"), NodeIdentifier::new("graphene_core::ops::IdNode"),
|_| IdNode::new().into_type_erased(), |_| Box::pin(async move { Box::pin(FutureWrapperNode::new(IdNode::new())) as TypeErasedPinned }),
NodeIOTypes::new(generic!(I), generic!(I), vec![]), NodeIOTypes::new(generic!(I), generic!(I), vec![]),
)], )],
// TODO: create macro to impl for all types // TODO: create macro to impl for all types
@ -158,37 +170,39 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
vec![( vec![(
NodeIdentifier::new("graphene_std::raster::CombineChannelsNode"), NodeIdentifier::new("graphene_std::raster::CombineChannelsNode"),
|args| { |args| {
use graphene_core::raster::*; Box::pin(async move {
use graphene_core::value::*; use graphene_core::raster::*;
use graphene_core::value::*;
let channel_r: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]); let channel_r: ImageFrame<Color> = DowncastBothNode::new(args[0]).eval(()).await;
let channel_g: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[1]); let channel_g: ImageFrame<Color> = DowncastBothNode::new(args[1]).eval(()).await;
let channel_b: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[2]); let channel_b: ImageFrame<Color> = DowncastBothNode::new(args[2]).eval(()).await;
let channel_a: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[3]); let channel_a: ImageFrame<Color> = DowncastBothNode::new(args[3]).eval(()).await;
let insert_r = InsertChannelNode::new(channel_r.clone(), CopiedNode::new(RedGreenBlue::Red)); let insert_r = InsertChannelNode::new(ClonedNode::new(channel_r.clone()), CopiedNode::new(RedGreenBlue::Red));
let insert_g = InsertChannelNode::new(channel_g.clone(), CopiedNode::new(RedGreenBlue::Green)); let insert_g = InsertChannelNode::new(ClonedNode::new(channel_g.clone()), CopiedNode::new(RedGreenBlue::Green));
let insert_b = InsertChannelNode::new(channel_b.clone(), CopiedNode::new(RedGreenBlue::Blue)); let insert_b = InsertChannelNode::new(ClonedNode::new(channel_b.clone()), CopiedNode::new(RedGreenBlue::Blue));
let complete_node = insert_r.then(insert_g).then(insert_b); let complete_node = insert_r.then(insert_g).then(insert_b);
let complete_node = complete_node.then(MaskImageNode::new(channel_a.clone())); let complete_node = complete_node.then(MaskImageNode::new(ClonedNode::new(channel_a.clone())));
// TODO: Move to FN Node for better performance // TODO: Move to FN Node for better performance
let (mut transform, mut bounds) = (DAffine2::ZERO, glam::UVec2::ZERO); let (mut transform, mut bounds) = (DAffine2::ZERO, glam::UVec2::ZERO);
for imf in [channel_a, channel_r, channel_g, channel_b] { for image in [channel_a, channel_r, channel_g, channel_b] {
let image = imf.eval(()); if image.image.width() > bounds.x {
if image.image.width() > bounds.x { bounds = glam::UVec2::new(image.image.width(), image.image.height());
bounds = glam::UVec2::new(image.image.width(), image.image.height()); transform = image.transform;
transform = image.transform; }
} }
} let empty_image = ImageFrame {
let empty_image = ImageFrame { image: Image::new(bounds.x, bounds.y, Color::BLACK),
image: Image::new(bounds.x, bounds.y, Color::BLACK), transform,
transform, };
}; let final_image = ClonedNode::new(empty_image).then(complete_node);
let final_image = ClonedNode::new(empty_image).then(complete_node); let final_image = FutureWrapperNode::new(final_image);
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(final_image)); let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(final_image));
Box::pin(any) Box::pin(any) as TypeErasedPinned
})
}, },
NodeIOTypes::new( NodeIOTypes::new(
concrete!(()), concrete!(()),
@ -200,12 +214,26 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
register_node!(graphene_std::memo::MonitorNode<_>, input: ImageFrame<Color>, params: []), register_node!(graphene_std::memo::MonitorNode<_>, input: ImageFrame<Color>, params: []),
register_node!(graphene_std::memo::MonitorNode<_>, input: graphene_core::GraphicGroup, params: []), register_node!(graphene_std::memo::MonitorNode<_>, input: graphene_core::GraphicGroup, params: []),
#[cfg(feature = "gpu")] #[cfg(feature = "gpu")]
register_node!(graphene_std::executor::MapGpuSingleImageNode<_>, input: Image<Color>, params: [String]), vec![(
NodeIdentifier::new("graphene_std::executor::MapGpuSingleImageNode<_>"),
|args| {
Box::pin(async move {
let document_node: DowncastBothNode<(), DocumentNode> = DowncastBothNode::new(args[0]);
let document_node = ClonedNode::new(document_node.eval(()).await);
let node = graphene_std::executor::MapGpuNode::new(document_node);
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
},
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(DocumentNode)]),
)],
vec![( vec![(
NodeIdentifier::new("graphene_core::structural::ComposeNode<_, _, _>"), NodeIdentifier::new("graphene_core::structural::ComposeNode<_, _, _>"),
|args| { |args| {
let node = ComposeTypeErased::new(args[0], args[1]); Box::pin(async move {
node.into_type_erased() let node = ComposeTypeErased::new(args[0], args[1]);
node.into_type_erased()
})
}, },
NodeIOTypes::new( NodeIOTypes::new(
generic!(T), generic!(T),
@ -213,8 +241,6 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
vec![Type::Fn(Box::new(generic!(T)), Box::new(generic!(V))), Type::Fn(Box::new(generic!(V)), Box::new(generic!(U)))], vec![Type::Fn(Box::new(generic!(T)), Box::new(generic!(V))), Type::Fn(Box::new(generic!(V)), Box::new(generic!(U)))],
), ),
)], )],
//register_node!(graphene_std::brush::ReduceNode<_, _>, input: core::slice::Iter<ImageFrame<Color>>, params: [ImageFrame<Color>, &ValueNode<BlendImageTupleNode<ValueNode<BlendNode<ClonedNode<BlendMode>, ClonedNode<f64>>>>>]),
//register_node!(graphene_std::brush::ReduceNode<_, _>, input: core::slice::Iter<ImageFrame<Color>>, params: [AxisAlignedBbox, &MergeBoundingBoxNode]),
register_node!(graphene_std::brush::IntoIterNode<_>, input: &Vec<DVec2>, params: []), register_node!(graphene_std::brush::IntoIterNode<_>, input: &Vec<DVec2>, params: []),
vec![( vec![(
NodeIdentifier::new("graphene_std::brush::BrushNode"), NodeIdentifier::new("graphene_std::brush::BrushNode"),
@ -223,42 +249,45 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
use graphene_core::value::*; use graphene_core::value::*;
use graphene_std::brush::*; use graphene_std::brush::*;
let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]); Box::pin(async move {
let bounds: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[1]); let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
let trace: DowncastBothNode<(), Vec<DVec2>> = DowncastBothNode::new(args[2]); let bounds: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[1]);
let diameter: DowncastBothNode<(), f64> = DowncastBothNode::new(args[3]); let trace: DowncastBothNode<(), Vec<DVec2>> = DowncastBothNode::new(args[2]);
let hardness: DowncastBothNode<(), f64> = DowncastBothNode::new(args[4]); let diameter: DowncastBothNode<(), f64> = DowncastBothNode::new(args[3]);
let flow: DowncastBothNode<(), f64> = DowncastBothNode::new(args[5]); let hardness: DowncastBothNode<(), f64> = DowncastBothNode::new(args[4]);
let color: DowncastBothNode<(), Color> = DowncastBothNode::new(args[6]); let flow: DowncastBothNode<(), f64> = DowncastBothNode::new(args[5]);
let color: DowncastBothNode<(), Color> = DowncastBothNode::new(args[6]);
let stamp = BrushStampGeneratorNode::new(color, CopiedNode::new(hardness.eval(())), CopiedNode::new(flow.eval(()))); let stamp = BrushStampGeneratorNode::new(CopiedNode::new(color.eval(()).await), CopiedNode::new(hardness.eval(()).await), CopiedNode::new(flow.eval(()).await));
let stamp = stamp.eval(diameter.eval(())); let stamp = stamp.eval(diameter.eval(()).await);
let frames = TranslateNode::new(CopiedNode::new(stamp)); let frames = TranslateNode::new(CopiedNode::new(stamp));
let frames = MapNode::new(ValueNode::new(frames)); let frames = MapNode::new(ValueNode::new(frames));
let frames = frames.eval(trace.eval(()).into_iter()).collect::<Vec<_>>(); let frames = frames.eval(trace.eval(()).await.into_iter()).collect::<Vec<_>>();
let background_bounds = ReduceNode::new(ClonedNode::new(None), ValueNode::new(MergeBoundingBoxNode::new())); let background_bounds = ReduceNode::new(ClonedNode::new(None), ValueNode::new(MergeBoundingBoxNode::new()));
let background_bounds = background_bounds.eval(frames.clone().into_iter()); let background_bounds = background_bounds.eval(frames.clone().into_iter());
let background_bounds = MergeBoundingBoxNode::new().eval((background_bounds, image.eval(()))); let background_bounds = MergeBoundingBoxNode::new().eval((background_bounds, image.eval(()).await));
let mut background_bounds = CopiedNode::new(background_bounds.unwrap().to_transform()); let mut background_bounds = CopiedNode::new(background_bounds.unwrap().to_transform());
let bounds_transform = bounds.eval(()).transform; let bounds_transform = bounds.eval(()).await.transform;
if bounds_transform != DAffine2::ZERO { if bounds_transform != DAffine2::ZERO {
background_bounds = CopiedNode::new(bounds_transform); background_bounds = CopiedNode::new(bounds_transform);
} }
let background_image = background_bounds.then(EmptyImageNode::new(CopiedNode::new(Color::TRANSPARENT))); let background_image = background_bounds.then(EmptyImageNode::new(CopiedNode::new(Color::TRANSPARENT)));
let blend_node = graphene_core::raster::BlendNode::new(CopiedNode::new(BlendMode::Normal), CopiedNode::new(100.)); let blend_node = graphene_core::raster::BlendNode::new(CopiedNode::new(BlendMode::Normal), CopiedNode::new(100.));
let background = ExtendImageNode::new(background_image); let background = ExtendImageNode::new(background_image);
let background_image = image.then(background); let background_image = image.and_then(background);
let final_image = ReduceNode::new(background_image, ValueNode::new(BlendImageTupleNode::new(ValueNode::new(blend_node)))); let final_image = ReduceNode::new(ClonedNode::new(background_image.eval(()).await), ValueNode::new(BlendImageTupleNode::new(ValueNode::new(blend_node))));
let final_image = ClonedNode::new(frames.into_iter()).then(final_image); let final_image = ClonedNode::new(frames.into_iter()).then(final_image);
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(final_image)); let final_image = FutureWrapperNode::new(final_image);
Box::pin(any) let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(final_image));
any.into_type_erased()
})
}, },
NodeIOTypes::new( NodeIOTypes::new(
concrete!(()), concrete!(()),
@ -277,14 +306,17 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
vec![( vec![(
NodeIdentifier::new("graphene_std::brush::ReduceNode<_, _>"), NodeIdentifier::new("graphene_std::brush::ReduceNode<_, _>"),
|args| { |args| {
let acc: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]); Box::pin(async move {
let image = acc.eval(()); let acc: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
let blend_node = graphene_core::raster::BlendNode::new(ClonedNode::new(BlendMode::Normal), ClonedNode::new(1.0)); let image = acc.eval(()).await;
let _ = &blend_node as &dyn for<'i> Node<'i, (Color, Color), Output = Color>; let blend_node = graphene_core::raster::BlendNode::new(ClonedNode::new(BlendMode::Normal), ClonedNode::new(1.0));
let node = ReduceNode::new(ClonedNode::new(image), ValueNode::new(BlendImageTupleNode::new(ValueNode::new(blend_node)))); let _ = &blend_node as &dyn for<'i> Node<'i, (Color, Color), Output = Color>;
//let _ = &node as &dyn for<'i> Node<'i, core::slice::Iter<ImageFrame<Color>>, Output = ImageFrame<Color>>; let node = ReduceNode::new(ClonedNode::new(image), ValueNode::new(BlendImageTupleNode::new(ValueNode::new(blend_node))));
let any: DynAnyNode<Box<dyn Iterator<Item = ImageFrame<Color>> + Sync + Send>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(node)); //let _ = &node as &dyn for<'i> Node<'i, core::slice::Iter<ImageFrame<Color>>, Output = ImageFrame<Color>>;
Box::pin(any) let node = FutureWrapperNode::new(node);
let any: DynAnyNode<Box<dyn Iterator<Item = ImageFrame<Color>> + Sync + Send>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(node));
any.into_type_erased()
})
}, },
NodeIOTypes::new( NodeIOTypes::new(
concrete!(Box<dyn Iterator<Item = &ImageFrame<Color>> + Sync + Send>), concrete!(Box<dyn Iterator<Item = &ImageFrame<Color>> + Sync + Send>),
@ -299,39 +331,25 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
raster_node!(graphene_core::raster::LevelsNode<_, _, _, _, _>, params: [f64, f64, f64, f64, f64]), raster_node!(graphene_core::raster::LevelsNode<_, _, _, _, _>, params: [f64, f64, f64, f64, f64]),
register_node!(graphene_std::image_segmentation::ImageSegmentationNode<_>, input: ImageFrame<Color>, params: [ImageFrame<Color>]), register_node!(graphene_std::image_segmentation::ImageSegmentationNode<_>, input: ImageFrame<Color>, params: [ImageFrame<Color>]),
register_node!(graphene_core::raster::IndexNode<_>, input: Vec<ImageFrame<Color>>, params: [u32]), register_node!(graphene_core::raster::IndexNode<_>, input: Vec<ImageFrame<Color>>, params: [u32]),
vec![ vec![(
( NodeIdentifier::new("graphene_core::raster::BlendNode<_, _, _, _>"),
NodeIdentifier::new("graphene_core::raster::BlendNode<_, _, _, _>"), |args| {
|args| { Box::pin(async move {
let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]); let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
let blend_mode: DowncastBothNode<(), BlendMode> = DowncastBothNode::new(args[1]); let blend_mode: DowncastBothNode<(), BlendMode> = DowncastBothNode::new(args[1]);
let opacity: DowncastBothNode<(), f64> = DowncastBothNode::new(args[2]); let opacity: DowncastBothNode<(), f64> = DowncastBothNode::new(args[2]);
let blend_node = graphene_core::raster::BlendNode::new(CopiedNode::new(blend_mode.eval(())), CopiedNode::new(opacity.eval(()))); let blend_node = graphene_core::raster::BlendNode::new(CopiedNode::new(blend_mode.eval(()).await), CopiedNode::new(opacity.eval(()).await));
let node = graphene_std::raster::BlendImageNode::new(image, ValueNode::new(blend_node)); let node = graphene_std::raster::BlendImageNode::new(image, FutureWrapperNode::new(ValueNode::new(blend_node)));
let _ = &node as &dyn for<'i> Node<'i, ImageFrame<Color>, Output = ImageFrame<Color>>;
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node)); let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
any.into_type_erased() Box::pin(any) as TypeErasedPinned
}, })
NodeIOTypes::new( },
concrete!(ImageFrame<Color>), NodeIOTypes::new(
concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>),
vec![value_fn!(ImageFrame<Color>), value_fn!(BlendMode), value_fn!(f64)], concrete!(ImageFrame<Color>),
), vec![value_fn!(ImageFrame<Color>), value_fn!(BlendMode), value_fn!(f64)],
), ),
( )],
NodeIdentifier::new("graphene_core::raster::EraseNode<_, _>"),
|args| {
let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
let opacity: DowncastBothNode<(), f64> = DowncastBothNode::new(args[1]);
let blend_node = graphene_std::brush::EraseNode::new(ClonedNode::new(opacity.eval(())));
let node = graphene_std::raster::BlendImageNode::new(image, ValueNode::new(blend_node));
let _ = &node as &dyn for<'i> Node<'i, ImageFrame<Color>, Output = ImageFrame<Color>>;
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
any.into_type_erased()
},
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>), value_fn!(f64)]),
),
],
raster_node!(graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>, params: [Color, f64, f64, f64, f64, f64, f64]), raster_node!(graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>, params: [Color, f64, f64, f64, f64, f64, f64]),
raster_node!(graphene_core::raster::HueSaturationNode<_, _, _>, params: [f64, f64, f64]), raster_node!(graphene_core::raster::HueSaturationNode<_, _, _>, params: [f64, f64, f64]),
raster_node!(graphene_core::raster::InvertRGBNode, params: []), raster_node!(graphene_core::raster::InvertRGBNode, params: []),
@ -348,25 +366,29 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
vec![( vec![(
NodeIdentifier::new("graphene_core::raster::BrightnessContrastNode<_, _, _>"), NodeIdentifier::new("graphene_core::raster::BrightnessContrastNode<_, _, _>"),
|args| { |args| {
use graphene_core::raster::brightness_contrast::*; Box::pin(async move {
use graphene_core::raster::brightness_contrast::*;
let brightness: DowncastBothNode<(), f64> = DowncastBothNode::new(args[0]); let brightness: DowncastBothNode<(), f64> = DowncastBothNode::new(args[0]);
let brightness = ClonedNode::new(brightness.eval(()) as f32); let brightness = ClonedNode::new(brightness.eval(()).await as f32);
let contrast: DowncastBothNode<(), f64> = DowncastBothNode::new(args[1]); let contrast: DowncastBothNode<(), f64> = DowncastBothNode::new(args[1]);
let contrast = ClonedNode::new(contrast.eval(()) as f32); let contrast = ClonedNode::new(contrast.eval(()).await as f32);
let use_legacy: DowncastBothNode<(), bool> = DowncastBothNode::new(args[2]); let use_legacy: DowncastBothNode<(), bool> = DowncastBothNode::new(args[2]);
if use_legacy.eval(()) { if use_legacy.eval(()).await {
let generate_brightness_contrast_legacy_mapper_node = GenerateBrightnessContrastLegacyMapperNode::new(brightness, contrast); let generate_brightness_contrast_legacy_mapper_node = GenerateBrightnessContrastLegacyMapperNode::new(brightness, contrast);
let map_image_frame_node = graphene_std::raster::MapImageNode::new(ValueNode::new(generate_brightness_contrast_legacy_mapper_node.eval(()))); let map_image_frame_node = graphene_std::raster::MapImageNode::new(ValueNode::new(generate_brightness_contrast_legacy_mapper_node.eval(())));
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(map_image_frame_node)); let map_image_frame_node = FutureWrapperNode::new(map_image_frame_node);
Box::pin(any) let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(map_image_frame_node));
} else { Box::pin(any) as TypeErasedPinned
let generate_brightness_contrast_mapper_node = GenerateBrightnessContrastMapperNode::new(brightness, contrast); } else {
let map_image_frame_node = graphene_std::raster::MapImageNode::new(ValueNode::new(generate_brightness_contrast_mapper_node.eval(()))); let generate_brightness_contrast_mapper_node = GenerateBrightnessContrastMapperNode::new(brightness, contrast);
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(map_image_frame_node)); let map_image_frame_node = graphene_std::raster::MapImageNode::new(ValueNode::new(generate_brightness_contrast_mapper_node.eval(())));
Box::pin(any) let map_image_frame_node = FutureWrapperNode::new(map_image_frame_node);
} let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(map_image_frame_node));
Box::pin(any) as TypeErasedPinned
}
})
}, },
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(f64), value_fn!(f64), value_fn!(bool)]), NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(f64), value_fn!(f64), value_fn!(bool)]),
)], )],
@ -377,88 +399,102 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
( (
NodeIdentifier::new("graphene_std::memo::LetNode<_>"), NodeIdentifier::new("graphene_std::memo::LetNode<_>"),
|_| { |_| {
let node: LetNode<ImageFrame<Color>> = graphene_std::memo::LetNode::new(); Box::pin(async move {
let any = graphene_std::any::DynAnyRefNode::new(node); let node: LetNode<ImageFrame<Color>> = graphene_std::memo::LetNode::new();
any.into_type_erased() let any = graphene_std::any::DynAnyRefNode::new(node);
any.into_type_erased()
})
}, },
NodeIOTypes::new(concrete!(Option<ImageFrame<Color>>), concrete!(&ImageFrame<Color>), vec![]), NodeIOTypes::new(concrete!(Option<ImageFrame<Color>>), concrete!(&ImageFrame<Color>), vec![]),
), ),
( (
NodeIdentifier::new("graphene_std::memo::LetNode<_>"), NodeIdentifier::new("graphene_std::memo::LetNode<_>"),
|_| { |_| {
let node: LetNode<graphene_core::EditorApi> = graphene_std::memo::LetNode::new(); Box::pin(async move {
let any = graphene_std::any::DynAnyRefNode::new(node); let node: LetNode<graphene_core::EditorApi> = graphene_std::memo::LetNode::new();
any.into_type_erased() let any = graphene_std::any::DynAnyRefNode::new(node);
any.into_type_erased()
})
}, },
NodeIOTypes::new(concrete!(Option<graphene_core::EditorApi>), concrete!(&graphene_core::EditorApi), vec![]), NodeIOTypes::new(concrete!(Option<graphene_core::EditorApi>), concrete!(&graphene_core::EditorApi), vec![]),
), ),
( (
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"), NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|args| { |args| {
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]); Box::pin(async move {
let node = graphene_std::memo::EndLetNode::new(input); let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node); let node = graphene_std::memo::EndLetNode::new(input);
any.into_type_erased() let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
Box::pin(any) as TypeErasedPinned<'_>
})
}, },
NodeIOTypes::new(generic!(T), concrete!(graphene_core::EditorApi), vec![value_fn!(ImageFrame<Color>)]), NodeIOTypes::new(generic!(T), concrete!(ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>)]),
), ),
( (
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"), NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|args| { |args| {
let input: DowncastBothNode<(), VectorData> = DowncastBothNode::new(args[0]); Box::pin(async move {
let node = graphene_std::memo::EndLetNode::new(input); let input: DowncastBothNode<(), VectorData> = DowncastBothNode::new(args[0]);
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node); let node = graphene_std::memo::EndLetNode::new(input);
any.into_type_erased() let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
Box::pin(any) as TypeErasedPinned
})
}, },
NodeIOTypes::new(generic!(T), concrete!(graphene_core::EditorApi), vec![value_fn!(VectorData)]), NodeIOTypes::new(generic!(T), concrete!(VectorData), vec![value_fn!(VectorData)]),
), ),
( (
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"), NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|args| { |args| {
let input: DowncastBothNode<(), graphene_core::GraphicGroup> = DowncastBothNode::new(args[0]); Box::pin(async move {
let node = graphene_std::memo::EndLetNode::new(input); let input: DowncastBothNode<(), graphene_core::GraphicGroup> = DowncastBothNode::new(args[0]);
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node); let node = graphene_std::memo::EndLetNode::new(input);
any.into_type_erased() let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
Box::pin(any) as TypeErasedPinned
})
}, },
NodeIOTypes::new(generic!(T), concrete!(graphene_core::EditorApi), vec![value_fn!(graphene_core::GraphicGroup)]), NodeIOTypes::new(generic!(T), concrete!(graphene_core::GraphicGroup), vec![value_fn!(graphene_core::GraphicGroup)]),
), ),
( (
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"), NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|args| { |args| {
let input: DowncastBothNode<(), graphene_core::Artboard> = DowncastBothNode::new(args[0]); Box::pin(async move {
let node = graphene_std::memo::EndLetNode::new(input); let input: DowncastBothNode<(), graphene_core::Artboard> = DowncastBothNode::new(args[0]);
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node); let node = graphene_std::memo::EndLetNode::new(input);
any.into_type_erased() let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
Box::pin(any) as TypeErasedPinned
})
}, },
NodeIOTypes::new(generic!(T), concrete!(graphene_core::EditorApi), vec![value_fn!(graphene_core::Artboard)]), NodeIOTypes::new(generic!(T), concrete!(graphene_core::Artboard), vec![value_fn!(graphene_core::Artboard)]),
), ),
( (
NodeIdentifier::new("graphene_std::memo::RefNode<_, _>"), NodeIdentifier::new("graphene_std::memo::RefNode<_, _>"),
|args| { |args| {
let map_fn: DowncastBothRefNode<Option<graphene_core::EditorApi>, graphene_core::EditorApi> = DowncastBothRefNode::new(args[0]); Box::pin(async move {
let node = graphene_std::memo::RefNode::new(map_fn); let map_fn: DowncastBothNode<Option<graphene_core::EditorApi>, &graphene_core::EditorApi> = DowncastBothNode::new(args[0]);
let any = graphene_std::any::DynAnyRefNode::new(node); //let map_fn = map_fn.then(EvalSyncNode::new());
any.into_type_erased() let node = graphene_std::memo::RefNode::new(map_fn);
let any = graphene_std::any::DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
}, },
NodeIOTypes::new(concrete!(()), concrete!(&graphene_core::EditorApi), vec![]), NodeIOTypes::new(
), concrete!(()),
( concrete!(&graphene_core::EditorApi),
NodeIdentifier::new("graphene_core::structural::MapImageNode"), vec![fn_type!(Option<graphene_core::EditorApi>, &graphene_core::EditorApi)],
|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<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
any.into_type_erased()
},
NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), vec![]),
), ),
/*
( (
NodeIdentifier::new("graphene_std::raster::ImaginateNode<_>"), NodeIdentifier::new("graphene_std::raster::ImaginateNode<_>"),
|args| { |args| {
let cached = graphene_std::any::input_node::<Option<std::sync::Arc<Image<Color>>>>(args[15]); Box::pin(async move {
let node = graphene_std::raster::ImaginateNode::new(cached); let cached = graphene_std::any::input_node::<Option<std::sync::Arc<Image<Color>>>>(args[15]);
let any = DynAnyNode::new(ValueNode::new(node)); let cached = cached.then(EvalSyncNode::new());
any.into_type_erased() let node = graphene_std::raster::ImaginateNode::new(cached);
let node = FutureWrapperNode::new(node);
let any = DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
}, },
NodeIOTypes::new( NodeIOTypes::new(
concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>),
@ -485,12 +521,15 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
], ],
), ),
), ),
*/
/*
( (
NodeIdentifier::new("graphene_core::raster::BlurNode"), NodeIdentifier::new("graphene_core::raster::BlurNode"),
|args| { |args| {
let radius = DowncastBothNode::<(), u32>::new(args[0]); let radius = DowncastBothNode::<(), u32>::new(args[0]);
let sigma = DowncastBothNode::<(), f64>::new(args[1]); let sigma = DowncastBothNode::<(), f64>::new(args[1]);
let image = DowncastBothRefNode::<Image<Color>, Image<Color>>::new(args[2]); let image = DowncastBothRefNode::<Image<Color>, Image<Color>>::new(args[2]);
let image = image.then(EvalSyncNode::new());
let empty_image: ValueNode<Image<Color>> = ValueNode::new(Image::empty()); let empty_image: ValueNode<Image<Color>> = ValueNode::new(Image::empty());
let empty: TypeNode<_, (), Image<Color>> = TypeNode::new(empty_image.then(CloneNode::new())); let empty: TypeNode<_, (), Image<Color>> = TypeNode::new(empty_image.then(CloneNode::new()));
use graphene_core::Node; use graphene_core::Node;
@ -517,61 +556,73 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
let dimensions: TypeNode<_, (), (u32, u32)> = TypeNode::new(dimensions); let dimensions: TypeNode<_, (), (u32, u32)> = TypeNode::new(dimensions);
let new_image = dimensions.then(new_image); let new_image = dimensions.then(new_image);
let new_image = ForgetNode::new().then(new_image); let new_image = ForgetNode::new().then(new_image);
let new_image = FutureWrapperNode::new(new_image);
let node: DynAnyNode<&Image<Color>, _, _> = DynAnyNode::new(ValueNode::new(new_image)); let node: DynAnyNode<&Image<Color>, _, _> = DynAnyNode::new(ValueNode::new(new_image));
node.into_type_erased() Box::pin(node)
}, },
NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), vec![value_fn!(u32), value_fn!(f64)]), NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), vec![value_fn!(u32), value_fn!(f64)]),
), ),
//register_node!(graphene_std::memo::CacheNode<_>, input: Image<Color>, params: []), //register_node!(graphene_std::memo::CacheNode<_>, input: Image<Color>, params: []),
*/
( (
NodeIdentifier::new("graphene_std::memo::CacheNode"), NodeIdentifier::new("graphene_std::memo::CacheNode"),
|args| { |args| {
let input: DowncastBothNode<(), Image<Color>> = DowncastBothNode::new(args[0]); Box::pin(async move {
let node: CacheNode<Image<Color>, _> = graphene_std::memo::CacheNode::new(input); let input: DowncastBothNode<(), Image<Color>> = DowncastBothNode::new(args[0]);
let any = DynAnyRefNode::new(node); let node: CacheNode<Image<Color>, _> = graphene_std::memo::CacheNode::new(input);
any.into_type_erased() let any = DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
}, },
NodeIOTypes::new(concrete!(()), concrete!(&Image<Color>), vec![value_fn!(Image<Color>)]), NodeIOTypes::new(concrete!(()), concrete!(Image<Color>), vec![value_fn!(Image<Color>)]),
), ),
( (
NodeIdentifier::new("graphene_std::memo::CacheNode"), NodeIdentifier::new("graphene_std::memo::CacheNode"),
|args| { |args| {
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]); Box::pin(async move {
let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input); let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
let any = DynAnyRefNode::new(node); let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input);
any.into_type_erased() let any = DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
}, },
NodeIOTypes::new(concrete!(()), concrete!(&ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>)]), NodeIOTypes::new(concrete!(()), concrete!(ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>)]),
), ),
( (
NodeIdentifier::new("graphene_std::memo::CacheNode"), NodeIdentifier::new("graphene_std::memo::CacheNode"),
|args| { |args| {
let input: DowncastBothNode<ImageFrame<Color>, ImageFrame<Color>> = DowncastBothNode::new(args[0]); Box::pin(async move {
let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input); let input: DowncastBothNode<ImageFrame<Color>, ImageFrame<Color>> = DowncastBothNode::new(args[0]);
let any = DynAnyRefNode::new(node); let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input);
any.into_type_erased() let any = DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
}, },
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(&ImageFrame<Color>), vec![fn_type!(ImageFrame<Color>, ImageFrame<Color>)]), NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(ImageFrame<Color>, ImageFrame<Color>)]),
), ),
( (
NodeIdentifier::new("graphene_std::memo::CacheNode"), NodeIdentifier::new("graphene_std::memo::CacheNode"),
|args| { |args| {
let input: DowncastBothNode<(), QuantizationChannels> = DowncastBothNode::new(args[0]); Box::pin(async move {
let node: CacheNode<QuantizationChannels, _> = graphene_std::memo::CacheNode::new(input); let input: DowncastBothNode<(), QuantizationChannels> = DowncastBothNode::new(args[0]);
let any = DynAnyRefNode::new(node); let node: CacheNode<QuantizationChannels, _> = graphene_std::memo::CacheNode::new(input);
any.into_type_erased() let any = DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
}, },
NodeIOTypes::new(concrete!(()), concrete!(&QuantizationChannels), vec![value_fn!(QuantizationChannels)]), NodeIOTypes::new(concrete!(()), concrete!(QuantizationChannels), vec![value_fn!(QuantizationChannels)]),
), ),
( (
NodeIdentifier::new("graphene_std::memo::CacheNode"), NodeIdentifier::new("graphene_std::memo::CacheNode"),
|args| { |args| {
let input: DowncastBothNode<(), Vec<DVec2>> = DowncastBothNode::new(args[0]); Box::pin(async move {
let node: CacheNode<Vec<DVec2>, _> = graphene_std::memo::CacheNode::new(input); let input: DowncastBothNode<(), Vec<DVec2>> = DowncastBothNode::new(args[0]);
let any = DynAnyRefNode::new(node); let node: CacheNode<Vec<DVec2>, _> = graphene_std::memo::CacheNode::new(input);
any.into_type_erased() let any = DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
})
}, },
NodeIOTypes::new(concrete!(()), concrete!(&Vec<DVec2>), vec![value_fn!(Vec<DVec2>)]), NodeIOTypes::new(concrete!(()), concrete!(Vec<DVec2>), vec![value_fn!(Vec<DVec2>)]),
), ),
], ],
register_node!(graphene_core::structural::ConsNode<_, _>, input: Image<Color>, params: [&str]), register_node!(graphene_core::structural::ConsNode<_, _>, input: Image<Color>, params: [&str]),
@ -595,9 +646,9 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
input: Vec<graphene_core::vector::bezier_rs::Subpath<graphene_core::uuid::ManipulatorGroupId>>, input: Vec<graphene_core::vector::bezier_rs::Subpath<graphene_core::uuid::ManipulatorGroupId>>,
params: [Vec<graphene_core::uuid::ManipulatorGroupId>] params: [Vec<graphene_core::uuid::ManipulatorGroupId>]
), ),
register_node!(graphene_core::text::TextGenerator<_, _, _>, input: graphene_core::EditorApi, params: [String, graphene_core::text::Font, f64]), register_node!(graphene_core::text::TextGenerator<_, _, _>, input: &graphene_core::EditorApi, params: [String, graphene_core::text::Font, f64]),
register_node!(graphene_std::brush::VectorPointsNode, input: VectorData, params: []), register_node!(graphene_std::brush::VectorPointsNode, input: VectorData, params: []),
register_node!(graphene_core::ExtractImageFrame, input: graphene_core::EditorApi, params: []), register_node!(graphene_core::ExtractImageFrame, input: &graphene_core::EditorApi, params: []),
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::vector::VectorData, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]), register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::vector::VectorData, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: ImageFrame<Color>, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]), register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: ImageFrame<Color>, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::GraphicGroup, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]), register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::GraphicGroup, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),

View file

@ -1,6 +1,6 @@
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro2::Span; use proc_macro2::Span;
use quote::{format_ident, ToTokens}; use quote::{format_ident, quote, ToTokens};
use syn::{ use syn::{
parse_macro_input, punctuated::Punctuated, token::Comma, FnArg, GenericParam, Ident, ItemFn, Lifetime, Pat, PatIdent, PathArguments, PredicateType, ReturnType, Token, TraitBound, Type, TypeParam, parse_macro_input, punctuated::Punctuated, token::Comma, FnArg, GenericParam, Ident, ItemFn, Lifetime, Pat, PatIdent, PathArguments, PredicateType, ReturnType, Token, TraitBound, Type, TypeParam,
TypeParamBound, WhereClause, WherePredicate, TypeParamBound, WhereClause, WherePredicate,
@ -8,14 +8,69 @@ use syn::{
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream { pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
//let node_name = parse_macro_input!(attr as Ident); let mut imp = node_impl_proxy(attr.clone(), item.clone());
let new = node_new_impl(attr, item);
imp.extend(new);
imp
}
#[proc_macro_attribute]
pub fn node_new(attr: TokenStream, item: TokenStream) -> TokenStream {
node_new_impl(attr, item)
}
#[proc_macro_attribute]
pub fn node_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
node_impl_proxy(attr, item)
}
fn node_new_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
let node = parse_macro_input!(attr as syn::PathSegment); let node = parse_macro_input!(attr as syn::PathSegment);
let function = parse_macro_input!(item as ItemFn); let function = parse_macro_input!(item as ItemFn);
let node = &node; let node = &node;
let node_name = &node.ident; let node_name = &node.ident;
let mut args = match node.arguments.clone() { let mut args = args(node);
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 (_, _, parameter_pat_ident_patterns) = parse_inputs(&function);
let parameter_idents = parameter_pat_ident_patterns.iter().map(|pat_ident| &pat_ident.ident).collect::<Vec<_>>();
// Extract the output type of the entire node - `()` by default
let struct_generics = (0..parameter_pat_ident_patterns.len())
.map(|x| {
let ident = format_ident!("S{x}");
ident
})
.collect::<Punctuated<_, Comma>>();
for ident in struct_generics.iter() {
args.push(Type::Verbatim(quote::quote!(#ident)));
}
let struct_generics_iter = struct_generics.iter();
quote::quote! {
#[automatically_derived]
impl <#(#args),*> #node_name<#(#args),*>
{
pub const fn new(#(#parameter_idents: #struct_generics_iter),*) -> Self{
Self{
#(#parameter_idents,)*
#(#arg_idents: core::marker::PhantomData,)*
}
}
}
}
.into()
}
fn args(node: &syn::PathSegment) -> Vec<Type> {
match node.arguments.clone() {
PathArguments::AngleBracketed(args) => args PathArguments::AngleBracketed(args) => args
.args .args
.into_iter() .into_iter()
@ -25,53 +80,59 @@ pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
_ => Default::default(), _ => Default::default(),
}
}
fn node_impl_proxy(attr: TokenStream, item: TokenStream) -> TokenStream {
let fn_item = item.clone();
let function = parse_macro_input!(fn_item as ItemFn);
let sync_input = if function.sig.asyncness.is_some() {
node_impl_impl(attr, item, Asyncness::AllAsync)
} else {
node_impl_impl(attr, item, Asyncness::Sync)
}; };
let arg_idents = args sync_input
.iter() }
.filter(|x| x.to_token_stream().to_string().starts_with('_')) enum Asyncness {
.map(|arg| Ident::new(arg.to_token_stream().to_string().to_lowercase().as_str(), Span::call_site())) Sync,
.collect::<Vec<_>>(); AsyncOut,
AllAsync,
}
let mut function_inputs = function.sig.inputs.iter().filter_map(|arg| if let FnArg::Typed(typed_arg) = arg { Some(typed_arg) } else { None }); fn node_impl_impl(attr: TokenStream, item: TokenStream, asyncness: Asyncness) -> TokenStream {
//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 node = &node;
let node_name = &node.ident;
let mut args = args(node);
let async_out = match asyncness {
Asyncness::Sync => false,
Asyncness::AsyncOut | Asyncness::AllAsync => true,
};
let async_in = matches!(asyncness, Asyncness::AllAsync);
let body = &function.block;
let mut type_generics = function.sig.generics.params.clone(); let mut type_generics = function.sig.generics.params.clone();
let mut where_clause = function.sig.generics.where_clause.clone().unwrap_or(WhereClause { let mut where_clause = function.sig.generics.where_clause.clone().unwrap_or(WhereClause {
where_token: Token![where](Span::call_site()), where_token: Token![where](Span::call_site()),
predicates: Default::default(), predicates: Default::default(),
}); });
// Extract primary input as first argument type_generics.iter_mut().for_each(|x| {
let primary_input = function_inputs.next().expect("Primary input required - set to `()` if not needed."); if let GenericParam::Type(t) = x {
t.bounds.insert(0, TypeParamBound::Lifetime(Lifetime::new("'input", Span::call_site())));
}
});
let (primary_input, parameter_inputs, parameter_pat_ident_patterns) = parse_inputs(&function);
let primary_input_ty = &primary_input.ty;
let Pat::Ident(PatIdent{ident: primary_input_ident, mutability: primary_input_mutability,..} ) =&*primary_input.pat else { let Pat::Ident(PatIdent{ident: primary_input_ident, mutability: primary_input_mutability,..} ) =&*primary_input.pat else {
panic!("Expected ident as primary input."); panic!("Expected ident as primary input.");
}; };
let primary_input_ty = &primary_input.ty;
let aux_type_generics = type_generics
.iter()
.filter(|gen| {
if let GenericParam::Type(ty) = gen {
!function.sig.inputs.iter().take(1).any(|param_ty| match param_ty {
FnArg::Typed(pat_ty) => ty.ident == pat_ty.ty.to_token_stream().to_string(),
_ => false,
})
} else {
false
}
})
.cloned()
.collect::<Vec<_>>();
let body = function.block;
// Extract secondary inputs as all other arguments
let parameter_inputs = function_inputs.collect::<Vec<_>>();
let parameter_pat_ident_patterns = parameter_inputs
.iter()
.map(|input| {
let Pat::Ident(pat_ident) = &*input.pat else { panic!("Expected ident for secondary input."); };
pat_ident
})
.collect::<Vec<_>>();
let parameter_idents = parameter_pat_ident_patterns.iter().map(|pat_ident| &pat_ident.ident).collect::<Vec<_>>(); let parameter_idents = parameter_pat_ident_patterns.iter().map(|pat_ident| &pat_ident.ident).collect::<Vec<_>>();
let parameter_mutability = parameter_pat_ident_patterns.iter().map(|pat_ident| &pat_ident.mutability); let parameter_mutability = parameter_pat_ident_patterns.iter().map(|pat_ident| &pat_ident.mutability);
@ -82,20 +143,94 @@ pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
quote::quote!(()) quote::quote!(())
}; };
let struct_generics = (0..parameter_inputs.len()) let struct_generics = (0..parameter_pat_ident_patterns.len()).map(|x| format_ident!("S{x}")).collect::<Vec<_>>();
.map(|x| { let future_generics = (0..parameter_pat_ident_patterns.len()).map(|x| format_ident!("F{x}")).collect::<Vec<_>>();
let ident = format_ident!("S{x}"); let future_types = future_generics.iter().map(|x| Type::Verbatim(x.to_token_stream())).collect::<Vec<_>>();
ident let parameter_types = parameter_inputs.iter().map(|x| *x.ty.clone()).collect::<Vec<Type>>();
})
.collect::<Punctuated<_, Comma>>();
let struct_generics_iter = struct_generics.iter();
for ident in struct_generics.iter() { for ident in struct_generics.iter() {
args.push(Type::Verbatim(quote::quote!(#ident))); args.push(Type::Verbatim(quote::quote!(#ident)));
} }
// Generics are simply `S0` through to `Sn-1` where n is the number of secondary inputs // Generics are simply `S0` through to `Sn-1` where n is the number of secondary inputs
let node_generics = struct_generics let node_generics = construct_node_generics(&struct_generics);
let future_generic_params = construct_node_generics(&future_generics);
let generics = if async_in {
type_generics
.into_iter()
.chain(node_generics.iter().cloned())
.chain(future_generic_params.iter().cloned())
.collect::<Punctuated<_, Comma>>()
} else {
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 node_bounds = if async_in {
let mut node_bounds = input_node_bounds(future_types, node_generics, |ty| quote! {Node<'input, (), Output = #ty>});
let future_bounds = input_node_bounds(parameter_types, future_generic_params, |ty| quote! { core::future::Future<Output = #ty>});
node_bounds.extend(future_bounds);
node_bounds
} else {
input_node_bounds(parameter_types, node_generics, |ty| quote! {Node<'input, (), Output = #ty>})
};
where_clause.predicates.extend(node_bounds);
let output = if async_out {
quote::quote!(core::pin::Pin<Box<dyn core::future::Future< Output = #output> + 'input>>)
} else {
quote::quote!(#output)
};
let parameters = if matches!(asyncness, Asyncness::AllAsync) {
quote::quote!(#(let #parameter_mutability #parameter_idents = self.#parameter_idents.eval(()).await;)*)
} else {
quote::quote!(#(let #parameter_mutability #parameter_idents = self.#parameter_idents.eval(());)*)
};
let mut body_with_inputs = quote::quote!(
#parameters
{#body}
);
if async_out {
body_with_inputs = quote::quote!(Box::pin(async move { #body_with_inputs }));
}
quote::quote! {
#[automatically_derived]
impl <'input, #generics> Node<'input, #primary_input_ty> for #node_name<#(#args),*>
#where_clause
{
type Output = #output;
#[inline]
fn eval(&'input self, #primary_input_mutability #primary_input_ident: #primary_input_ty) -> Self::Output {
#body_with_inputs
}
}
}
.into()
}
fn parse_inputs(function: &ItemFn) -> (&syn::PatType, Vec<&syn::PatType>, Vec<&PatIdent>) {
let mut function_inputs = function.sig.inputs.iter().filter_map(|arg| if let FnArg::Typed(typed_arg) = arg { Some(typed_arg) } else { None });
// Extract primary input as first argument
let primary_input = function_inputs.next().expect("Primary input required - set to `()` if not needed.");
// Extract secondary inputs as all other arguments
let parameter_inputs = function_inputs.collect::<Vec<_>>();
let parameter_pat_ident_patterns = parameter_inputs
.iter()
.map(|input| {
let Pat::Ident(pat_ident) = &*input.pat else { panic!("Expected ident for secondary input."); };
pat_ident
})
.collect::<Vec<_>>();
(primary_input, parameter_inputs, parameter_pat_ident_patterns)
}
fn construct_node_generics(struct_generics: &[Ident]) -> Vec<GenericParam> {
struct_generics
.iter() .iter()
.cloned() .cloned()
.map(|ident| { .map(|ident| {
@ -108,22 +243,17 @@ pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
default: None, default: None,
}) })
}) })
.collect::<Punctuated<_, Comma>>(); .collect()
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()))); fn input_node_bounds(parameter_inputs: Vec<Type>, node_generics: Vec<GenericParam>, trait_bound: impl Fn(Type) -> proc_macro2::TokenStream) -> Vec<WherePredicate> {
} parameter_inputs
});
let generics = type_generics.into_iter().chain(node_generics.iter().cloned()).collect::<Punctuated<_, Comma>>();
let new_fn_generics = aux_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() .iter()
.zip(&node_generics) .zip(&node_generics)
.map(|(ty, name)| { .map(|(ty, name)| {
let ty = &ty.ty;
let GenericParam::Type(generic_ty) = name else { panic!("Expected type generic."); }; let GenericParam::Type(generic_ty) = name else { panic!("Expected type generic."); };
let ident = &generic_ty.ident; let ident = &generic_ty.ident;
let bound = trait_bound(ty.clone());
WherePredicate::Type(PredicateType { WherePredicate::Type(PredicateType {
lifetimes: None, lifetimes: None,
bounded_ty: Type::Verbatim(ident.to_token_stream()), bounded_ty: Type::Verbatim(ident.to_token_stream()),
@ -131,43 +261,10 @@ pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
bounds: Punctuated::from_iter([TypeParamBound::Trait(TraitBound { bounds: Punctuated::from_iter([TypeParamBound::Trait(TraitBound {
paren_token: None, paren_token: None,
modifier: syn::TraitBoundModifier::None, modifier: syn::TraitBoundModifier::None,
lifetimes: syn::parse_quote!(for<'any_input>), lifetimes: None, //syn::parse_quote!(for<'any_input>),
path: syn::parse_quote!(Node<'any_input, (), Output = #ty>), path: syn::parse_quote!(#bound),
})]), })]),
}) })
}) })
.collect::<Vec<_>>(); .collect()
where_clause.predicates.extend(extra_where_clause.clone());
let input_lifetime = if generics.is_empty() { quote::quote!() } else { quote::quote!('input,) };
quote::quote! {
impl <'input, #generics> Node<'input, #primary_input_ty> for #node_name<#(#args),*>
#where_clause
{
type Output = #output;
#[inline]
fn eval(&'input self, #primary_input_mutability #primary_input_ident: #primary_input_ty) -> Self::Output {
#(
let #parameter_mutability #parameter_idents = self.#parameter_idents.eval(());
)*
#body
}
}
impl <#input_lifetime #new_fn_generics> #node_name<#(#args),*>
where #(#extra_where_clause),*
{
pub const fn new(#(#parameter_idents: #struct_generics_iter),*) -> Self{
Self{
#(#parameter_idents,)*
#(#arg_idents: core::marker::PhantomData,)*
}
}
}
}
.into()
} }

View file

@ -2,6 +2,7 @@ use super::context::Context;
use graph_craft::executor::{Any, Executor}; use graph_craft::executor::{Any, Executor};
use graph_craft::proto::LocalFuture;
use graphene_core::gpu::PushConstants; use graphene_core::gpu::PushConstants;
use bytemuck::Pod; use bytemuck::Pod;
@ -38,7 +39,7 @@ impl<I: StaticTypeSized, O> GpuExecutor<I, O> {
} }
impl<I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync + Pod> Executor for GpuExecutor<I, O> { impl<I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync + Pod> Executor for GpuExecutor<I, O> {
fn execute<'i, 's: 'i>(&'s self, input: Any<'i>) -> Result<Any<'i>, Box<dyn std::error::Error>> { fn execute<'i>(&'i self, input: Any<'i>) -> LocalFuture<Result<Any<'i>, Box<dyn std::error::Error>>> {
let input = dyn_any::downcast::<Vec<I>>(input).expect("Wrong input type"); let input = dyn_any::downcast::<Vec<I>>(input).expect("Wrong input type");
let context = &self.context; let context = &self.context;
let result: Vec<O> = execute_shader( let result: Vec<O> = execute_shader(
@ -49,10 +50,11 @@ impl<I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync +
&context.command_buffer_allocator, &context.command_buffer_allocator,
*input, *input,
); );
Ok(Box::new(result)) Box::pin(async move { Ok(Box::new(result) as Any) })
} }
} }
// TODO: make async
fn execute_shader<I: Pod + Send + Sync, O: Pod + Send + Sync>( fn execute_shader<I: Pod + Send + Sync, O: Pod + Send + Sync>(
device: std::sync::Arc<Device>, device: std::sync::Arc<Device>,
queue: std::sync::Arc<vulkano::device::Queue>, queue: std::sync::Arc<vulkano::device::Queue>,

View file

@ -5,7 +5,10 @@ use wgpu::util::DeviceExt;
use super::context::Context; use super::context::Context;
use bytemuck::Pod; use bytemuck::Pod;
use dyn_any::StaticTypeSized; use dyn_any::StaticTypeSized;
use graph_craft::executor::{Any, Executor}; use graph_craft::{
executor::{Any, Executor},
proto::LocalFuture,
};
#[derive(Debug)] #[derive(Debug)]
pub struct GpuExecutor<'a, I: StaticTypeSized, O> { pub struct GpuExecutor<'a, I: StaticTypeSized, O> {
@ -27,14 +30,16 @@ 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> { impl<'a, I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync + Pod> Executor for GpuExecutor<'a, I, O> {
fn execute<'i, 's: 'i>(&'s self, input: Any<'i>) -> Result<Any<'i>, Box<dyn std::error::Error>> { fn execute<'i>(&'i self, input: Any<'i>) -> LocalFuture<Result<Any<'i>, Box<dyn std::error::Error>>> {
let input = dyn_any::downcast::<Vec<I>>(input).expect("Wrong input type"); let input = dyn_any::downcast::<Vec<I>>(input).expect("Wrong input type");
let context = &self.context; let context = &self.context;
let future = execute_shader(context.device.clone(), context.queue.clone(), self.shader.to_vec(), *input, self.entry_point.clone()); let future = execute_shader(context.device.clone(), context.queue.clone(), self.shader.to_vec(), *input, self.entry_point.clone());
let result = future_executor::block_on(future); Box::pin(async move {
let result = future.await;
let result: Vec<O> = result.ok_or_else(|| String::from("Failed to execute shader"))?; let result: Vec<O> = result.ok_or_else(|| String::from("Failed to execute shader"))?;
Ok(Box::new(result)) Ok(Box::new(result) as Any)
})
} }
} }