mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-04 05:18:19 +00:00
Implement node registry (#822)
This commit is contained in:
parent
c3fbc4eac9
commit
11c6413251
10 changed files with 213 additions and 45 deletions
|
@ -7,3 +7,4 @@ license = "MIT OR Apache-2.0"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
dyn-any = {path = "../../libraries/dyn-any"}
|
||||
|
|
|
@ -5,25 +5,24 @@ use std::{
|
|||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
pub trait BorrowStack<'n> {
|
||||
pub trait BorrowStack {
|
||||
type Item;
|
||||
/// # Safety
|
||||
unsafe fn push(&self, value: Self::Item);
|
||||
/// # Safety
|
||||
unsafe fn pop(&self);
|
||||
/// # Safety
|
||||
unsafe fn get(&self) -> &'n [Self::Item];
|
||||
unsafe fn get(&self) -> &'static [Self::Item];
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FixedSizeStack<'n, T> {
|
||||
pub struct FixedSizeStack<T: dyn_any::StaticTypeSized> {
|
||||
data: Pin<Box<[MaybeUninit<T>]>>,
|
||||
capacity: usize,
|
||||
len: AtomicUsize,
|
||||
_phantom: PhantomData<&'n ()>,
|
||||
}
|
||||
|
||||
impl<'n, T: Unpin + 'n> FixedSizeStack<'n, T> {
|
||||
impl<'n, T: Unpin + 'n + dyn_any::StaticTypeSized> FixedSizeStack<T> {
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
let layout = std::alloc::Layout::array::<MaybeUninit<T>>(capacity).unwrap();
|
||||
let array = unsafe { std::alloc::alloc(layout) };
|
||||
|
@ -33,7 +32,6 @@ impl<'n, T: Unpin + 'n> FixedSizeStack<'n, T> {
|
|||
data: array,
|
||||
capacity,
|
||||
len: AtomicUsize::new(0),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,19 +42,19 @@ impl<'n, T: Unpin + 'n> FixedSizeStack<'n, T> {
|
|||
pub fn is_empty(&self) -> bool {
|
||||
self.len.load(Ordering::SeqCst) == 0
|
||||
}
|
||||
pub fn push_fn(&self, f: impl FnOnce(&'n [T]) -> T) {
|
||||
unsafe { self.push(f(self.get())) }
|
||||
pub fn push_fn(&self, f: impl FnOnce(&'static [T::Static]) -> T) {
|
||||
unsafe { self.push(std::mem::transmute_copy(&f(self.get()))) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'n, T> BorrowStack<'n> for FixedSizeStack<'n, T> {
|
||||
type Item = T;
|
||||
impl<'n, T: 'n + dyn_any::StaticTypeSized> BorrowStack for FixedSizeStack<T> {
|
||||
type Item = T::Static;
|
||||
|
||||
unsafe fn push(&self, value: Self::Item) {
|
||||
let len = self.len.load(Ordering::SeqCst);
|
||||
assert!(len < self.capacity);
|
||||
let ptr = self.data[len].as_ptr();
|
||||
(ptr as *mut T).write(value);
|
||||
(ptr as *mut T::Static).write(value);
|
||||
self.len.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
|
@ -66,8 +64,8 @@ impl<'n, T> BorrowStack<'n> for FixedSizeStack<'n, T> {
|
|||
self.len.fetch_sub(1, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
unsafe fn get(&self) -> &'n [Self::Item] {
|
||||
std::slice::from_raw_parts(self.data.as_ptr() as *const T, self.len.load(Ordering::SeqCst))
|
||||
unsafe fn get(&self) -> &'static [Self::Item] {
|
||||
std::slice::from_raw_parts(self.data.as_ptr() as *const T::Static, self.len.load(Ordering::SeqCst))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub trait AsBoxNode<'n, T>
|
||||
pub trait AsRefNode<'n, T>
|
||||
where
|
||||
&'n Self: Node<T>,
|
||||
Self: 'n,
|
||||
|
@ -57,7 +57,7 @@ where
|
|||
fn eval_box(&'n self, input: T) -> <Self>::Output;
|
||||
}
|
||||
|
||||
impl<'n, N: 'n, I> AsBoxNode<'n, I> for N
|
||||
impl<'n, N: 'n, I> AsRefNode<'n, I> for N
|
||||
where
|
||||
&'n N: Node<I, Output = N::Output>,
|
||||
N: Node<I>,
|
||||
|
@ -69,7 +69,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'n, T> Node<T> for &'n (dyn AsBoxNode<'n, T, Output = T> + 'n) {
|
||||
impl<'n, T> Node<T> for &'n (dyn AsRefNode<'n, T, Output = T> + 'n) {
|
||||
type Output = T;
|
||||
fn eval(self, input: T) -> Self::Output {
|
||||
self.eval_box(input)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use core::marker::PhantomData;
|
||||
use core::ops::Add;
|
||||
|
||||
use crate::Node;
|
||||
use crate::{Node, RefNode};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct AddNode;
|
||||
|
@ -153,18 +153,24 @@ impl<'n, T: Clone + 'n> Node<T> for DupNode {
|
|||
/// Return the Input Argument
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct IdNode;
|
||||
impl<'n, T: 'n> Node<T> for IdNode {
|
||||
impl<T> Node<T> for IdNode {
|
||||
type Output = T;
|
||||
fn eval(self, input: T) -> Self::Output {
|
||||
input
|
||||
}
|
||||
}
|
||||
impl<'n, T: 'n> Node<T> for &'n IdNode {
|
||||
impl<'n, T> Node<T> for &'n IdNode {
|
||||
type Output = T;
|
||||
fn eval(self, input: T) -> Self::Output {
|
||||
input
|
||||
}
|
||||
}
|
||||
impl<T> RefNode<T> for IdNode {
|
||||
type Output = T;
|
||||
fn eval_ref(&self, input: T) -> Self::Output {
|
||||
input
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MapResultNode<MN, I, E>(pub MN, pub PhantomData<(I, E)>);
|
||||
|
||||
|
@ -177,7 +183,7 @@ impl<MN: Node<I>, I, E> Node<Result<I, E>> for MapResultNode<MN, I, E> {
|
|||
impl<'n, MN: Node<I> + Copy, I, E> Node<Result<I, E>> for &'n MapResultNode<MN, I, E> {
|
||||
type Output = Result<MN::Output, E>;
|
||||
fn eval(self, input: Result<I, E>) -> Self::Output {
|
||||
input.map(|x| (&self.0).eval(x))
|
||||
input.map(|x| self.0.eval(x))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use core::marker::PhantomData;
|
||||
|
||||
use crate::{Node, RefNode};
|
||||
use crate::{AsRefNode, Node, RefNode};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ComposeNode<First, Second, Input> {
|
||||
|
@ -26,17 +26,19 @@ where
|
|||
}
|
||||
impl<'n, Input, Inter, First, Second> Node<Input> for &'n ComposeNode<First, Second, Input>
|
||||
where
|
||||
First: RefNode<Input, Output = Inter> + Copy,
|
||||
Second: RefNode<Inter> + Copy,
|
||||
First: AsRefNode<'n, Input, Output = Inter>,
|
||||
Second: AsRefNode<'n, Inter>,
|
||||
&'n First: Node<Input, Output = Inter>,
|
||||
&'n Second: Node<Inter>,
|
||||
{
|
||||
type Output = <Second as RefNode<Inter>>::Output;
|
||||
type Output = <Second as AsRefNode<'n, Inter>>::Output;
|
||||
|
||||
fn eval(self, input: Input) -> Self::Output {
|
||||
// evaluate the first node with the given input
|
||||
// and then pipe the result from the first computation
|
||||
// into the second node
|
||||
let arg: Inter = (self.first).eval_ref(input);
|
||||
(self.second).eval_ref(arg)
|
||||
let arg: Inter = (self.first).eval_box(input);
|
||||
(self.second).eval_box(arg)
|
||||
}
|
||||
}
|
||||
impl<Input, Inter, First, Second> RefNode<Input> for ComposeNode<First, Second, Input>
|
||||
|
@ -136,3 +138,8 @@ impl<'n, Root: Node<T> + Copy, T: From<()>, Input> Node<Input> for &'n ConsNode<
|
|||
(input, arg)
|
||||
}
|
||||
}
|
||||
impl<Root, T: From<()>> ConsNode<Root, T> {
|
||||
pub fn new(root: Root) -> Self {
|
||||
ConsNode(root, PhantomData)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
pub mod node_registry;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
|
@ -7,7 +9,7 @@ mod tests {
|
|||
use graphene_core::{structural::*, RefNode};
|
||||
|
||||
use borrow_stack::BorrowStack;
|
||||
use dyn_any::{downcast, DynAny, IntoDynAny};
|
||||
use dyn_any::{downcast, IntoDynAny};
|
||||
use graphene_std::any::{Any, DowncastNode, DynAnyNode, TypeErasedNode};
|
||||
use graphene_std::ops::AddNode;
|
||||
|
||||
|
@ -19,7 +21,8 @@ mod tests {
|
|||
stack.push(dynanynode.into_box());
|
||||
}
|
||||
stack.push_fn(|nodes| {
|
||||
let downcast: DowncastNode<_, &u32> = DowncastNode::new(&nodes[0]);
|
||||
let pre_node = nodes.get(0).unwrap();
|
||||
let downcast: DowncastNode<&TypeErasedNode, &u32> = DowncastNode::new(pre_node);
|
||||
let dynanynode: DynAnyNode<ConsNode<_, Any<'_>>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData));
|
||||
dynanynode.into_box()
|
||||
});
|
||||
|
@ -39,17 +42,6 @@ mod tests {
|
|||
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
|
||||
let add = unsafe { &stack.get()[3] }.eval_ref(4_u32.into_dyn());
|
||||
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
|
||||
|
||||
/*
|
||||
for i in 0..3 {
|
||||
println!("node_id: {}", i);
|
||||
let value = unsafe { &stack.get()[i] };
|
||||
input = value.eval_ref(input);
|
||||
}*/
|
||||
|
||||
//assert_eq!(*dyn_any::downcast::<u32>(result).unwrap(), 4)
|
||||
|
||||
//assert_eq!(4, *dyn_any::downcast::<u32>(DynamicAddNode.eval((Box::new(2_u32) as Dynamic, Box::new(2_u32) as Dynamic))).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
120
node-graph/graph-craft/src/node_registry.rs
Normal file
120
node-graph/graph-craft/src/node_registry.rs
Normal file
|
@ -0,0 +1,120 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use borrow_stack::FixedSizeStack;
|
||||
use graphene_core::ops::{AddNode, IdNode};
|
||||
use graphene_core::structural::{ConsNode, Then};
|
||||
use graphene_core::{AsRefNode, Node};
|
||||
use graphene_std::{
|
||||
any::{Any, DowncastNode, DynAnyNode, IntoTypeErasedNode, TypeErasedNode},
|
||||
document::{ConstructionArgs, ProtoNode, ProtoNodeInput},
|
||||
};
|
||||
|
||||
struct NodeIdentifier {
|
||||
name: &'static str,
|
||||
types: &'static [&'static str],
|
||||
}
|
||||
|
||||
const fn annotate<'n, 's: 'n, F>(f: F) -> F
|
||||
where
|
||||
F: Fn(ProtoNode, FixedSizeStack<TypeErasedNode<'n>>),
|
||||
{
|
||||
f
|
||||
}
|
||||
|
||||
use borrow_stack::BorrowStack;
|
||||
unsafe fn foo<'n>(proto_node: ProtoNode, stack: &'n FixedSizeStack<TypeErasedNode<'n>>) {
|
||||
let node_id = proto_node.input.unwrap_node() as usize;
|
||||
let nodes = stack.get();
|
||||
let pre_node = nodes.get(node_id).unwrap();
|
||||
let downcast: DowncastNode<_, &u32> = DowncastNode::new(pre_node);
|
||||
let dynanynode: DynAnyNode<ConsNode<_, Any<'_>>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData));
|
||||
stack.push(dynanynode.into_box());
|
||||
}
|
||||
fn borrow_stack() {
|
||||
let stack = borrow_stack::FixedSizeStack::new(256);
|
||||
unsafe {
|
||||
{
|
||||
let proto_node = ProtoNode::id();
|
||||
foo(proto_node, &stack);
|
||||
let proto_node = ProtoNode::id();
|
||||
let stack = &stack;
|
||||
let node_id = proto_node.input.unwrap_node() as usize;
|
||||
let nodes = stack.get();
|
||||
let pre_node = nodes.get(node_id).unwrap();
|
||||
let downcast: DowncastNode<&TypeErasedNode, &u32> = DowncastNode::new(pre_node);
|
||||
let dynanynode: DynAnyNode<ConsNode<_, Any<'_>>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData));
|
||||
stack.push(dynanynode.into_box());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack<TypeErasedNode<'static>>))] = &[
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::ops::IdNode",
|
||||
types: &["Any<'n>"],
|
||||
},
|
||||
|proto_node, stack| {
|
||||
stack.push_fn(|nodes| {
|
||||
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
|
||||
let node = pre_node.then(graphene_core::ops::IdNode);
|
||||
node.into_type_erased()
|
||||
})
|
||||
},
|
||||
),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::ops::AddNode",
|
||||
types: &["u32", "u32"],
|
||||
},
|
||||
|proto_node, stack| {
|
||||
stack.push_fn(|nodes| {
|
||||
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
|
||||
let node: DynAnyNode<AddNode, (u32, u32), _, _> = DynAnyNode::new(graphene_core::ops::AddNode);
|
||||
let node = (pre_node).then(node);
|
||||
|
||||
node.into_type_erased()
|
||||
})
|
||||
},
|
||||
),
|
||||
/*(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::structural::ConsNode",
|
||||
types: &["&TypeErasedNode", "&u32", "u32"],
|
||||
},
|
||||
|proto_node, stack| {
|
||||
let node_id = proto_node.input.unwrap_node() as usize;
|
||||
stack.push_fn(move |nodes| {
|
||||
let pre_node = nodes.get(node_id).unwrap();
|
||||
let downcast: DowncastNode<_, &u32> = DowncastNode::new(pre_node);
|
||||
let dynanynode: DynAnyNode<ConsNode<_, Any<'_>>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData));
|
||||
dynanynode.into_box()
|
||||
})
|
||||
},
|
||||
),*/
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::any::DowncastNode",
|
||||
types: &["&TypeErasedNode", "&u32"],
|
||||
},
|
||||
|proto_node, stack| {
|
||||
stack.push_fn(|nodes| {
|
||||
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
|
||||
let node = pre_node.then(graphene_core::ops::IdNode);
|
||||
node.into_type_erased()
|
||||
})
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
/*#[test]
|
||||
fn test() {
|
||||
let nodes = [TypeErasedNode(Box::new(42u32))];
|
||||
let node = NODE_REGISTRY[0].1(node, &nodes);
|
||||
assert_eq!(node.eval(()), 42);
|
||||
}*/
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use dyn_any::{DynAny, StaticType};
|
||||
use dyn_any::{DynAny, StaticType, StaticTypeSized};
|
||||
pub use graphene_core::{generic, ops /*, structural*/, Node, RefNode};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
@ -6,7 +6,7 @@ fn fmt_error<I>() -> String {
|
|||
format!("DynAnyNode: input is not of correct type, expected {}", std::any::type_name::<I>())
|
||||
}
|
||||
|
||||
pub struct DynAnyNode<N, I: StaticType, O: StaticType, ORef: StaticType>(pub N, PhantomData<(I, O, ORef)>);
|
||||
pub struct DynAnyNode<N, I: StaticType, O: StaticType, ORef: StaticType>(pub N, pub PhantomData<(I, O, ORef)>);
|
||||
/*impl<'n, I: StaticType, N: RefNode<'n, &'n I, Output = O> + 'n, O: 'n + StaticType> Node<&'n dyn DynAny<'n>> for DynAnyNode<'n, N, I> {
|
||||
type Output = Box<dyn dyn_any::DynAny<'n> + 'n>;
|
||||
fn eval(self, input: &'n dyn DynAny<'n>) -> Self::Output {
|
||||
|
@ -49,13 +49,37 @@ where
|
|||
Box::new((&self.0).eval_ref(*input))
|
||||
}
|
||||
}
|
||||
pub struct TypeErasedNode<'n>(pub Box<dyn AsBoxNode<'n, Any<'n>, Output = Any<'n>>>);
|
||||
pub struct TypeErasedNode<'n>(pub Box<dyn AsRefNode<'n, Any<'n>, Output = Any<'n>> + 'n>);
|
||||
impl<'n> Node<Any<'n>> for &'n TypeErasedNode<'n> {
|
||||
type Output = Any<'n>;
|
||||
fn eval(self, input: Any<'n>) -> Self::Output {
|
||||
self.0.eval_box(input)
|
||||
}
|
||||
}
|
||||
impl<'n> Node<Any<'n>> for &'n &'n TypeErasedNode<'n> {
|
||||
type Output = Any<'n>;
|
||||
fn eval(self, input: Any<'n>) -> Self::Output {
|
||||
self.0.eval_box(input)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoTypeErasedNode<'n> {
|
||||
fn into_type_erased(self) -> TypeErasedNode<'n>;
|
||||
}
|
||||
|
||||
impl<'n> StaticTypeSized for TypeErasedNode<'n> {
|
||||
type Static = TypeErasedNode<'static>;
|
||||
}
|
||||
|
||||
impl<'n, N: 'n> IntoTypeErasedNode<'n> for N
|
||||
where
|
||||
N: AsRefNode<'n, Any<'n>, Output = Any<'n>>,
|
||||
&'n N: Node<Any<'n>, Output = Any<'n>>,
|
||||
{
|
||||
fn into_type_erased(self) -> TypeErasedNode<'n> {
|
||||
TypeErasedNode(Box::new(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'n, I: StaticType + 'n, N: 'n, O: 'n + StaticType, ORef: 'n + StaticType> DynAnyNode<N, I, O, ORef>
|
||||
where
|
||||
|
@ -81,11 +105,19 @@ where
|
|||
Self: 'a,
|
||||
N: Node<I, Output = O>,
|
||||
{
|
||||
TypeErasedNode(Box::new(self))
|
||||
self.into_type_erased()
|
||||
}
|
||||
}
|
||||
impl<'n, I: StaticType + 'n, N: 'n, O: 'n + StaticType, ORef: 'n + StaticType> DynAnyNode<&'n N, I, O, ORef>
|
||||
where
|
||||
N: Node<I, Output = ORef>,
|
||||
{
|
||||
pub fn new_from_ref(n: &'n N) -> Self {
|
||||
DynAnyNode(n, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DowncastNode<N, I: StaticType>(pub N, PhantomData<I>);
|
||||
pub struct DowncastNode<N, I: StaticType>(pub N, pub PhantomData<I>);
|
||||
impl<N: Copy + Clone, I: StaticType> Clone for DowncastNode<N, I> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0, self.1)
|
||||
|
@ -127,7 +159,7 @@ where
|
|||
}
|
||||
}*/
|
||||
|
||||
use graphene_core::{ops::Dynamic, AsBoxNode};
|
||||
use graphene_core::{ops::Dynamic, AsRefNode};
|
||||
pub struct BoxedComposition<'a, Second> {
|
||||
pub first: Box<dyn Node<(), Output = Dynamic<'a>>>,
|
||||
pub second: Second,
|
||||
|
|
|
@ -198,6 +198,15 @@ impl NodeInput {
|
|||
}
|
||||
}
|
||||
|
||||
impl ProtoNodeInput {
|
||||
pub fn unwrap_node(self) -> NodeId {
|
||||
match self {
|
||||
ProtoNodeInput::Node(id) => id,
|
||||
_ => panic!("tried to unwrap id from non node input"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtoNode {
|
||||
pub fn id() -> Self {
|
||||
Self {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue