Implement node registry (#822)

This commit is contained in:
TrueDoctor 2022-10-26 00:32:50 +02:00 committed by Keavon Chambers
parent c3fbc4eac9
commit 11c6413251
10 changed files with 213 additions and 45 deletions

3
Cargo.lock generated
View file

@ -100,6 +100,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "borrow_stack"
version = "0.1.0"
dependencies = [
"dyn-any",
]
[[package]]
name = "bumpalo"

View file

@ -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"}

View file

@ -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))
}
}

View file

@ -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)

View file

@ -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))
}
}

View file

@ -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)
}
}

View file

@ -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]

View 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);
}*/
}

View file

@ -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,

View file

@ -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 {