Node graph dynamic execution (#824)
Restructure document node implementation * Implement topological sort * Enforce the usage of type annotations * Add complete test case
This commit is contained in:
parent
d142a9092c
commit
4ec600957c
|
|
@ -359,6 +359,7 @@ dependencies = [
|
||||||
"graphene-core",
|
"graphene-core",
|
||||||
"graphene-std",
|
"graphene-std",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"rand_chacha",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -395,7 +396,6 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rand_chacha",
|
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,10 @@ impl<'n, L: Add<R, Output = O> + 'n + Copy, R: Copy, O: 'n> Node<&'n (L, R)> for
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub mod dynamic {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
// Unfortunatly we can't impl the AddNode as we get
|
// Unfortunatly we can't impl the AddNode as we get
|
||||||
// `upstream crates may add a new impl of trait `core::ops::Add` for type `alloc::boxed::Box<(dyn dyn_any::DynAny<'_> + 'static)>` in future versions`
|
// `upstream crates may add a new impl of trait `core::ops::Add` for type `alloc::boxed::Box<(dyn dyn_any::DynAny<'_> + 'static)>` in future versions`
|
||||||
pub struct DynamicAddNode;
|
pub struct DynamicAddNode;
|
||||||
|
|
@ -75,6 +79,7 @@ impl<'n> Node<(Dynamic<'n>, Dynamic<'n>)> for DynamicAddNode {
|
||||||
(left: f64, right: f64) }
|
(left: f64, right: f64) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct CloneNode;
|
pub struct CloneNode;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
#[cfg(feature = "std")]
|
||||||
use dyn_any::{DynAny, StaticType};
|
use dyn_any::{DynAny, StaticType};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
@ -6,7 +7,8 @@ use serde::{Deserialize, Serialize};
|
||||||
/// The other components (RGB) are stored as `f32` that range from `0.0` up to `f32::MAX`,
|
/// The other components (RGB) are stored as `f32` that range from `0.0` up to `f32::MAX`,
|
||||||
/// the values encode the brightness of each channel proportional to the light intensity in cd/m² (nits) in HDR, and `0.0` (black) to `1.0` (white) in SDR color.
|
/// the values encode the brightness of each channel proportional to the light intensity in cd/m² (nits) in HDR, and `0.0` (black) to `1.0` (white) in SDR color.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize, DynAny)]
|
#[cfg_attr(feature = "std", derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize, DynAny))]
|
||||||
|
#[cfg_attr(not(feature = "std"), derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize))]
|
||||||
pub struct Color {
|
pub struct Color {
|
||||||
red: f32,
|
red: f32,
|
||||||
green: f32,
|
green: f32,
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,4 @@ dyn-any = { path = "../../libraries/dyn-any" }
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
borrow_stack = { path = "../borrow_stack" }
|
borrow_stack = { path = "../borrow_stack" }
|
||||||
dyn-clone = "1.0"
|
dyn-clone = "1.0"
|
||||||
|
rand_chacha = "0.3.1"
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
|
use crate::proto::{ConstructionArgs, NodeIdentifier, ProtoNetwork, ProtoNode, ProtoNodeInput, Type};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Display;
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use dyn_any::{DynAny, StaticType};
|
pub mod value;
|
||||||
use dyn_clone::DynClone;
|
|
||||||
use rand_chacha::{
|
use rand_chacha::{
|
||||||
rand_core::{RngCore, SeedableRng},
|
rand_core::{RngCore, SeedableRng},
|
||||||
ChaCha20Rng,
|
ChaCha20Rng,
|
||||||
};
|
};
|
||||||
|
|
||||||
type NodeId = u64;
|
pub type NodeId = u64;
|
||||||
static RNG: Mutex<Option<ChaCha20Rng>> = Mutex::new(None);
|
static RNG: Mutex<Option<ChaCha20Rng>> = Mutex::new(None);
|
||||||
|
|
||||||
pub fn generate_uuid() -> u64 {
|
pub fn generate_uuid() -> u64 {
|
||||||
|
|
@ -20,14 +20,6 @@ pub fn generate_uuid() -> u64 {
|
||||||
lock.as_mut().map(ChaCha20Rng::next_u64).unwrap()
|
lock.as_mut().map(ChaCha20Rng::next_u64).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_node_id() -> NodeId {
|
|
||||||
static mut NODE_ID: NodeId = 3;
|
|
||||||
unsafe {
|
|
||||||
NODE_ID += 1;
|
|
||||||
NODE_ID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn merge_ids(a: u64, b: u64) -> u64 {
|
fn merge_ids(a: u64, b: u64) -> u64 {
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||||
|
|
@ -36,6 +28,8 @@ fn merge_ids(a: u64, b: u64) -> u64 {
|
||||||
hasher.finish()
|
hasher.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Fqn = NodeIdentifier<'static>;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct DocumentNode {
|
pub struct DocumentNode {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
@ -57,35 +51,33 @@ impl DocumentNode {
|
||||||
self.inputs[index] = NodeInput::Node(node);
|
self.inputs[index] = NodeInput::Node(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_proto_nodes(&mut self) {
|
fn resolve_proto_node(mut self) -> ProtoNode {
|
||||||
let first = self.inputs.remove(0);
|
let first = self.inputs.remove(0);
|
||||||
if let DocumentNodeImplementation::ProtoNode(proto) = &mut self.implementation {
|
if let DocumentNodeImplementation::Unresolved(fqn) = self.implementation {
|
||||||
match first {
|
let (input, mut args) = match first {
|
||||||
NodeInput::Value(value) => {
|
NodeInput::Value(value) => {
|
||||||
proto.input = ProtoNodeInput::None;
|
|
||||||
proto.construction_args = ConstructionArgs::Value(value);
|
|
||||||
assert_eq!(self.inputs.len(), 0);
|
assert_eq!(self.inputs.len(), 0);
|
||||||
return;
|
(ProtoNodeInput::None, ConstructionArgs::Value(value))
|
||||||
}
|
}
|
||||||
NodeInput::Node(id) => proto.input = ProtoNodeInput::Node(id),
|
NodeInput::Node(id) => (ProtoNodeInput::Node(id), ConstructionArgs::Nodes(vec![])),
|
||||||
NodeInput::Network => proto.input = ProtoNodeInput::Network,
|
NodeInput::Network => (ProtoNodeInput::Network, ConstructionArgs::Nodes(vec![])),
|
||||||
}
|
};
|
||||||
assert!(!self.inputs.iter().any(|input| matches!(input, NodeInput::Network)), "recived non resolved parameter");
|
assert!(!self.inputs.iter().any(|input| matches!(input, NodeInput::Network)), "recieved non resolved parameter");
|
||||||
assert!(!self.inputs.iter().any(|input| matches!(input, NodeInput::Value(_))), "recieved value as parameter");
|
assert!(!self.inputs.iter().any(|input| matches!(input, NodeInput::Value(_))), "recieved value as parameter");
|
||||||
|
|
||||||
let nodes: Vec<_> = self
|
if let ConstructionArgs::Nodes(nodes) = &mut args {
|
||||||
.inputs
|
nodes.extend(self.inputs.iter().map(|input| match input {
|
||||||
.iter()
|
NodeInput::Node(id) => *id,
|
||||||
.filter_map(|input| match input {
|
_ => unreachable!(),
|
||||||
NodeInput::Node(id) => Some(*id),
|
}));
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
match nodes {
|
|
||||||
vec if vec.is_empty() => proto.construction_args = ConstructionArgs::None,
|
|
||||||
vec => proto.construction_args = ConstructionArgs::Nodes(vec),
|
|
||||||
}
|
}
|
||||||
self.inputs = vec![];
|
ProtoNode {
|
||||||
|
identifier: fqn,
|
||||||
|
input,
|
||||||
|
construction_args: args,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!("tried to resolve not flattened node on resolved node");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -93,10 +85,18 @@ impl DocumentNode {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum NodeInput {
|
pub enum NodeInput {
|
||||||
Node(NodeId),
|
Node(NodeId),
|
||||||
Value(Value),
|
Value(value::Value),
|
||||||
Network,
|
Network,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl NodeInput {
|
||||||
|
fn map_ids(&mut self, f: impl Fn(NodeId) -> NodeId) {
|
||||||
|
if let NodeInput::Node(id) = self {
|
||||||
|
*self = NodeInput::Node(f(*id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for NodeInput {
|
impl PartialEq for NodeInput {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
match (&self, &other) {
|
match (&self, &other) {
|
||||||
|
|
@ -110,7 +110,7 @@ impl PartialEq for NodeInput {
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum DocumentNodeImplementation {
|
pub enum DocumentNodeImplementation {
|
||||||
Network(NodeNetwork),
|
Network(NodeNetwork),
|
||||||
ProtoNode(ProtoNode),
|
Unresolved(Fqn),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq)]
|
#[derive(Debug, Default, PartialEq)]
|
||||||
|
|
@ -119,127 +119,6 @@ pub struct NodeNetwork {
|
||||||
pub output: NodeId,
|
pub output: NodeId,
|
||||||
pub nodes: HashMap<NodeId, DocumentNode>,
|
pub nodes: HashMap<NodeId, DocumentNode>,
|
||||||
}
|
}
|
||||||
pub type Value = Box<dyn ValueTrait>;
|
|
||||||
pub trait ValueTrait: DynAny<'static> + std::fmt::Debug + DynClone {}
|
|
||||||
|
|
||||||
pub trait IntoValue: Sized + ValueTrait + 'static {
|
|
||||||
fn into_any(self) -> Value {
|
|
||||||
Box::new(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: 'static + StaticType + std::fmt::Debug + PartialEq + Clone> ValueTrait for T {}
|
|
||||||
impl<T: 'static + ValueTrait> IntoValue for T {}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
struct Vtable {
|
|
||||||
destructor: unsafe fn(*mut ()),
|
|
||||||
size: usize,
|
|
||||||
align: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
struct TraitObject {
|
|
||||||
self_ptr: *mut u8,
|
|
||||||
vtable: &'static Vtable,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Box<dyn ValueTrait> {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
if self.type_id() != other.type_id() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) };
|
|
||||||
let other_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(other.as_ref()) };
|
|
||||||
let size = self_trait_object.vtable.size;
|
|
||||||
let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) };
|
|
||||||
let other_mem = unsafe { std::slice::from_raw_parts(other_trait_object.self_ptr, size) };
|
|
||||||
self_mem == other_mem
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for Value {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) };
|
|
||||||
let size = self_trait_object.vtable.size;
|
|
||||||
let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) }.to_owned();
|
|
||||||
let ptr = Vec::leak(self_mem);
|
|
||||||
unsafe {
|
|
||||||
std::mem::transmute(TraitObject {
|
|
||||||
self_ptr: ptr as *mut [u8] as *mut u8,
|
|
||||||
vtable: self_trait_object.vtable,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub enum ConstructionArgs {
|
|
||||||
None,
|
|
||||||
#[default]
|
|
||||||
Unresolved,
|
|
||||||
Value(Value),
|
|
||||||
Nodes(Vec<NodeId>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for ConstructionArgs {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
match (&self, &other) {
|
|
||||||
(Self::Nodes(n1), Self::Nodes(n2)) => n1 == n2,
|
|
||||||
(Self::Value(v1), Self::Value(v2)) => v1 == v2,
|
|
||||||
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq)]
|
|
||||||
pub struct ProtoNode {
|
|
||||||
pub construction_args: ConstructionArgs,
|
|
||||||
pub input: ProtoNodeInput,
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq, Eq)]
|
|
||||||
pub enum ProtoNodeInput {
|
|
||||||
None,
|
|
||||||
#[default]
|
|
||||||
Network,
|
|
||||||
Node(NodeId),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NodeInput {
|
|
||||||
fn map_ids(&mut self, f: impl Fn(NodeId) -> NodeId) {
|
|
||||||
if let NodeInput::Node(id) = self {
|
|
||||||
*self = NodeInput::Node(f(*id))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
name: "id".into(),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn unresolved(name: String) -> Self {
|
|
||||||
Self { name, ..Default::default() }
|
|
||||||
}
|
|
||||||
pub fn value(name: String, value: ConstructionArgs) -> Self {
|
|
||||||
Self {
|
|
||||||
name,
|
|
||||||
construction_args: value,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NodeNetwork {
|
impl NodeNetwork {
|
||||||
pub fn map_ids(&mut self, f: impl Fn(NodeId) -> NodeId + Copy) {
|
pub fn map_ids(&mut self, f: impl Fn(NodeId) -> NodeId + Copy) {
|
||||||
|
|
@ -286,7 +165,7 @@ impl NodeNetwork {
|
||||||
let value_node = DocumentNode {
|
let value_node = DocumentNode {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
inputs: vec![NodeInput::Value(value)],
|
inputs: vec![NodeInput::Value(value)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::unresolved("value".into())),
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::value::ValueNode", &[Type::Generic])),
|
||||||
};
|
};
|
||||||
assert!(!self.nodes.contains_key(&new_id));
|
assert!(!self.nodes.contains_key(&new_id));
|
||||||
self.nodes.insert(new_id, value_node);
|
self.nodes.insert(new_id, value_node);
|
||||||
|
|
@ -301,50 +180,41 @@ impl NodeNetwork {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.implementation = DocumentNodeImplementation::ProtoNode(ProtoNode::id());
|
node.implementation = DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode", &[Type::Generic]));
|
||||||
node.inputs = vec![NodeInput::Node(inner_network.output)];
|
node.inputs = vec![NodeInput::Node(inner_network.output)];
|
||||||
for node_id in new_nodes {
|
for node_id in new_nodes {
|
||||||
self.flatten_with_fns(node_id, map_ids, gen_id);
|
self.flatten_with_fns(node_id, map_ids, gen_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DocumentNodeImplementation::ProtoNode(proto_node) => {
|
DocumentNodeImplementation::Unresolved(_) => (),
|
||||||
node.implementation = DocumentNodeImplementation::ProtoNode(proto_node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert!(!self.nodes.contains_key(&id), "Trying to insert a node into the network caused an id conflict");
|
assert!(!self.nodes.contains_key(&id), "Trying to insert a node into the network caused an id conflict");
|
||||||
self.nodes.insert(id, node);
|
self.nodes.insert(id, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_proto_nodes(&mut self) {
|
pub fn into_proto_network(self) -> ProtoNetwork {
|
||||||
for node in self.nodes.values_mut() {
|
let mut nodes: Vec<_> = self.nodes.into_iter().map(|(id, node)| (id, node.resolve_proto_node())).collect();
|
||||||
node.resolve_proto_nodes();
|
nodes.sort_unstable_by_key(|(i, _)| *i);
|
||||||
|
ProtoNetwork {
|
||||||
|
inputs: self.inputs,
|
||||||
|
output: self.output,
|
||||||
|
nodes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Map<I, O>(core::marker::PhantomData<(I, O)>);
|
|
||||||
|
|
||||||
impl<O> Display for Map<(), O> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
|
||||||
write!(f, "Map")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Map<i32, String> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
|
||||||
write!(f, "Map<String>")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::proto::{ConstructionArgs, NodeIdentifier, ProtoNetwork, ProtoNode, ProtoNodeInput};
|
||||||
|
use value::IntoValue;
|
||||||
|
|
||||||
#[test]
|
fn gen_node_id() -> NodeId {
|
||||||
fn test_any_src() {
|
static mut NODE_ID: NodeId = 3;
|
||||||
assert!(2_u32.into_any() == 2_u32.into_any());
|
unsafe {
|
||||||
assert!(2_u32.into_any() != 3_u32.into_any());
|
NODE_ID += 1;
|
||||||
assert!(2_u32.into_any() != 3_i32.into_any());
|
NODE_ID
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_network() -> NodeNetwork {
|
fn add_network() -> NodeNetwork {
|
||||||
|
|
@ -357,7 +227,7 @@ mod test {
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "cons".into(),
|
name: "cons".into(),
|
||||||
inputs: vec![NodeInput::Network, NodeInput::Network],
|
inputs: vec![NodeInput::Network, NodeInput::Network],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::unresolved("cons".into())),
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic])),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
|
@ -365,7 +235,7 @@ mod test {
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "add".into(),
|
name: "add".into(),
|
||||||
inputs: vec![NodeInput::Node(0)],
|
inputs: vec![NodeInput::Node(0)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::unresolved("add".into())),
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Generic, Type::Generic])),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
@ -387,7 +257,7 @@ mod test {
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "cons".into(),
|
name: "cons".into(),
|
||||||
inputs: vec![NodeInput::Network, NodeInput::Network],
|
inputs: vec![NodeInput::Network, NodeInput::Network],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::value("cons".into(), ConstructionArgs::Unresolved)),
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic])),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
|
@ -395,7 +265,7 @@ mod test {
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "add".into(),
|
name: "add".into(),
|
||||||
inputs: vec![NodeInput::Node(1)],
|
inputs: vec![NodeInput::Node(1)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::value("add".into(), ConstructionArgs::Unresolved)),
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Generic, Type::Generic])),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
@ -431,85 +301,58 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_proto_node_add() {
|
fn resolve_proto_node_add() {
|
||||||
let mut d_node = DocumentNode {
|
let document_node = DocumentNode {
|
||||||
name: "cons".into(),
|
name: "cons".into(),
|
||||||
inputs: vec![NodeInput::Network, NodeInput::Node(0)],
|
inputs: vec![NodeInput::Network, NodeInput::Node(0)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::value("cons".into(), ConstructionArgs::Unresolved)),
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic])),
|
||||||
};
|
};
|
||||||
|
|
||||||
d_node.resolve_proto_nodes();
|
let proto_node = document_node.resolve_proto_node();
|
||||||
let reference = DocumentNode {
|
let reference = ProtoNode {
|
||||||
name: "cons".into(),
|
identifier: NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic]),
|
||||||
inputs: vec![],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode {
|
|
||||||
name: "cons".into(),
|
|
||||||
input: ProtoNodeInput::Network,
|
input: ProtoNodeInput::Network,
|
||||||
construction_args: ConstructionArgs::Nodes(vec![0]),
|
construction_args: ConstructionArgs::Nodes(vec![0]),
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
assert_eq!(d_node, reference);
|
assert_eq!(proto_node, reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_flatten_add() {
|
fn resolve_flatten_add_as_proto_network() {
|
||||||
let construction_network = NodeNetwork {
|
let construction_network = ProtoNetwork {
|
||||||
inputs: vec![10],
|
inputs: vec![10],
|
||||||
output: 1,
|
output: 1,
|
||||||
nodes: [
|
nodes: [
|
||||||
(
|
(
|
||||||
1,
|
1,
|
||||||
DocumentNode {
|
ProtoNode {
|
||||||
name: "Inc".into(),
|
identifier: NodeIdentifier::new("graphene_core::ops::IdNode", &[Type::Generic]),
|
||||||
inputs: vec![],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode {
|
|
||||||
name: "id".into(),
|
|
||||||
input: ProtoNodeInput::Node(11),
|
input: ProtoNodeInput::Node(11),
|
||||||
construction_args: ConstructionArgs::None,
|
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
10,
|
10,
|
||||||
DocumentNode {
|
ProtoNode {
|
||||||
name: "cons".into(),
|
identifier: NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic]),
|
||||||
inputs: vec![],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode {
|
|
||||||
name: "cons".into(),
|
|
||||||
input: ProtoNodeInput::Network,
|
input: ProtoNodeInput::Network,
|
||||||
construction_args: ConstructionArgs::Nodes(vec![14]),
|
construction_args: ConstructionArgs::Nodes(vec![14]),
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
11,
|
11,
|
||||||
DocumentNode {
|
ProtoNode {
|
||||||
name: "add".into(),
|
identifier: NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Generic, Type::Generic]),
|
||||||
inputs: vec![],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode {
|
|
||||||
name: "add".into(),
|
|
||||||
input: ProtoNodeInput::Node(10),
|
input: ProtoNodeInput::Node(10),
|
||||||
construction_args: ConstructionArgs::None,
|
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||||
}),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
14,
|
|
||||||
DocumentNode {
|
|
||||||
name: "Value: 2".into(),
|
|
||||||
inputs: vec![],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode {
|
|
||||||
name: "value".into(),
|
|
||||||
input: ProtoNodeInput::None,
|
|
||||||
construction_args: ConstructionArgs::Value(2_u32.into_any()),
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
(14, ProtoNode::value(ConstructionArgs::Value(2_u32.into_any()))),
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
let mut resolved_network = flat_network();
|
let network = flat_network();
|
||||||
resolved_network.resolve_proto_nodes();
|
let resolved_network = network.into_proto_network();
|
||||||
|
|
||||||
println!("{:#?}", resolved_network);
|
println!("{:#?}", resolved_network);
|
||||||
println!("{:#?}", construction_network);
|
println!("{:#?}", construction_network);
|
||||||
|
|
@ -526,7 +369,7 @@ mod test {
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "Inc".into(),
|
name: "Inc".into(),
|
||||||
inputs: vec![NodeInput::Node(11)],
|
inputs: vec![NodeInput::Node(11)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::id()),
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode", &[Type::Generic])),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
|
@ -534,7 +377,7 @@ mod test {
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "cons".into(),
|
name: "cons".into(),
|
||||||
inputs: vec![NodeInput::Network, NodeInput::Node(14)],
|
inputs: vec![NodeInput::Network, NodeInput::Node(14)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::unresolved("cons".into())),
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic])),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
|
@ -542,7 +385,7 @@ mod test {
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "Value: 2".into(),
|
name: "Value: 2".into(),
|
||||||
inputs: vec![NodeInput::Value(2_u32.into_any())],
|
inputs: vec![NodeInput::Value(2_u32.into_any())],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::unresolved("value".into())),
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::value::ValueNode", &[Type::Generic])),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
|
@ -550,7 +393,7 @@ mod test {
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "add".into(),
|
name: "add".into(),
|
||||||
inputs: vec![NodeInput::Node(10)],
|
inputs: vec![NodeInput::Node(10)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode::unresolved("add".into())),
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Generic, Type::Generic])),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
use dyn_any::StaticType;
|
||||||
|
|
||||||
|
use dyn_clone::DynClone;
|
||||||
|
|
||||||
|
use dyn_any::DynAny;
|
||||||
|
|
||||||
|
pub type Value = Box<dyn ValueTrait>;
|
||||||
|
|
||||||
|
pub trait ValueTrait: DynAny<'static> + std::fmt::Debug + DynClone {}
|
||||||
|
|
||||||
|
pub trait IntoValue: Sized + ValueTrait + 'static {
|
||||||
|
fn into_any(self) -> Value {
|
||||||
|
Box::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static + StaticType + std::fmt::Debug + PartialEq + Clone> ValueTrait for T {}
|
||||||
|
|
||||||
|
impl<T: 'static + ValueTrait> IntoValue for T {}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub(crate) struct Vtable {
|
||||||
|
pub(crate) destructor: unsafe fn(*mut ()),
|
||||||
|
pub(crate) size: usize,
|
||||||
|
pub(crate) align: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub(crate) struct TraitObject {
|
||||||
|
pub(crate) self_ptr: *mut u8,
|
||||||
|
pub(crate) vtable: &'static Vtable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Box<dyn ValueTrait> {
|
||||||
|
#[cfg_attr(miri, ignore)]
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
if self.type_id() != other.type_id() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) };
|
||||||
|
let other_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(other.as_ref()) };
|
||||||
|
let size = self_trait_object.vtable.size;
|
||||||
|
let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) };
|
||||||
|
let other_mem = unsafe { std::slice::from_raw_parts(other_trait_object.self_ptr, size) };
|
||||||
|
self_mem == other_mem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Value {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) };
|
||||||
|
let size = self_trait_object.vtable.size;
|
||||||
|
let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) }.to_owned();
|
||||||
|
let ptr = Vec::leak(self_mem);
|
||||||
|
unsafe {
|
||||||
|
std::mem::transmute(TraitObject {
|
||||||
|
self_ptr: ptr as *mut [u8] as *mut u8,
|
||||||
|
vtable: self_trait_object.vtable,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_any_src() {
|
||||||
|
assert!(2_u32.into_any() == 2_u32.into_any());
|
||||||
|
assert!(2_u32.into_any() != 3_u32.into_any());
|
||||||
|
assert!(2_u32.into_any() != 3_i32.into_any());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
#![feature(trait_upcasting)]
|
#![feature(trait_upcasting)]
|
||||||
pub mod node_registry;
|
pub mod node_registry;
|
||||||
|
|
||||||
|
pub mod document;
|
||||||
|
pub mod proto;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
|
|
@ -9,7 +12,9 @@ mod tests {
|
||||||
use graphene_core::value::ValueNode;
|
use graphene_core::value::ValueNode;
|
||||||
use graphene_core::{structural::*, RefNode};
|
use graphene_core::{structural::*, RefNode};
|
||||||
|
|
||||||
|
use crate::document::value::IntoValue;
|
||||||
use borrow_stack::BorrowStack;
|
use borrow_stack::BorrowStack;
|
||||||
|
use borrow_stack::FixedSizeStack;
|
||||||
use dyn_any::{downcast, IntoDynAny};
|
use dyn_any::{downcast, IntoDynAny};
|
||||||
use graphene_std::any::{Any, DowncastNode, DynAnyNode, TypeErasedNode};
|
use graphene_std::any::{Any, DowncastNode, DynAnyNode, TypeErasedNode};
|
||||||
use graphene_std::ops::AddNode;
|
use graphene_std::ops::AddNode;
|
||||||
|
|
@ -27,7 +32,6 @@ mod tests {
|
||||||
let dynanynode: DynAnyNode<ConsNode<_, Any<'_>>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData));
|
let dynanynode: DynAnyNode<ConsNode<_, Any<'_>>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData));
|
||||||
dynanynode.into_box()
|
dynanynode.into_box()
|
||||||
});
|
});
|
||||||
/*
|
|
||||||
stack.push_fn(|_| {
|
stack.push_fn(|_| {
|
||||||
let dynanynode: DynAnyNode<_, (u32, &u32), _, _> = DynAnyNode::new(AddNode);
|
let dynanynode: DynAnyNode<_, (u32, &u32), _, _> = DynAnyNode::new(AddNode);
|
||||||
dynanynode.into_box()
|
dynanynode.into_box()
|
||||||
|
|
@ -35,79 +39,81 @@ mod tests {
|
||||||
stack.push_fn(|nodes| {
|
stack.push_fn(|nodes| {
|
||||||
let compose_node = nodes[1].after(&nodes[2]);
|
let compose_node = nodes[1].after(&nodes[2]);
|
||||||
TypeErasedNode(Box::new(compose_node))
|
TypeErasedNode(Box::new(compose_node))
|
||||||
});}*/
|
});
|
||||||
|
|
||||||
let result = unsafe { &stack.get()[0] }.eval_ref(().into_dyn());
|
let result = unsafe { &stack.get()[0] }.eval_ref(().into_dyn());
|
||||||
assert_eq!(*downcast::<&u32>(result).unwrap(), &2_u32);
|
assert_eq!(*downcast::<&u32>(result).unwrap(), &2_u32);
|
||||||
let result = unsafe { &stack.get()[1] }.eval_ref(4_u32.into_dyn());
|
let result = unsafe { &stack.get()[1] }.eval_ref(4_u32.into_dyn());
|
||||||
assert_eq!(*downcast::<(u32, &u32)>(result).unwrap(), (4_u32, &2_u32));
|
assert_eq!(*downcast::<(u32, &u32)>(result).unwrap(), (4_u32, &2_u32));
|
||||||
/*
|
|
||||||
let result = unsafe { &stack.get()[1] }.eval_ref(4_u32.into_dyn());
|
let result = unsafe { &stack.get()[1] }.eval_ref(4_u32.into_dyn());
|
||||||
let add = unsafe { &stack.get()[2] }.eval_ref(result);
|
let add = unsafe { &stack.get()[2] }.eval_ref(result);
|
||||||
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
|
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
|
||||||
let add = unsafe { &stack.get()[3] }.eval_ref(4_u32.into_dyn());
|
let add = unsafe { &stack.get()[3] }.eval_ref(4_u32.into_dyn());
|
||||||
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);*/
|
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn craft_from_flattened() {
|
fn execute_add() {
|
||||||
use graphene_std::document::*;
|
use crate::document::*;
|
||||||
// This is input and evaluated
|
use crate::node_registry::push_node;
|
||||||
let construction_network = NodeNetwork {
|
use crate::proto::*;
|
||||||
inputs: vec![10],
|
use graphene_core::Node;
|
||||||
|
|
||||||
|
fn add_network() -> NodeNetwork {
|
||||||
|
NodeNetwork {
|
||||||
|
inputs: vec![0, 0],
|
||||||
output: 1,
|
output: 1,
|
||||||
nodes: [
|
nodes: [
|
||||||
|
(
|
||||||
|
0,
|
||||||
|
DocumentNode {
|
||||||
|
name: "cons".into(),
|
||||||
|
inputs: vec![NodeInput::Network, NodeInput::Network],
|
||||||
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Concrete("u32"), Type::Concrete("u32")])),
|
||||||
|
},
|
||||||
|
),
|
||||||
(
|
(
|
||||||
1,
|
1,
|
||||||
DocumentNode {
|
|
||||||
name: "Inc".into(),
|
|
||||||
inputs: vec![],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode {
|
|
||||||
name: "id".into(),
|
|
||||||
input: ProtoNodeInput::Node(11),
|
|
||||||
construction_args: ConstructionArgs::None,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
10,
|
|
||||||
DocumentNode {
|
|
||||||
name: "cons".into(),
|
|
||||||
inputs: vec![],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode {
|
|
||||||
name: "cons".into(),
|
|
||||||
input: ProtoNodeInput::Network,
|
|
||||||
construction_args: ConstructionArgs::Nodes(vec![14]),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
11,
|
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "add".into(),
|
name: "add".into(),
|
||||||
inputs: vec![],
|
inputs: vec![NodeInput::Node(0)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode {
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Concrete("u32"), Type::Concrete("u32")])),
|
||||||
name: "add".into(),
|
|
||||||
input: ProtoNodeInput::Node(10),
|
|
||||||
construction_args: ConstructionArgs::None,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
14,
|
|
||||||
DocumentNode {
|
|
||||||
name: "Value: 2".into(),
|
|
||||||
inputs: vec![],
|
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNode {
|
|
||||||
name: "value".into(),
|
|
||||||
input: ProtoNodeInput::None,
|
|
||||||
construction_args: ConstructionArgs::Value(2_u32.into_any()),
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut network = NodeNetwork {
|
||||||
|
inputs: vec![0],
|
||||||
|
output: 0,
|
||||||
|
nodes: [(
|
||||||
|
0,
|
||||||
|
DocumentNode {
|
||||||
|
name: "Inc".into(),
|
||||||
|
inputs: vec![NodeInput::Network, NodeInput::Value(1_u32.into_any())],
|
||||||
|
implementation: DocumentNodeImplementation::Network(add_network()),
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let stack = FixedSizeStack::new(256);
|
||||||
|
println!("flattening");
|
||||||
|
network.flatten(0);
|
||||||
|
//println!("flat_network: {:#?}", network);
|
||||||
|
let mut proto_network = network.into_proto_network();
|
||||||
|
proto_network.reorder_ids();
|
||||||
|
//println!("reordered_ides: {:#?}", proto_network);
|
||||||
|
for (_id, node) in proto_network.nodes {
|
||||||
|
push_node(node, &stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = unsafe { stack.get().last().unwrap().eval(32_u32.into_dyn()) };
|
||||||
|
let val = *dyn_any::downcast::<u32>(result).unwrap();
|
||||||
|
assert_eq!(val, 33_u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,39 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use borrow_stack::FixedSizeStack;
|
use borrow_stack::FixedSizeStack;
|
||||||
use dyn_clone::DynClone;
|
|
||||||
use graphene_core::generic::FnNode;
|
use graphene_core::generic::FnNode;
|
||||||
use graphene_core::ops::{AddNode, IdNode};
|
use graphene_core::ops::{AddNode, IdNode};
|
||||||
use graphene_core::raster::color::Color;
|
use graphene_core::raster::color::Color;
|
||||||
use graphene_core::structural::{ConsNode, Then};
|
use graphene_core::structural::{ConsNode, Then};
|
||||||
use graphene_core::{AsRefNode, Node};
|
use graphene_core::{AsRefNode, Node};
|
||||||
use graphene_std::any::DowncastBothNode;
|
use graphene_std::any::DowncastBothNode;
|
||||||
|
use graphene_std::any::{Any, DowncastNode, DynAnyNode, IntoTypeErasedNode, TypeErasedNode};
|
||||||
use graphene_std::raster::Image;
|
use graphene_std::raster::Image;
|
||||||
use graphene_std::{
|
|
||||||
any::{Any, DowncastNode, DynAnyNode, IntoTypeErasedNode, TypeErasedNode},
|
|
||||||
document::{ConstructionArgs, ProtoNode, ProtoNodeInput},
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NodeIdentifier {
|
use crate::proto::Type;
|
||||||
name: &'static str,
|
use crate::proto::{ConstructionArgs, NodeIdentifier, ProtoNode, ProtoNodeInput, Type::Concrete};
|
||||||
types: &'static [&'static str],
|
|
||||||
}
|
|
||||||
|
|
||||||
static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack<TypeErasedNode<'static>>))] = &[
|
type NodeConstructor = fn(ProtoNode, &FixedSizeStack<TypeErasedNode<'static>>);
|
||||||
|
|
||||||
|
//TODO: turn into hasmap
|
||||||
|
static NODE_REGISTRY: &[(NodeIdentifier<'static>, NodeConstructor)] = &[
|
||||||
(
|
(
|
||||||
NodeIdentifier {
|
NodeIdentifier {
|
||||||
name: "graphene_core::ops::IdNode",
|
name: "graphene_core::ops::IdNode",
|
||||||
types: &["Any<'n>"],
|
types: &[Concrete("Any<'_>")],
|
||||||
|
},
|
||||||
|
|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::IdNode",
|
||||||
|
types: &[Type::Generic],
|
||||||
},
|
},
|
||||||
|proto_node, stack| {
|
|proto_node, stack| {
|
||||||
stack.push_fn(|nodes| {
|
stack.push_fn(|nodes| {
|
||||||
|
|
@ -36,7 +46,7 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack<TypeErase
|
||||||
(
|
(
|
||||||
NodeIdentifier {
|
NodeIdentifier {
|
||||||
name: "graphene_core::ops::AddNode",
|
name: "graphene_core::ops::AddNode",
|
||||||
types: &["u32", "u32"],
|
types: &[Concrete("u32"), Concrete("u32")],
|
||||||
},
|
},
|
||||||
|proto_node, stack| {
|
|proto_node, stack| {
|
||||||
stack.push_fn(|nodes| {
|
stack.push_fn(|nodes| {
|
||||||
|
|
@ -48,10 +58,95 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack<TypeErase
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
NodeIdentifier {
|
||||||
|
name: "graphene_core::ops::AddNode",
|
||||||
|
types: &[Concrete("&u32"), Concrete("&u32")],
|
||||||
|
},
|
||||||
|
|proto_node, stack| {
|
||||||
|
stack.push_fn(|nodes| {
|
||||||
|
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
|
||||||
|
let node: DynAnyNode<AddNode, (&u32, &u32), _, _> = DynAnyNode::new(graphene_core::ops::AddNode);
|
||||||
|
let node = (pre_node).then(node);
|
||||||
|
|
||||||
|
node.into_type_erased()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
NodeIdentifier {
|
||||||
|
name: "graphene_core::ops::AddNode",
|
||||||
|
types: &[Concrete("&u32"), Concrete("u32")],
|
||||||
|
},
|
||||||
|
|proto_node, stack| {
|
||||||
|
stack.push_fn(|nodes| {
|
||||||
|
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
|
||||||
|
let node: DynAnyNode<AddNode, (&u32, u32), _, _> = DynAnyNode::new(graphene_core::ops::AddNode);
|
||||||
|
let node = (pre_node).then(node);
|
||||||
|
|
||||||
|
node.into_type_erased()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
),
|
||||||
(
|
(
|
||||||
NodeIdentifier {
|
NodeIdentifier {
|
||||||
name: "graphene_core::structural::ConsNode",
|
name: "graphene_core::structural::ConsNode",
|
||||||
types: &["&TypeErasedNode", "&u32", "u32"],
|
types: &[Concrete("&u32"), Concrete("u32")],
|
||||||
|
},
|
||||||
|
|proto_node, stack| {
|
||||||
|
if let ConstructionArgs::Nodes(cons_node_arg) = proto_node.construction_args {
|
||||||
|
stack.push_fn(move |nodes| {
|
||||||
|
let cons_node_arg = nodes.get(cons_node_arg[0] as usize).unwrap();
|
||||||
|
|
||||||
|
let cons_node = ConsNode::new(DowncastNode::<_, &u32>::new(cons_node_arg));
|
||||||
|
let node: DynAnyNode<_, u32, _, _> = DynAnyNode::new(cons_node);
|
||||||
|
let node = match proto_node.input {
|
||||||
|
ProtoNodeInput::Network => node.into_type_erased(),
|
||||||
|
ProtoNodeInput::Node(node_id) => {
|
||||||
|
let pre_node = nodes.get(node_id as usize).unwrap();
|
||||||
|
(pre_node).then(node).into_type_erased()
|
||||||
|
}
|
||||||
|
ProtoNodeInput::None => unreachable!(),
|
||||||
|
};
|
||||||
|
node
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
NodeIdentifier {
|
||||||
|
name: "graphene_core::structural::ConsNode",
|
||||||
|
types: &[Concrete("u32"), Concrete("u32")],
|
||||||
|
},
|
||||||
|
|proto_node, stack| {
|
||||||
|
if let ConstructionArgs::Nodes(cons_node_arg) = proto_node.construction_args {
|
||||||
|
stack.push_fn(move |nodes| {
|
||||||
|
let cons_node_arg = nodes.get(cons_node_arg[0] as usize).unwrap();
|
||||||
|
|
||||||
|
let cons_node = ConsNode::new(DowncastNode::<_, u32>::new(cons_node_arg));
|
||||||
|
let node: DynAnyNode<_, u32, _, _> = DynAnyNode::new(cons_node);
|
||||||
|
let node = match proto_node.input {
|
||||||
|
ProtoNodeInput::Network => node.into_type_erased(),
|
||||||
|
ProtoNodeInput::Node(node_id) => {
|
||||||
|
let pre_node = nodes.get(node_id as usize).unwrap();
|
||||||
|
(pre_node).then(node).into_type_erased()
|
||||||
|
}
|
||||||
|
ProtoNodeInput::None => unreachable!(),
|
||||||
|
};
|
||||||
|
node
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// TODO: create macro to impl for all types
|
||||||
|
(
|
||||||
|
NodeIdentifier {
|
||||||
|
name: "graphene_core::structural::ConsNode",
|
||||||
|
types: &[Concrete("&u32"), Concrete("&u32")],
|
||||||
},
|
},
|
||||||
|proto_node, stack| {
|
|proto_node, stack| {
|
||||||
let node_id = proto_node.input.unwrap_node() as usize;
|
let node_id = proto_node.input.unwrap_node() as usize;
|
||||||
|
|
@ -60,8 +155,8 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack<TypeErase
|
||||||
let pre_node = nodes.get(node_id).unwrap();
|
let pre_node = nodes.get(node_id).unwrap();
|
||||||
let cons_node_arg = nodes.get(cons_node_arg[0] as usize).unwrap();
|
let cons_node_arg = nodes.get(cons_node_arg[0] as usize).unwrap();
|
||||||
|
|
||||||
let cons_node = ConsNode::new(DowncastNode::<_, u32>::new(cons_node_arg));
|
let cons_node = ConsNode::new(DowncastNode::<_, &u32>::new(cons_node_arg));
|
||||||
let node: DynAnyNode<_, u32, _, _> = DynAnyNode::new(cons_node);
|
let node: DynAnyNode<_, &u32, _, _> = DynAnyNode::new(cons_node);
|
||||||
let node = (pre_node).then(node);
|
let node = (pre_node).then(node);
|
||||||
node.into_type_erased()
|
node.into_type_erased()
|
||||||
})
|
})
|
||||||
|
|
@ -73,7 +168,7 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack<TypeErase
|
||||||
(
|
(
|
||||||
NodeIdentifier {
|
NodeIdentifier {
|
||||||
name: "graphene_core::any::DowncastNode",
|
name: "graphene_core::any::DowncastNode",
|
||||||
types: &["&TypeErasedNode", "&u32"],
|
types: &[Concrete("&u32")],
|
||||||
},
|
},
|
||||||
|proto_node, stack| {
|
|proto_node, stack| {
|
||||||
stack.push_fn(|nodes| {
|
stack.push_fn(|nodes| {
|
||||||
|
|
@ -86,7 +181,23 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack<TypeErase
|
||||||
(
|
(
|
||||||
NodeIdentifier {
|
NodeIdentifier {
|
||||||
name: "graphene_core::value::ValueNode",
|
name: "graphene_core::value::ValueNode",
|
||||||
types: &["Any<'n>"],
|
types: &[Concrete("Any<'_>")],
|
||||||
|
},
|
||||||
|
|proto_node, stack| {
|
||||||
|
stack.push_fn(|_nodes| {
|
||||||
|
if let ConstructionArgs::Value(value) = proto_node.construction_args {
|
||||||
|
let node = FnNode::new(move |_| value.clone() as Any<'static>);
|
||||||
|
node.into_type_erased()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
NodeIdentifier {
|
||||||
|
name: "graphene_core::value::ValueNode",
|
||||||
|
types: &[Type::Generic],
|
||||||
},
|
},
|
||||||
|proto_node, stack| {
|
|proto_node, stack| {
|
||||||
stack.push_fn(|_nodes| {
|
stack.push_fn(|_nodes| {
|
||||||
|
|
@ -102,7 +213,7 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack<TypeErase
|
||||||
(
|
(
|
||||||
NodeIdentifier {
|
NodeIdentifier {
|
||||||
name: "graphene_core::raster::GrayscaleNode",
|
name: "graphene_core::raster::GrayscaleNode",
|
||||||
types: &["Color"],
|
types: &[],
|
||||||
},
|
},
|
||||||
|proto_node, stack| {
|
|proto_node, stack| {
|
||||||
stack.push_fn(|nodes| {
|
stack.push_fn(|nodes| {
|
||||||
|
|
@ -120,7 +231,7 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack<TypeErase
|
||||||
(
|
(
|
||||||
NodeIdentifier {
|
NodeIdentifier {
|
||||||
name: "graphene_std::raster::MapImageNode",
|
name: "graphene_std::raster::MapImageNode",
|
||||||
types: &["Image"],
|
types: &[],
|
||||||
},
|
},
|
||||||
|proto_node, stack| {
|
|proto_node, stack| {
|
||||||
let node_id = proto_node.input.unwrap_node() as usize;
|
let node_id = proto_node.input.unwrap_node() as usize;
|
||||||
|
|
@ -143,8 +254,8 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack<TypeErase
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
NodeIdentifier {
|
NodeIdentifier {
|
||||||
name: "graphene_std::raster::image_node",
|
name: "graphene_std::raster::ImageNode",
|
||||||
types: &["&str"],
|
types: &[Concrete("&str")],
|
||||||
},
|
},
|
||||||
|_proto_node, stack| {
|
|_proto_node, stack| {
|
||||||
stack.push_fn(|_nodes| {
|
stack.push_fn(|_nodes| {
|
||||||
|
|
@ -156,8 +267,8 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack<TypeErase
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
NodeIdentifier {
|
NodeIdentifier {
|
||||||
name: "graphene_std::raster::export_image_node",
|
name: "graphene_std::raster::ExportImageNode",
|
||||||
types: &["Image", "&str"],
|
types: &[Concrete("&str")],
|
||||||
},
|
},
|
||||||
|proto_node, stack| {
|
|proto_node, stack| {
|
||||||
stack.push_fn(|nodes| {
|
stack.push_fn(|nodes| {
|
||||||
|
|
@ -173,7 +284,7 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack<TypeErase
|
||||||
(
|
(
|
||||||
NodeIdentifier {
|
NodeIdentifier {
|
||||||
name: "graphene_core::structural::ConsNode",
|
name: "graphene_core::structural::ConsNode",
|
||||||
types: &["Image", "&str"],
|
types: &[Concrete("Image"), Concrete("&str")],
|
||||||
},
|
},
|
||||||
|proto_node, stack| {
|
|proto_node, stack| {
|
||||||
let node_id = proto_node.input.unwrap_node() as usize;
|
let node_id = proto_node.input.unwrap_node() as usize;
|
||||||
|
|
@ -194,6 +305,14 @@ static NODE_REGISTRY: &[(NodeIdentifier, fn(ProtoNode, &FixedSizeStack<TypeErase
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub fn push_node(proto_node: ProtoNode, stack: &FixedSizeStack<TypeErasedNode<'static>>) {
|
||||||
|
if let Some((_id, f)) = NODE_REGISTRY.iter().find(|(id, _)| *id == proto_node.identifier) {
|
||||||
|
f(proto_node, stack);
|
||||||
|
} else {
|
||||||
|
panic!("NodeImplementation: {:?} not found in Registry", proto_node.identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod protograph_testing {
|
mod protograph_testing {
|
||||||
use borrow_stack::BorrowStack;
|
use borrow_stack::BorrowStack;
|
||||||
|
|
@ -208,25 +327,25 @@ mod protograph_testing {
|
||||||
#[test]
|
#[test]
|
||||||
fn add_values() {
|
fn add_values() {
|
||||||
let stack = FixedSizeStack::new(256);
|
let stack = FixedSizeStack::new(256);
|
||||||
let val_1_protonode = ProtoNode::value("name".to_string(), ConstructionArgs::Value(Box::new(2u32)));
|
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(Box::new(2u32)));
|
||||||
simple_lookup("ValueNode").1(val_1_protonode, &stack);
|
push_node(val_1_protonode, &stack);
|
||||||
|
|
||||||
let val_2_protonode = ProtoNode::value("name".to_string(), ConstructionArgs::Value(Box::new(40u32)));
|
let val_2_protonode = ProtoNode::value(ConstructionArgs::Value(Box::new(40u32)));
|
||||||
simple_lookup("ValueNode").1(val_2_protonode, &stack);
|
push_node(val_2_protonode, &stack);
|
||||||
|
|
||||||
let cons_protonode = ProtoNode {
|
let cons_protonode = ProtoNode {
|
||||||
construction_args: ConstructionArgs::Nodes(vec![1]),
|
construction_args: ConstructionArgs::Nodes(vec![1]),
|
||||||
input: ProtoNodeInput::Node(0),
|
input: ProtoNodeInput::Node(0),
|
||||||
name: "todo!()".to_string(),
|
identifier: NodeIdentifier::new("graphene_core::structural::ConsNode", &[Concrete("u32"), Concrete("u32")]),
|
||||||
};
|
};
|
||||||
simple_lookup("ConsNode").1(cons_protonode, &stack);
|
push_node(cons_protonode, &stack);
|
||||||
|
|
||||||
let add_protonode = ProtoNode {
|
let add_protonode = ProtoNode {
|
||||||
construction_args: ConstructionArgs::None,
|
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||||
input: ProtoNodeInput::Node(2),
|
input: ProtoNodeInput::Node(2),
|
||||||
name: "todo!()".to_string(),
|
identifier: NodeIdentifier::new("graphene_core::ops::AddNode", &[Concrete("u32"), Concrete("u32")]),
|
||||||
};
|
};
|
||||||
simple_lookup("AddNode").1(add_protonode, &stack);
|
push_node(add_protonode, &stack);
|
||||||
|
|
||||||
let result = unsafe { stack.get()[3].eval(Box::new(())) };
|
let result = unsafe { stack.get()[3].eval(Box::new(())) };
|
||||||
let val = *dyn_any::downcast::<u32>(result).unwrap();
|
let val = *dyn_any::downcast::<u32>(result).unwrap();
|
||||||
|
|
@ -236,15 +355,15 @@ mod protograph_testing {
|
||||||
#[test]
|
#[test]
|
||||||
fn greyscale_colour() {
|
fn greyscale_colour() {
|
||||||
let stack = FixedSizeStack::new(256);
|
let stack = FixedSizeStack::new(256);
|
||||||
let val_protonode = ProtoNode::value("name".to_string(), ConstructionArgs::Value(Box::new(Color::from_rgb8(10, 20, 30))));
|
let val_protonode = ProtoNode::value(ConstructionArgs::Value(Box::new(Color::from_rgb8(10, 20, 30))));
|
||||||
simple_lookup("ValueNode").1(val_protonode, &stack);
|
push_node(val_protonode, &stack);
|
||||||
|
|
||||||
let greyscale_protonode = ProtoNode {
|
let greyscale_protonode = ProtoNode {
|
||||||
construction_args: ConstructionArgs::None,
|
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||||
input: ProtoNodeInput::Node(0),
|
input: ProtoNodeInput::Node(0),
|
||||||
name: "todo!()".to_string(),
|
identifier: NodeIdentifier::new("graphene_core::raster::GrayscaleNode", &[]),
|
||||||
};
|
};
|
||||||
simple_lookup("GrayscaleNode").1(greyscale_protonode, &stack);
|
push_node(greyscale_protonode, &stack);
|
||||||
|
|
||||||
let result = unsafe { stack.get()[1].eval(Box::new(())) };
|
let result = unsafe { stack.get()[1].eval(Box::new(())) };
|
||||||
let val = *dyn_any::downcast::<Color>(result).unwrap();
|
let val = *dyn_any::downcast::<Color>(result).unwrap();
|
||||||
|
|
@ -255,11 +374,11 @@ mod protograph_testing {
|
||||||
fn load_image() {
|
fn load_image() {
|
||||||
let stack = FixedSizeStack::new(256);
|
let stack = FixedSizeStack::new(256);
|
||||||
let image_protonode = ProtoNode {
|
let image_protonode = ProtoNode {
|
||||||
construction_args: ConstructionArgs::None,
|
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||||
input: ProtoNodeInput::None,
|
input: ProtoNodeInput::None,
|
||||||
name: "todo!()".to_string(),
|
identifier: NodeIdentifier::new("graphene_std::raster::ImageNode", &[Concrete("&str")]),
|
||||||
};
|
};
|
||||||
simple_lookup("image_node").1(image_protonode, &stack);
|
push_node(image_protonode, &stack);
|
||||||
|
|
||||||
let result = unsafe { stack.get()[0].eval(Box::new("../gstd/test-image-1.png")) };
|
let result = unsafe { stack.get()[0].eval(Box::new("../gstd/test-image-1.png")) };
|
||||||
let image = *dyn_any::downcast::<Image>(result).unwrap();
|
let image = *dyn_any::downcast::<Image>(result).unwrap();
|
||||||
|
|
@ -270,25 +389,25 @@ mod protograph_testing {
|
||||||
fn greyscale_map_image() {
|
fn greyscale_map_image() {
|
||||||
let stack = FixedSizeStack::new(256);
|
let stack = FixedSizeStack::new(256);
|
||||||
let image_protonode = ProtoNode {
|
let image_protonode = ProtoNode {
|
||||||
construction_args: ConstructionArgs::None,
|
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||||
input: ProtoNodeInput::None,
|
input: ProtoNodeInput::None,
|
||||||
name: "todo!()".to_string(),
|
identifier: NodeIdentifier::new("graphene_std::raster::ImageNode", &[Concrete("&str")]),
|
||||||
};
|
};
|
||||||
simple_lookup("image_node").1(image_protonode, &stack);
|
push_node(image_protonode, &stack);
|
||||||
|
|
||||||
let greyscale_protonode = ProtoNode {
|
let greyscale_protonode = ProtoNode {
|
||||||
construction_args: ConstructionArgs::None,
|
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||||
input: ProtoNodeInput::None,
|
input: ProtoNodeInput::None,
|
||||||
name: "todo!()".to_string(),
|
identifier: NodeIdentifier::new("graphene_core::raster::GrayscaleNode", &[]),
|
||||||
};
|
};
|
||||||
simple_lookup("GrayscaleNode").1(greyscale_protonode, &stack);
|
push_node(greyscale_protonode, &stack);
|
||||||
|
|
||||||
let image_map_protonode = ProtoNode {
|
let image_map_protonode = ProtoNode {
|
||||||
construction_args: ConstructionArgs::Nodes(vec![1]),
|
construction_args: ConstructionArgs::Nodes(vec![1]),
|
||||||
input: ProtoNodeInput::Node(0),
|
input: ProtoNodeInput::Node(0),
|
||||||
name: "todo!()".to_string(),
|
identifier: NodeIdentifier::new("graphene_std::raster::MapImageNode", &[]),
|
||||||
};
|
};
|
||||||
simple_lookup("MapImageNode").1(image_map_protonode, &stack);
|
push_node(image_map_protonode, &stack);
|
||||||
|
|
||||||
let result = unsafe { stack.get()[2].eval(Box::new("../gstd/test-image-1.png")) };
|
let result = unsafe { stack.get()[2].eval(Box::new("../gstd/test-image-1.png")) };
|
||||||
let image = *dyn_any::downcast::<Image>(result).unwrap();
|
let image = *dyn_any::downcast::<Image>(result).unwrap();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,231 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use crate::document::value;
|
||||||
|
use crate::document::NodeId;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct NodeIdentifier<'a> {
|
||||||
|
pub name: &'a str,
|
||||||
|
pub types: &'a [Type<'a>],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Type<'a> {
|
||||||
|
Generic,
|
||||||
|
Concrete(&'a str),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a str> for Type<'a> {
|
||||||
|
fn from(s: &'a str) -> Self {
|
||||||
|
Type::Concrete(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> From<&'a str> for NodeIdentifier<'a> {
|
||||||
|
fn from(s: &'a str) -> Self {
|
||||||
|
NodeIdentifier { name: s, types: &[] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> NodeIdentifier<'a> {
|
||||||
|
pub fn new(name: &'a str, types: &'a [Type<'a>]) -> Self {
|
||||||
|
NodeIdentifier { name, types }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, PartialEq)]
|
||||||
|
pub struct ProtoNetwork {
|
||||||
|
pub inputs: Vec<NodeId>,
|
||||||
|
pub output: NodeId,
|
||||||
|
pub nodes: Vec<(NodeId, ProtoNode)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ConstructionArgs {
|
||||||
|
Value(value::Value),
|
||||||
|
Nodes(Vec<NodeId>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for ConstructionArgs {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (&self, &other) {
|
||||||
|
(Self::Nodes(n1), Self::Nodes(n2)) => n1 == n2,
|
||||||
|
(Self::Value(v1), Self::Value(v2)) => v1 == v2,
|
||||||
|
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct ProtoNode {
|
||||||
|
pub construction_args: ConstructionArgs,
|
||||||
|
pub input: ProtoNodeInput,
|
||||||
|
pub identifier: NodeIdentifier<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, PartialEq, Eq)]
|
||||||
|
pub enum ProtoNodeInput {
|
||||||
|
None,
|
||||||
|
#[default]
|
||||||
|
Network,
|
||||||
|
Node(NodeId),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProtoNodeInput {
|
||||||
|
pub fn unwrap_node(self) -> NodeId {
|
||||||
|
match self {
|
||||||
|
ProtoNodeInput::Node(id) => id,
|
||||||
|
_ => panic!("tried to unwrap id from non node input \n node: {:#?}", self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProtoNode {
|
||||||
|
pub fn value(value: ConstructionArgs) -> Self {
|
||||||
|
Self {
|
||||||
|
identifier: NodeIdentifier {
|
||||||
|
name: "graphene_core::value::ValueNode",
|
||||||
|
types: &[Type::Generic],
|
||||||
|
},
|
||||||
|
construction_args: value,
|
||||||
|
input: ProtoNodeInput::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_ids(&mut self, f: impl Fn(NodeId) -> NodeId) {
|
||||||
|
if let ProtoNodeInput::Node(id) = self.input {
|
||||||
|
self.input = ProtoNodeInput::Node(f(id))
|
||||||
|
}
|
||||||
|
if let ConstructionArgs::Nodes(ids) = &mut self.construction_args {
|
||||||
|
ids.iter_mut().for_each(|id| *id = f(*id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_construction_nodes(&self) -> Vec<NodeId> {
|
||||||
|
match &self.construction_args {
|
||||||
|
ConstructionArgs::Nodes(nodes) => nodes.clone(),
|
||||||
|
_ => panic!("tried to unwrap nodes from non node construction args \n node: {:#?}", self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProtoNetwork {
|
||||||
|
fn reverse_edges(&self) -> HashMap<NodeId, Vec<NodeId>> {
|
||||||
|
let mut edges: HashMap<NodeId, Vec<NodeId>> = HashMap::new();
|
||||||
|
for (id, node) in &self.nodes {
|
||||||
|
if let ProtoNodeInput::Node(ref_id) = &node.input {
|
||||||
|
edges.entry(*id).or_default().push(*ref_id)
|
||||||
|
}
|
||||||
|
if let ConstructionArgs::Nodes(ref_nodes) = &node.construction_args {
|
||||||
|
for ref_id in ref_nodes {
|
||||||
|
edges.entry(*id).or_default().push(*ref_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
edges
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn topological_sort(&self) -> Vec<NodeId> {
|
||||||
|
let mut visited = HashSet::new();
|
||||||
|
let mut stack = Vec::new();
|
||||||
|
let mut sorted = Vec::new();
|
||||||
|
let graph = self.reverse_edges();
|
||||||
|
// TODO: remove
|
||||||
|
println!("{:#?}", graph);
|
||||||
|
|
||||||
|
for (id, _) in &self.nodes {
|
||||||
|
if !visited.contains(id) {
|
||||||
|
stack.push(*id);
|
||||||
|
|
||||||
|
while let Some(id) = stack.pop() {
|
||||||
|
//TODO remove
|
||||||
|
println!("{:?}", stack);
|
||||||
|
if !visited.contains(&id) {
|
||||||
|
visited.insert(id);
|
||||||
|
if let Some(refs) = graph.get(&id) {
|
||||||
|
for ref_id in refs {
|
||||||
|
if !visited.contains(ref_id) {
|
||||||
|
stack.push(id);
|
||||||
|
stack.push(*ref_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sorted.push(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sorted.reverse();
|
||||||
|
sorted
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reorder_ids(&mut self) {
|
||||||
|
let order = self.topological_sort();
|
||||||
|
let lookup = self
|
||||||
|
.nodes
|
||||||
|
.iter()
|
||||||
|
.map(|(id, _)| (*id, order.iter().position(|x| x == id).unwrap() as u64))
|
||||||
|
.collect::<HashMap<u64, u64>>();
|
||||||
|
self.nodes.sort_by_key(|(id, _)| lookup.get(id).unwrap());
|
||||||
|
self.nodes.iter_mut().for_each(|(id, node)| {
|
||||||
|
node.map_ids(|id| *lookup.get(&id).unwrap());
|
||||||
|
*id = *lookup.get(id).unwrap()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, ProtoNodeInput};
|
||||||
|
use value::IntoValue;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn topological_sort() {
|
||||||
|
let construction_network = ProtoNetwork {
|
||||||
|
inputs: vec![10],
|
||||||
|
output: 1,
|
||||||
|
nodes: [
|
||||||
|
(
|
||||||
|
1,
|
||||||
|
ProtoNode {
|
||||||
|
identifier: "id".into(),
|
||||||
|
input: ProtoNodeInput::Node(11),
|
||||||
|
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
10,
|
||||||
|
ProtoNode {
|
||||||
|
identifier: "cons".into(),
|
||||||
|
input: ProtoNodeInput::Network,
|
||||||
|
construction_args: ConstructionArgs::Nodes(vec![14]),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
11,
|
||||||
|
ProtoNode {
|
||||||
|
identifier: "add".into(),
|
||||||
|
input: ProtoNodeInput::Node(10),
|
||||||
|
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
14,
|
||||||
|
ProtoNode {
|
||||||
|
identifier: "value".into(),
|
||||||
|
input: ProtoNodeInput::None,
|
||||||
|
construction_args: ConstructionArgs::Value(2_u32.into_any()),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
let sorted = construction_network.topological_sort();
|
||||||
|
|
||||||
|
println!("{:#?}", sorted);
|
||||||
|
assert_eq!(sorted, vec![14, 10, 11, 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,5 +25,4 @@ syn = {version = "1.0", default-features = false, features = ["parsing", "printi
|
||||||
proc-macro2 = {version = "1.0", default-features = false, features = ["proc-macro"]}
|
proc-macro2 = {version = "1.0", default-features = false, features = ["proc-macro"]}
|
||||||
quote = {version = "1.0", default-features = false }
|
quote = {version = "1.0", default-features = false }
|
||||||
image = "*"
|
image = "*"
|
||||||
rand_chacha = "0.3.1"
|
|
||||||
dyn-clone = "1.0"
|
dyn-clone = "1.0"
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ where
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
use graphene_core::{ops::Dynamic, AsRefNode};
|
use graphene_core::{ops::dynamic::Dynamic, AsRefNode};
|
||||||
pub struct BoxedComposition<'a, Second> {
|
pub struct BoxedComposition<'a, Second> {
|
||||||
pub first: Box<dyn Node<(), Output = Dynamic<'a>>>,
|
pub first: Box<dyn Node<(), Output = Dynamic<'a>>>,
|
||||||
pub second: Second,
|
pub second: Second,
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,6 @@ pub mod raster;
|
||||||
|
|
||||||
pub mod any;
|
pub mod any;
|
||||||
|
|
||||||
pub mod document;
|
|
||||||
|
|
||||||
pub use graphene_core::*;
|
pub use graphene_core::*;
|
||||||
|
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue