Test using slotmap

This commit is contained in:
Dennis Kobert 2023-06-01 23:50:34 +02:00 committed by Keavon Chambers
parent 95b23ce1af
commit f5fd0a8bd7
20 changed files with 395 additions and 386 deletions

13
Cargo.lock generated
View file

@ -1014,6 +1014,7 @@ name = "dyn-any"
version = "0.3.1"
dependencies = [
"dyn-any-derive",
"ghost-cell",
"glam",
"log",
]
@ -1424,6 +1425,12 @@ dependencies = [
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
name = "ghost-cell"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5fdd3f2182d5fad2c97a25af8992c30e844a775f8fc7339dae5328377d164e6"
[[package]]
name = "gimli"
version = "0.27.2"
@ -1652,11 +1659,14 @@ dependencies = [
"bytemuck",
"dyn-any",
"dyn-clone",
"futures",
"ghost-cell",
"glam",
"graphene-core",
"log",
"num-traits",
"serde",
"slotmap",
"specta",
"xxhash-rust",
]
@ -1670,6 +1680,7 @@ dependencies = [
"bezier-rs",
"bytemuck",
"dyn-any",
"ghost-cell",
"glam",
"js-sys",
"kurbo",
@ -1681,6 +1692,7 @@ dependencies = [
"rand_chacha 0.3.1",
"rustybuzz",
"serde",
"slotmap",
"specta",
"spin 0.9.8",
"spirv-std",
@ -1699,6 +1711,7 @@ dependencies = [
"dyn-any",
"dyn-clone",
"futures",
"ghost-cell",
"glam",
"gpu-compiler-bin-wrapper",
"gpu-executor",

View file

@ -7,9 +7,9 @@ use crate::messages::prelude::*;
use document_legacy::layers::layer_info::LayerDataType;
use document_legacy::{LayerId, Operation};
use graph_craft::compiler::Compiler;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{generate_uuid, DocumentNodeImplementation, NodeId, NodeNetwork};
use graph_craft::executor::Compiler;
use graph_craft::{concrete, Type, TypeDescriptor};
use graphene_core::application_io::ApplicationIo;
use graphene_core::raster::{Image, ImageFrame};
@ -19,7 +19,7 @@ use graphene_core::vector::style::ViewMode;
use graphene_core::wasm_application_io::WasmApplicationIo;
use graphene_core::{Color, EditorApi, SurfaceFrame, SurfaceId};
use interpreted_executor::executor::DynamicExecutor;
use interpreted_executor::dynamic_executor::DynamicExecutor;
use glam::{DAffine2, DVec2};
use std::borrow::Cow;
@ -147,7 +147,7 @@ impl NodeRuntime {
return Err(e);
}
use graph_craft::executor::Executor;
use graph_craft::compiler::Executor;
let result = match self.executor.input_type() {
Some(t) if t == concrete!(EditorApi) => (&self.executor).execute(editor_api).await.map_err(|e| e.to_string()),

View file

@ -15,6 +15,7 @@ documentation = "https://docs.rs/dyn-any"
dyn-any-derive = { path = "derive", version = "0.3.0", optional = true }
log = { version = "0.4", optional = true }
glam = { version = "0.22", optional = true, default-features = false }
ghost-cell = "0.2.3"
[features]
derive = ["dyn-any-derive"]

View file

@ -205,6 +205,12 @@ unsafe impl<T: StaticTypeSized> StaticType for dyn core::future::Future<Output =
unsafe impl<T: StaticTypeSized> StaticType for dyn core::future::Future<Output = T> + '_ {
type Static = dyn core::future::Future<Output = T::Static>;
}
unsafe impl<T: StaticType> StaticType for ghost_cell::GhostCell<'_, T> {
type Static = ghost_cell::GhostCell<'static, T::Static>;
}
unsafe impl StaticType for ghost_cell::GhostToken<'_> {
type Static = ghost_cell::GhostToken<'static>;
}
#[cfg(feature = "alloc")]
pub trait IntoDynAny<'n>: Sized + StaticType + 'n {
fn into_dyn(self) -> Box<dyn DynAny<'n> + 'n> {

View file

@ -14,7 +14,7 @@ fn main() {
let client = reqwest::blocking::Client::new();
let network = add_network();
let compiler = graph_craft::executor::Compiler {};
let compiler = graph_craft::compiler::Compiler {};
let proto_network = compiler.compile_single(network, true).unwrap();
let io = ShaderIO {

View file

@ -9,24 +9,10 @@ license = "MIT OR Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
std = [
"dyn-any",
"dyn-any/std",
"alloc",
"glam/std",
"specta",
"num-traits/std",
"rustybuzz",
]
std = ["dyn-any", "dyn-any/std", "alloc", "glam/std", "specta", "num-traits/std", "rustybuzz"]
default = ["async", "serde", "kurbo", "log", "std", "rand_chacha", "wasm"]
log = ["dep:log"]
serde = [
"dep:serde",
"glam/serde",
"bezier-rs/serde",
"bezier-rs/serde",
"base64",
]
serde = ["dep:serde", "glam/serde", "bezier-rs/serde", "bezier-rs/serde", "base64"]
gpu = ["spirv-std", "glam/bytemuck", "dyn-any", "glam/libm"]
async = ["async-trait", "alloc"]
nightly = []
@ -73,6 +59,8 @@ num-traits = { version = "0.2.15", default-features = false, features = [
wasm-bindgen = { version = "0.2.84", optional = true }
js-sys = { version = "0.3.55", optional = true }
ghost-cell = "0.2.3"
slotmap = { version = "1.0.6", default-features = false }
[dependencies.web-sys]
version = "0.3.4"

View file

@ -58,6 +58,7 @@ mod types;
#[cfg(feature = "alloc")]
pub use types::*;
use dyn_any::StaticTypeSized;
pub trait NodeIO<'i, Input: 'i>: 'i + Node<'i, Input>
where
Self::Output: 'i + StaticTypeSized,
@ -96,54 +97,81 @@ where
{
}
/*impl<'i, I: 'i, O: 'i> Node<'i, I> for &'i dyn for<'n> Node<'n, I, Output = O> {
use ghost_cell::{GhostCell, GhostToken};
impl<'i, 'brand, I: 'i, N: Node<'i, I>> Node<'i, (I, &'i GhostToken<'brand>)> for GhostCell<'brand, N> {
type Output = N::Output;
fn eval(&'i self, input: (I, &'i GhostToken<'brand>)) -> Self::Output {
self.borrow(input.1).eval(input.0)
}
}
#[cfg(feature = "alloc")]
pub mod dyn_exec {
use super::{Node, NodeIO};
use alloc::boxed::Box;
use core::pin::Pin;
use dyn_any::{DynAny, StaticType, StaticTypeSized};
use slotmap::{DefaultKey, SlotMap};
pub type DynFuture<'n, T> = Pin<Box<dyn core::future::Future<Output = T> + 'n>>;
pub type Any<'n> = Box<dyn DynAny<'n> + 'n>;
pub type FutureAny<'n> = DynFuture<'n, Any<'n>>;
#[derive(Clone, Copy)]
pub struct SlotInput<'i, T>(pub T, pub &'i SlotMap<DefaultKey, Box<TypeErasedNode<'i>>>);
impl<'i, T> SlotInput<'i, T> {
pub fn new(&self, arg: T) -> SlotInput<'i, T> {
SlotInput(arg, self.1)
}
}
unsafe impl<'i, T: StaticTypeSized> StaticType for SlotInput<'i, T> {
type Static = SlotInput<'static, T::Static>;
}
pub type AnySlotInput<'i> = SlotInput<'i, Any<'i>>;
//pub type SlotInput<'i> = (Any<'i>, &'i SlotMap<DefaultKey, Box<TypeErasedNode>>);
pub type TypeErasedNode<'n> = dyn for<'i> NodeIO<'i, AnySlotInput<'i>, Output = FutureAny<'i>> + 'n;
impl<'i> Node<'i, AnySlotInput<'i>> for DefaultKey {
type Output = FutureAny<'i>;
fn eval(&'i self, input: AnySlotInput<'i>) -> Self::Output {
input.1[*self].eval(input)
}
}
}
#[cfg(feature = "alloc")]
impl<'i, 's: 'i, I: 'i, O: 'i, N: Node<'i, I, Output = O>> Node<'i, I> for alloc::sync::Arc<N> {
type Output = O;
fn eval(&'i self, input: I) -> Self::Output {
(*self.as_ref()).eval(input)
}
}
impl<'i, 's: 'i, I: 'i, O: 'i, N: Node<'i, I, Output = O>> Node<'i, I> for &'i N {
type Output = O;
fn eval(&'i self, input: I) -> Self::Output {
(**self).eval(input)
}
}
#[cfg(feature = "alloc")]
impl<'i, I: 'i, O: 'i, N: Node<'i, I, Output = O>> Node<'i, I> for Box<N> {
type Output = O;
fn eval(&'i self, input: I) -> Self::Output {
(**self).eval(input)
}
}
/*
// Specifically implement for trait objects because they would otherwise evaluated as unsized objetcs
impl<'i, I: 'i, O: 'i> Node<'i, I> for &'i dyn Node<'i, I, Output = O> {
type Output = O;
fn eval(&'i self, input: I) -> Self::Output {
(**self).eval(input)
}
}*/
impl<'i, 's: 'i, I: 'i, O: 'i, N: Node<'i, I, Output = O>> Node<'i, I> for &'s N {
type Output = O;
fn eval(&'i self, input: I) -> Self::Output {
(**self).eval(input)
}
}
#[cfg(feature = "alloc")]
impl<'i, 's: 'i, I: 'i, O: 'i, N: Node<'i, I, Output = O>> Node<'i, I> for Box<N> {
type Output = O;
fn eval(&'i self, input: I) -> Self::Output {
(**self).eval(input)
}
}
impl<'i, I: 'i, O: 'i> Node<'i, I> for &'i dyn for<'a> Node<'a, I, Output = O> {
type Output = O;
fn eval(&'i self, input: I) -> Self::Output {
(**self).eval(input)
}
}
use core::pin::Pin;
use dyn_any::StaticTypeSized;
#[cfg(feature = "alloc")]
impl<'i, I: 'i, O: 'i> Node<'i, I> for Pin<Box<dyn for<'a> Node<'a, I, Output = O> + 'i>> {
type Output = O;
fn eval(&'i self, input: I) -> Self::Output {
(**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)
}
}
pub use crate::application_io::{ExtractImageFrame, SurfaceFrame, SurfaceId};
#[cfg(feature = "wasm")]

View file

@ -304,5 +304,7 @@ mod test {
assert_eq!(fnn.eval((1u32, 2u32)), (2, 1));
let result: u32 = fns.eval(());
assert_eq!(result, 42);
AddParameterNode::new(IntNode::<42>).eval(2u32);
}
}

View file

@ -27,3 +27,4 @@ anyhow = "1.0.66"
xxhash-rust = {workspace = true}
ghost-cell = "0.2.3"
futures = "0.3.28"
slotmap = "1.0.6"

View file

@ -13,13 +13,10 @@ use graphene_core::*;
use serde::{Deserialize, Serialize};
use std::pin::Pin;
pub type DynFuture<'n, T> = Pin<Box<dyn core::future::Future<Output = T> + 'n>>;
pub type Any<'n> = Box<dyn DynAny<'n> + 'n>;
pub type FutureAny<'n> = DynFuture<'n, Any<'n>>;
pub type TypeErasedNode<'n> = dyn for<'i> NodeIO<Any<'i>, Output = FutureAny<'i>> + 'n;
pub type TypeErasedCell<'n> = Arc<TypeErasedNode<'n>>;
pub use graphene_core::dyn_exec::*;
pub type TypeErasedCell<'n> = Box<TypeErasedNode<'n>>;
pub type NodeConstructor = for<'i> fn(Vec<TypeErasedCell<'i>>) -> DynFuture<'i, TypeErasedCell<'i>>;
pub type NodeConstructor = fn(Vec<TypeErasedCell>) -> DynFuture<'static, TypeErasedCell>;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Default, PartialEq, Clone, Hash, Eq)]

View file

@ -10,12 +10,7 @@ license = "MIT OR Apache-2.0"
[features]
default = ["wgpu"]
gpu = [
"graphene-core/gpu",
"gpu-compiler-bin-wrapper",
"compilation-client",
"gpu-executor",
]
gpu = ["graphene-core/gpu", "gpu-compiler-bin-wrapper", "compilation-client", "gpu-executor"]
vulkan = ["gpu", "vulkan-executor"]
wgpu = ["gpu", "wgpu-executor"]
quantization = ["autoquant"]
@ -53,6 +48,7 @@ xxhash-rust = { workspace = true }
serde_json = "1.0.96"
reqwest = { version = "0.11.17", features = ["rustls", "rustls-tls"] }
futures = "0.3.28"
ghost-cell = "0.2.3"
[dependencies.serde]
version = "1.0"

View file

@ -1,9 +1,10 @@
use dyn_any::StaticType;
pub use graph_craft::proto::{Any, TypeErasedNode, TypeErasedPinned, TypeErasedPinnedRef};
use graph_craft::proto::{DynFuture, FutureAny};
use dyn_any::{StaticType, StaticTypeSized};
use gpu_executor::ShaderInput;
pub use graph_craft::proto::{Any, TypeErasedCell, TypeErasedNode};
use graph_craft::proto::{AnySlotInput, DynFuture, FutureAny, SlotInput};
use graphene_core::NodeIO;
pub use graphene_core::{generic, ops, Node};
use std::marker::PhantomData;
use std::{marker::PhantomData, sync::Arc};
pub struct DynAnyNode<I, O, Node> {
node: Node,
@ -124,15 +125,15 @@ impl<'i, N> FutureWrapperNode<N> {
}
pub trait IntoTypeErasedNode<'n> {
fn into_type_erased(self) -> TypeErasedPinned<'n>;
fn into_type_erased(self) -> TypeErasedCell<'n>;
}
impl<'n, N: 'n> IntoTypeErasedNode<'n> for N
where
N: for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n,
N: for<'i> NodeIO<'i, AnySlotInput<'i>, Output = FutureAny<'i>> + 'n,
{
fn into_type_erased(self) -> TypeErasedPinned<'n> {
Box::pin(self)
fn into_type_erased(self) -> TypeErasedCell<'n> {
Box::new(self)
}
}
@ -147,32 +148,22 @@ impl<N: Clone, O: StaticType> Clone for DowncastNode<O, N> {
}
impl<N: Copy, O: StaticType> Copy for DowncastNode<O, N> {}
#[node_macro::node_fn(DowncastNode<_O>)]
fn downcast<N: 'input, _O: StaticType>(input: Any<'input>, node: &'input N) -> _O
where
N: for<'any_input> Node<'any_input, Any<'any_input>, Output = Any<'any_input>> + 'input,
{
let node_name = core::any::type_name::<N>();
let out = dyn_any::downcast(node.eval(input)).unwrap_or_else(|e| panic!("DowncastNode Input {e} in:\n{node_name}"));
*out
}
/// Boxes the input and downcasts the output.
/// Wraps around a node taking Box<dyn DynAny> and returning Box<dyn DynAny>
#[derive(Clone, Copy)]
pub struct DowncastBothNode<'a, I, O> {
node: TypeErasedPinnedRef<'a>,
pub struct DowncastBothNode<'n, I, O> {
node: TypeErasedCell<'n>,
_i: PhantomData<I>,
_o: PhantomData<O>,
}
impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'input, I> for DowncastBothNode<'n, I, O> {
impl<'n: 'input, 'i: 'input, 't, 'input, O: 'input + StaticType, I: 'input + StaticTypeSized> Node<'input, SlotInput<'i, I>> for DowncastBothNode<'n, I, O> {
type Output = DynFuture<'input, O>;
#[inline]
fn eval(&'input self, input: I) -> Self::Output {
fn eval(&'input self, input: SlotInput<'input, I>) -> Self::Output {
{
let node_name = self.node.node_name();
let input = Box::new(input);
let future = self.node.eval(input);
let slotmap = input.1;
let box_input = Box::new(input);
let future = self.node.eval(SlotInput(box_input, slotmap));
Box::pin(async move {
let out = dyn_any::downcast(future.await).unwrap_or_else(|e| panic!("DowncastBothNode Input {e} in: \n{node_name}"));
*out
@ -181,7 +172,7 @@ impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'i
}
}
impl<'n, I, O> DowncastBothNode<'n, I, O> {
pub const fn new(node: TypeErasedPinnedRef<'n>) -> Self {
pub const fn new(node: TypeErasedCell<'n>) -> Self {
Self {
node,
_i: core::marker::PhantomData,
@ -191,53 +182,54 @@ impl<'n, I, O> DowncastBothNode<'n, I, O> {
}
/// Boxes the input and downcasts the output.
/// Wraps around a node taking Box<dyn DynAny> and returning Box<dyn DynAny>
#[derive(Clone, Copy)]
pub struct DowncastBothRefNode<'a, I, O> {
node: TypeErasedPinnedRef<'a>,
node: TypeErasedCell<'a>,
_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 + StaticTypeSized> Node<'input, SlotInput<'input, I>> for DowncastBothRefNode<'n, I, O> {
type Output = DynFuture<'input, &'input O>;
#[inline]
fn eval(&'input self, input: I) -> Self::Output {
fn eval(&'input self, input: SlotInput<'input, I>) -> Self::Output {
{
let slotmap = input.1;
let node_name = self.node.node_name();
let input = Box::new(input);
Box::pin(async move {
let out: Box<&_> = dyn_any::downcast::<&O>(self.node.eval(input).await).unwrap_or_else(|e| panic!("DowncastBothRefNode Input {e} in {node_name}"));
let box_input = Box::new(input);
let out: Box<&_> = dyn_any::downcast::<&O>(self.node.eval(SlotInput(box_input, slotmap)).await).unwrap_or_else(|e| panic!("DowncastBothRefNode Input {e}"));
*out
})
}
}
}
impl<'n, I, O> DowncastBothRefNode<'n, I, O> {
pub const fn new(node: TypeErasedPinnedRef<'n>) -> Self {
pub const fn new(node: TypeErasedCell<'n>) -> Self {
Self { node, _i: core::marker::PhantomData }
}
}
pub struct ComposeTypeErased<'a> {
first: TypeErasedPinnedRef<'a>,
second: TypeErasedPinnedRef<'a>,
first: TypeErasedCell<'a>,
second: TypeErasedCell<'a>,
}
impl<'i, 'a: 'i> Node<'i, Any<'i>> for ComposeTypeErased<'a> {
impl<'i, 'a, 't> Node<'i, AnySlotInput<'i>> for ComposeTypeErased<'i> {
type Output = DynFuture<'i, Any<'i>>;
fn eval(&'i self, input: Any<'i>) -> Self::Output {
fn eval(&'i self, input: AnySlotInput<'i>) -> Self::Output {
let slotmap = input.1;
Box::pin(async move {
let arg = self.first.eval(input).await;
self.second.eval(arg).await
self.second.eval(SlotInput(arg, slotmap)).await
})
}
}
impl<'a> ComposeTypeErased<'a> {
pub const fn new(first: TypeErasedPinnedRef<'a>, second: TypeErasedPinnedRef<'a>) -> Self {
pub const fn new(first: TypeErasedCell<'a>, second: TypeErasedCell<'a>) -> Self {
ComposeTypeErased { first, second }
}
}
pub fn input_node<O: StaticType>(n: TypeErasedPinnedRef) -> DowncastBothNode<(), O> {
pub fn input_node<'n, O: StaticType>(n: TypeErasedCell<'n>) -> DowncastBothNode<'n, (), O> {
DowncastBothNode::new(n)
}
@ -267,9 +259,9 @@ mod test {
//let add = DynAnyNode::new(AddNode::new()).into_type_erased();
//add.eval(Box::new(&("32", 32u32)));
let dyn_any = DynAnyNode::<(u32, u32), u32, _>::new(ValueNode::new(FutureWrapperNode { node: AddNode::new() }));
let type_erased = Box::pin(dyn_any) as TypeErasedPinned;
let type_erased = Box::pin(dyn_any) as TypeErasedCell;
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 TypeErasedCell<'_>;
type_erased.eval(Box::new(&("32", 32u32)));
}
@ -278,10 +270,10 @@ mod test {
//let add = DynAnyNode::new(AddNode::new()).into_type_erased();
//add.eval(Box::new(&("32", 32u32)));
let dyn_any = DynAnyNode::<(u32, u32), u32, _>::new(ValueNode::new(FutureWrapperNode { node: AddNode::new() }));
let type_erased = Box::pin(dyn_any) as TypeErasedPinned<'_>;
let type_erased = Box::pin(dyn_any) as TypeErasedCell<'_>;
type_erased.eval(Box::new((4u32, 2u32)));
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 TypeErasedCell;
let type_erased = ComposeTypeErased::new(type_erased.as_ref(), type_erased_id.as_ref());
type_erased.eval(Box::new((4u32, 2u32)));
//let downcast: DowncastBothNode<(u32, u32), u32> = DowncastBothNode::new(type_erased.as_ref());

View file

@ -18,7 +18,7 @@ pub struct GpuCompiler<TypingContext, ShaderIO> {
// TODO: Move to graph-craft
#[node_macro::node_fn(GpuCompiler)]
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::compiler::Compiler {};
let DocumentNodeImplementation::Network(ref network) = node.implementation else { panic!() };
let proto_networks: Vec<_> = compiler.compile(network.clone(), true).collect();
@ -44,7 +44,7 @@ pub struct MapGpuNode<Node> {
#[node_macro::node_fn(MapGpuNode)]
async fn map_gpu(image: ImageFrame<Color>, node: DocumentNode) -> ImageFrame<Color> {
log::debug!("Executing gpu node");
let compiler = graph_craft::executor::Compiler {};
let compiler = graph_craft::compiler::Compiler {};
let inner_network = NodeNetwork::value_network(node);
log::debug!("inner_network: {:?}", inner_network);
@ -262,7 +262,7 @@ async fn blend_gpu_image(foreground: ImageFrame<Color>, background: ImageFrame<C
let translation: Vec2 = bg_to_fg.translation.as_vec2();
log::debug!("Executing gpu blend node!");
let compiler = graph_craft::executor::Compiler {};
let compiler = graph_craft::compiler::Compiler {};
let network = NodeNetwork {
inputs: vec![],

View file

@ -0,0 +1,99 @@
use std::error::Error;
use std::sync::Arc;
use dyn_any::StaticType;
use graph_craft::compiler::Executor;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::NodeId;
use graph_craft::proto::{DynFuture, ProtoNetwork, TypingContext};
use graph_craft::Type;
use crate::node_registry;
mod borrow_tree;
#[derive(Clone)]
pub struct DynamicExecutor {
output: NodeId,
tree: borrow_tree::BorrowTree,
typing_context: TypingContext,
// This allows us to keep the nodes around for one more frame which is used for introspection
orphaned_nodes: Vec<NodeId>,
}
impl Default for DynamicExecutor {
fn default() -> Self {
Self {
output: Default::default(),
tree: Default::default(),
typing_context: TypingContext::new(&node_registry::NODE_REGISTRY),
orphaned_nodes: Vec::new(),
}
}
}
impl DynamicExecutor {
pub async fn new(proto_network: ProtoNetwork) -> Result<Self, String> {
let mut typing_context = TypingContext::new(&node_registry::NODE_REGISTRY);
typing_context.update(&proto_network)?;
let output = proto_network.output;
let tree = borrow_tree::BorrowTree::new(proto_network, &typing_context).await?;
Ok(Self {
tree,
output,
typing_context,
orphaned_nodes: Vec::new(),
})
}
pub async fn update(&mut self, proto_network: ProtoNetwork) -> Result<(), String> {
self.output = proto_network.output;
self.typing_context.update(&proto_network)?;
let mut orphans = self.tree.update(proto_network, &self.typing_context).await?;
core::mem::swap(&mut self.orphaned_nodes, &mut orphans);
for node_id in orphans {
if self.orphaned_nodes.contains(&node_id) {
self.tree.free_node(node_id)
}
}
Ok(())
}
pub fn introspect(&self, node_path: &[NodeId]) -> Option<Option<Arc<dyn std::any::Any>>> {
self.tree.introspect(node_path)
}
pub fn input_type(&self) -> Option<Type> {
self.typing_context.type_of(self.output).map(|node_io| node_io.input.clone())
}
pub fn output_type(&self) -> Option<Type> {
self.typing_context.type_of(self.output).map(|node_io| node_io.output.clone())
}
}
impl<'a, I: StaticType + 'a> Executor<I, TaggedValue> for &'a DynamicExecutor {
fn execute(&self, input: I) -> DynFuture<Result<TaggedValue, Box<dyn Error>>> {
Box::pin(async move { self.tree.eval_tagged_value(self.output, input).await.map_err(|e| e.into()) })
}
}
#[cfg(test)]
mod test {
use graph_craft::document::value::TaggedValue;
use super::*;
#[test]
fn push_node_sync() {
let mut tree = borrow_tree::BorrowTree::default();
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32)), vec![]);
let context = TypingContext::default();
let future = tree.push_node(0, val_1_protonode, &context); //.await.unwrap();
futures::executor::block_on(future).unwrap();
let _node = tree.get(0).unwrap();
let result = futures::executor::block_on(tree.eval(0, ()));
assert_eq!(result, Some(2u32));
}
}

View file

@ -0,0 +1,125 @@
use dyn_any::StaticType;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::value::UpcastNode;
use graph_craft::document::NodeId;
use graph_craft::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, TypingContext};
use graphene_std::any::TypeErasedCell;
use std::collections::HashMap;
use std::collections::HashSet;
use std::sync::Arc;
use std::sync::RwLock;
#[derive(Clone)]
pub struct NodeContainer<'n> {
pub node: TypeErasedCell<'n>,
}
impl<'a> core::fmt::Debug for NodeContainer<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NodeContainer").finish()
}
}
impl<'a> NodeContainer<'a> {
pub fn new(node: TypeErasedCell<'a>) -> Self {
Self { node }
}
}
#[derive(Default, Debug, Clone)]
pub struct BorrowTree {
pub(crate) nodes: HashMap<NodeId, NodeContainer<'static>>,
pub(crate) source_map: HashMap<Vec<NodeId>, NodeId>,
}
impl BorrowTree {
pub async fn new(proto_network: ProtoNetwork, typing_context: &TypingContext) -> Result<Self, String> {
let mut nodes = BorrowTree::default();
for (id, node) in proto_network.nodes {
nodes.push_node(id, node, typing_context).await?
}
Ok(nodes)
}
/// Pushes new nodes into the tree and return orphaned nodes
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();
for (id, node) in proto_network.nodes {
if !self.nodes.contains_key(&id) {
self.push_node(id, node, typing_context).await?;
} else {
let Some(node_container) = self.nodes.get_mut(&id) else { continue };
node_container.node.reset();
}
old_nodes.remove(&id);
}
self.source_map.retain(|_, nid| !old_nodes.contains(nid));
Ok(old_nodes.into_iter().collect())
}
pub(crate) fn node_deps(&self, nodes: &[NodeId]) -> Vec<NodeContainer<'static>> {
nodes.iter().map(|node| self.nodes.get(node).unwrap().clone()).collect()
}
pub(crate) fn store_node(&mut self, node: NodeContainer<'static>, id: NodeId) -> NodeContainer<'static> {
self.nodes.insert(id, node.clone());
node
}
pub fn introspect(&self, node_path: &[NodeId]) -> Option<Option<Arc<dyn std::any::Any>>> {
let id = self.source_map.get(node_path)?;
let node = self.nodes.get(id)?;
Some(node.node.serialize())
}
pub fn get(&self, id: NodeId) -> Option<NodeContainer<'static>> {
self.nodes.get(&id).cloned()
}
pub async fn eval<'i, I: StaticType + 'i, O: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Option<O> {
let node = self.nodes.get(&id).cloned()?;
let output = node.node.eval(Box::new(input));
dyn_any::downcast::<O>(output.await).ok().map(|o| *o)
}
pub async fn eval_tagged_value<'i, I: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Result<TaggedValue, String> {
let node = self.nodes.get(&id).cloned().ok_or_else(|| "Output node not found in executor")?;
let output = node.node.eval(Box::new(input));
TaggedValue::try_from_any(output.await)
}
pub fn free_node(&mut self, id: NodeId) {
self.nodes.remove(&id);
}
pub async fn push_node(&mut self, id: NodeId, proto_node: ProtoNode, typing_context: &TypingContext) -> Result<(), String> {
let ProtoNode {
construction_args,
identifier,
document_node_path,
..
} = proto_node;
self.source_map.insert(document_node_path, id);
match construction_args {
ConstructionArgs::Value(value) => {
let upcasted = UpcastNode::new(value);
let node = Arc::new(upcasted) as TypeErasedCell<'_>;
let node = NodeContainer { node };
self.store_node(node.into(), id);
}
ConstructionArgs::Inline(_) => unimplemented!("Inline nodes are not supported yet"),
ConstructionArgs::Nodes(ids) => {
let ids: Vec<_> = ids.iter().map(|(id, _)| *id).collect();
let construction_nodes = self.node_deps(&ids);
let constructor = typing_context.constructor(id).ok_or(format!("No constructor found for node {:?}", identifier))?;
let node = constructor(construction_nodes).await;
let node = NodeContainer { node };
self.store_node(node.into(), id);
}
};
Ok(())
}
}

View file

@ -1,239 +0,0 @@
use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::sync::{Arc, RwLock};
use dyn_any::StaticType;
use graph_craft::document::value::{TaggedValue, UpcastNode};
use graph_craft::document::NodeId;
use graph_craft::executor::Executor;
use graph_craft::proto::{ConstructionArgs, LocalFuture, ProtoNetwork, ProtoNode, TypingContext};
use graph_craft::Type;
use graphene_std::any::{TypeErasedPinned, TypeErasedPinnedRef};
use crate::node_registry;
#[derive(Debug, Clone)]
pub struct DynamicExecutor {
output: NodeId,
tree: BorrowTree,
typing_context: TypingContext,
// This allows us to keep the nodes around for one more frame which is used for introspection
orphaned_nodes: Vec<NodeId>,
}
impl Default for DynamicExecutor {
fn default() -> Self {
Self {
output: Default::default(),
tree: Default::default(),
typing_context: TypingContext::new(&node_registry::NODE_REGISTRY),
orphaned_nodes: Vec::new(),
}
}
}
impl DynamicExecutor {
pub async fn new(proto_network: ProtoNetwork) -> Result<Self, String> {
let mut typing_context = TypingContext::new(&node_registry::NODE_REGISTRY);
typing_context.update(&proto_network)?;
let output = proto_network.output;
let tree = BorrowTree::new(proto_network, &typing_context).await?;
Ok(Self {
tree,
output,
typing_context,
orphaned_nodes: Vec::new(),
})
}
pub async fn update(&mut self, proto_network: ProtoNetwork) -> Result<(), String> {
self.output = proto_network.output;
self.typing_context.update(&proto_network)?;
let mut orphans = self.tree.update(proto_network, &self.typing_context).await?;
core::mem::swap(&mut self.orphaned_nodes, &mut orphans);
for node_id in orphans {
if self.orphaned_nodes.contains(&node_id) {
self.tree.free_node(node_id)
}
}
Ok(())
}
pub fn introspect(&self, node_path: &[NodeId]) -> Option<Option<Arc<dyn std::any::Any>>> {
self.tree.introspect(node_path)
}
pub fn input_type(&self) -> Option<Type> {
self.typing_context.type_of(self.output).map(|node_io| node_io.input.clone())
}
pub fn output_type(&self) -> Option<Type> {
self.typing_context.type_of(self.output).map(|node_io| node_io.output.clone())
}
}
impl<'a, I: StaticType + 'a> Executor<I, TaggedValue> for &'a DynamicExecutor {
fn execute(&self, input: I) -> LocalFuture<Result<TaggedValue, Box<dyn Error>>> {
Box::pin(async move { self.tree.eval_tagged_value(self.output, input).await.map_err(|e| e.into()) })
}
}
pub struct NodeContainer<'n> {
pub node: TypeErasedPinned<'n>,
// the dependencies are only kept to ensure that the nodes are not dropped while still in use
_dependencies: Vec<Arc<RwLock<NodeContainer<'static>>>>,
}
impl<'a> core::fmt::Debug for NodeContainer<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NodeContainer").finish()
}
}
impl<'a> NodeContainer<'a> {
pub fn new(node: TypeErasedPinned<'a>, _dependencies: Vec<Arc<RwLock<NodeContainer<'static>>>>) -> Self {
Self { node, _dependencies }
}
/// Return a static reference to the TypeErasedNode
/// # Safety
/// This is unsafe because the returned reference is only valid as long as the NodeContainer is alive
pub unsafe fn erase_lifetime(self) -> NodeContainer<'static> {
std::mem::transmute(self)
}
}
impl NodeContainer<'static> {
pub unsafe fn static_ref(&self) -> TypeErasedPinnedRef<'static> {
let s = &*(self as *const Self);
*(&s.node.as_ref() as *const TypeErasedPinnedRef<'static>)
}
}
#[derive(Default, Debug, Clone)]
pub struct BorrowTree {
nodes: HashMap<NodeId, Arc<RwLock<NodeContainer<'static>>>>,
source_map: HashMap<Vec<NodeId>, NodeId>,
}
impl BorrowTree {
pub async fn new(proto_network: ProtoNetwork, typing_context: &TypingContext) -> Result<Self, String> {
let mut nodes = BorrowTree::default();
for (id, node) in proto_network.nodes {
nodes.push_node(id, node, typing_context).await?
}
Ok(nodes)
}
/// Pushes new nodes into the tree and return orphaned nodes
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();
for (id, node) in proto_network.nodes {
if !self.nodes.contains_key(&id) {
self.push_node(id, node, typing_context).await?;
} else {
let Some(node_container) = self.nodes.get_mut(&id) else { continue };
let mut node_container_writer = node_container.write().unwrap();
let node = node_container_writer.node.as_mut();
node.reset();
}
old_nodes.remove(&id);
}
self.source_map.retain(|_, nid| !old_nodes.contains(nid));
Ok(old_nodes.into_iter().collect())
}
fn node_refs(&self, nodes: &[NodeId]) -> Vec<TypeErasedPinnedRef<'static>> {
self.node_deps(nodes).into_iter().map(|node| unsafe { node.read().unwrap().static_ref() }).collect()
}
fn node_deps(&self, nodes: &[NodeId]) -> Vec<Arc<RwLock<NodeContainer<'static>>>> {
nodes.iter().map(|node| self.nodes.get(node).unwrap().clone()).collect()
}
fn store_node(&mut self, node: Arc<RwLock<NodeContainer<'static>>>, id: NodeId) -> Arc<RwLock<NodeContainer<'static>>> {
self.nodes.insert(id, node.clone());
node
}
pub fn introspect(&self, node_path: &[NodeId]) -> Option<Option<Arc<dyn std::any::Any>>> {
let id = self.source_map.get(node_path)?;
let node = self.nodes.get(id)?;
let reader = node.read().unwrap();
let node = reader.node.as_ref();
Some(node.serialize())
}
pub fn get(&self, id: NodeId) -> Option<Arc<RwLock<NodeContainer<'static>>>> {
self.nodes.get(&id).cloned()
}
pub async fn eval<'i, I: StaticType + 'i, O: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Option<O> {
let node = self.nodes.get(&id).cloned()?;
let reader = node.read().unwrap();
let output = reader.node.eval(Box::new(input));
dyn_any::downcast::<O>(output.await).ok().map(|o| *o)
}
pub async fn eval_tagged_value<'i, I: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Result<TaggedValue, String> {
let node = self.nodes.get(&id).cloned().ok_or_else(|| "Output node not found in executor")?;
let reader = node.read().unwrap();
let output = reader.node.eval(Box::new(input));
TaggedValue::try_from_any(output.await)
}
pub fn free_node(&mut self, id: NodeId) {
self.nodes.remove(&id);
}
pub async fn push_node(&mut self, id: NodeId, proto_node: ProtoNode, typing_context: &TypingContext) -> Result<(), String> {
let ProtoNode {
construction_args,
identifier,
document_node_path,
..
} = proto_node;
self.source_map.insert(document_node_path, id);
match construction_args {
ConstructionArgs::Value(value) => {
let upcasted = UpcastNode::new(value);
let node = Box::pin(upcasted) as TypeErasedPinned<'_>;
let node = NodeContainer { node, _dependencies: vec![] };
let node = unsafe { node.erase_lifetime() };
self.store_node(Arc::new(node.into()), id);
}
ConstructionArgs::Inline(_) => unimplemented!("Inline nodes are not supported yet"),
ConstructionArgs::Nodes(ids) => {
let ids: Vec<_> = ids.iter().map(|(id, _)| *id).collect();
let construction_nodes = self.node_refs(&ids);
let constructor = typing_context.constructor(id).ok_or(format!("No constructor found for node {:?}", identifier))?;
let node = constructor(construction_nodes).await;
let node = NodeContainer {
node,
_dependencies: self.node_deps(&ids),
};
let node = unsafe { node.erase_lifetime() };
self.store_node(Arc::new(node.into()), id);
}
};
Ok(())
}
}
#[cfg(test)]
mod test {
use graph_craft::document::value::TaggedValue;
use super::*;
#[test]
fn push_node_sync() {
let mut tree = BorrowTree::default();
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32)), vec![]);
let context = TypingContext::default();
let future = tree.push_node(0, val_1_protonode, &context); //.await.unwrap();
futures::executor::block_on(future).unwrap();
let _node = tree.get(0).unwrap();
let result = futures::executor::block_on(tree.eval(0, ()));
assert_eq!(result, Some(2u32));
}
}

View file

@ -1,7 +1,7 @@
#[macro_use]
extern crate log;
pub mod executor;
pub mod dynamic_executor;
pub mod node_registry;
#[cfg(test)]
@ -72,8 +72,8 @@ mod tests {
..Default::default()
};
use crate::executor::DynamicExecutor;
use graph_craft::executor::{Compiler, Executor};
use crate::dynamic_executor::DynamicExecutor;
use graph_craft::compiler::{Compiler, Executor};
let compiler = Compiler {};
let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
@ -120,8 +120,8 @@ mod tests {
..Default::default()
};
use crate::executor::DynamicExecutor;
use graph_craft::executor::Compiler;
use crate::dynamic_executor::DynamicExecutor;
use graph_craft::compiler::Compiler;
let compiler = Compiler {};
let protograph = compiler.compile_single(network, true).expect("Graph should be generated");

View file

@ -1,4 +1,4 @@
use graph_craft::proto::{NodeConstructor, TypeErasedPinned};
use graph_craft::proto::{NodeConstructor, TypeErasedCell};
use graphene_core::ops::IdNode;
use graphene_core::quantization::QuantizationChannels;
use graphene_core::raster::bbox::AxisAlignedBbox;
@ -50,7 +50,7 @@ macro_rules! register_node {
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));
Box::pin(any) as TypeErasedPinned
Arc::new(any) as TypeErasedCell
})
},
{
@ -58,7 +58,7 @@ macro_rules! register_node {
graphene_std::any::PanicNode::<(), $type>::new()
),*);
let params = vec![$(fn_type!((), $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);
node_io.input = concrete!(<$input as StaticType>::Static);
node_io
},
@ -76,7 +76,7 @@ macro_rules! async_node {
args.reverse();
let node = <$path>::new($(graphene_std::any::input_node::<$type>(args.pop().expect("Not enough arguments provided to construct node"))),*);
let any: DynAnyNode<$input, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
Arc::new(any) as TypeErasedCell
})
},
{
@ -111,7 +111,7 @@ macro_rules! raster_node {
let node = construct_node!(args, $path, [$($type),*]).await;
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
Arc::new(any) as TypeErasedCell
})
},
{
@ -127,7 +127,7 @@ macro_rules! raster_node {
let map_node = graphene_std::raster::MapImageNode::new(graphene_core::value::ValueNode::new(node));
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
Arc::new(any) as TypeErasedCell
})
},
{
@ -143,7 +143,7 @@ macro_rules! raster_node {
let map_node = graphene_std::raster::MapImageNode::new(graphene_core::value::ValueNode::new(node));
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
Arc::new(any) as TypeErasedCell
})
},
{
@ -163,7 +163,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
//register_node!(graphene_core::ops::IdNode, input: Any<'_>, params: []),
vec![(
NodeIdentifier::new("graphene_core::ops::IdNode"),
|_| Box::pin(async move { Box::pin(FutureWrapperNode::new(IdNode::new())) as TypeErasedPinned }),
|_| Box::pin(async move { Box::pin(FutureWrapperNode::new(IdNode::new())) as TypeErasedCell }),
NodeIOTypes::new(generic!(I), generic!(I), vec![]),
)],
// TODO: create macro to impl for all types
@ -225,7 +225,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
let final_image = FutureWrapperNode::new(final_image);
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(final_image));
Box::pin(any) as TypeErasedPinned
Arc::new(any) as TypeErasedCell
})
},
NodeIOTypes::new(
@ -248,7 +248,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
//let document_node = ClonedNode::new(document_node.eval(()));
let node = graphene_std::executor::MapGpuNode::new(document_node);
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
Arc::new(any) as TypeErasedCell
})
},
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(graph_craft::document::DocumentNode)]),
@ -264,7 +264,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
let node = graphene_std::executor::BlendGpuImageNode::new(background, blend_mode, opacity);
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
Arc::new(any) as TypeErasedCell
})
},
NodeIOTypes::new(
@ -333,7 +333,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
let node = ClonedNode::new(blits.into_iter()).then(all_blits);
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
Arc::new(any) as TypeErasedCell
})
},
NodeIOTypes::new(
@ -359,7 +359,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
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, FutureWrapperNode::new(ValueNode::new(blend_node)));
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
Arc::new(any) as TypeErasedCell
})
},
NodeIOTypes::new(
@ -398,13 +398,13 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
let map_image_frame_node = graphene_std::raster::MapImageNode::new(ValueNode::new(generate_brightness_contrast_legacy_mapper_node.eval(())));
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
Arc::new(any) as TypeErasedCell
} else {
let generate_brightness_contrast_mapper_node = GenerateBrightnessContrastMapperNode::new(brightness, contrast);
let map_image_frame_node = graphene_std::raster::MapImageNode::new(ValueNode::new(generate_brightness_contrast_mapper_node.eval(())));
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
Arc::new(any) as TypeErasedCell
}
})
},
@ -427,7 +427,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
let node: DowncastBothNode<Option<graphene_core::EditorApi>, graphene_core::EditorApi> = graphene_std::any::DowncastBothNode::new(args[0]);
let node = <graphene_core::memo::RefNode<_, _>>::new(node);
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
Box::pin(any) as TypeErasedPinned
Arc::new(any) as TypeErasedCell
})
},
NodeIOTypes::new(

View file

@ -2,9 +2,9 @@ use std::error::Error;
use super::context::Context;
use graph_craft::executor::Executor;
use graph_craft::compiler::Executor;
use graph_craft::proto::LocalFuture;
use graph_craft::proto::DynFuture;
use graphene_core::gpu::PushConstants;
use bytemuck::Pod;
@ -41,7 +41,7 @@ impl<I: StaticTypeSized, O> GpuExecutor<I, O> {
}
impl<'a, I: StaticTypeSized + Sync + Pod + Send + 'a, O: StaticTypeSized + Send + Sync + Pod + 'a> Executor<Vec<I>, Vec<O>> for &'a GpuExecutor<I, O> {
fn execute(&self, input: Vec<I>) -> LocalFuture<Result<Vec<O>, Box<dyn Error>>> {
fn execute(&self, input: Vec<I>) -> DynFuture<Result<Vec<O>, Box<dyn Error>>> {
let context = &self.context;
let result: Vec<O> = execute_shader(
context.device.clone(),

View file

@ -5,7 +5,7 @@ use wgpu::util::DeviceExt;
use super::context::Context;
use bytemuck::Pod;
use dyn_any::StaticTypeSized;
use graph_craft::{executor::Executor, proto::LocalFuture};
use graph_craft::{compiler::Executor, proto::DynFuture};
#[derive(Debug)]
pub struct GpuExecutor<'a, I: StaticTypeSized, O> {
@ -27,7 +27,7 @@ impl<'a, I: StaticTypeSized, O> GpuExecutor<'a, I, O> {
}
impl<'a, I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync + Pod> Executor<Vec<I>, Vec<O>> for GpuExecutor<'a, I, O> {
fn execute(&self, input: Vec<I>) -> LocalFuture<Result<Vec<O>, Box<dyn Error>>> {
fn execute(&self, input: Vec<I>) -> DynFuture<Result<Vec<O>, Box<dyn Error>>> {
let context = &self.context;
let future = execute_shader(context.device.clone(), context.queue.clone(), self.shader.to_vec(), input, self.entry_point.clone());
Box::pin(async move {