mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Restructure node graph project layout
This commit is contained in:
1319
node-graph/gstd/Cargo.lock
generated
Normal file
1319
node-graph/gstd/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
25
node-graph/gstd/Cargo.toml
Normal file
25
node-graph/gstd/Cargo.toml
Normal file
@@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "graphene-std"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "Graphene standard library"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
rust_analyzer = ["ide", "ide_db"]
|
||||
caching = ["storage-map", "lock_api", "parking_lot"]
|
||||
derive = ["graph-proc-macros"]
|
||||
memoization = ["once_cell"]
|
||||
default = ["derive", "memoization"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
graphene-core = {path = "../gcore"}
|
||||
graph-proc-macros = {path = "../proc-macro", optional = true}
|
||||
once_cell = {version= "1.10", optional = true}
|
||||
ide = { version = "*", package = "ra_ap_ide", optional = true }
|
||||
ide_db = { version = "*", package = "ra_ap_ide_db" , optional = true }
|
||||
storage-map = { version = "*", optional = true }
|
||||
lock_api = { version= "*", optional = true }
|
||||
parking_lot = { version = "*", optional = true }
|
||||
48
node-graph/gstd/src/cache.rs
Normal file
48
node-graph/gstd/src/cache.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
use parking_lot::RawRwLock;
|
||||
use std::{
|
||||
any::Any,
|
||||
borrow::Borrow,
|
||||
cell::RefCell,
|
||||
collections::{hash_map::DefaultHasher, HashMap},
|
||||
hash::{Hash, Hasher},
|
||||
iter,
|
||||
iter::Sum,
|
||||
marker::PhantomData,
|
||||
};
|
||||
use storage_map::{StorageMap, StorageMapGuard};
|
||||
|
||||
use graphene_api::{DynamicInput, Node};
|
||||
|
||||
/// Caches the output of a given Node and acts as a proxy
|
||||
/// Automatically resets if it receives different input
|
||||
pub struct SmartCacheNode<'n, 'c, NODE: Node + 'c> {
|
||||
node: &'n NODE,
|
||||
map: StorageMap<RawRwLock, HashMap<u64, CacheNode<'n, 'c, NODE>>>,
|
||||
}
|
||||
impl<'n: 'c, 'c, NODE: Node + 'c> Node for SmartCacheNode<'n, 'c, NODE>
|
||||
where
|
||||
for<'a> NODE::Input<'a>: Hash,
|
||||
{
|
||||
type Input<'a> = NODE::Input<'a> where Self: 'a, 'c : 'a;
|
||||
type Output<'a> = StorageMapGuard<'a, RawRwLock, CacheNode<'n, 'c, NODE>> where Self: 'a, 'c: 'a;
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
input.borrow().hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
|
||||
self.map
|
||||
.get_or_create_with(&hash, || CacheNode::new(self.node))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'n, 'c, NODE: Node> SmartCacheNode<'n, 'c, NODE> {
|
||||
pub fn clear(&'n mut self) {
|
||||
self.map = StorageMap::default();
|
||||
}
|
||||
pub fn new(node: &'n NODE) -> SmartCacheNode<'n, 'c, NODE> {
|
||||
SmartCacheNode {
|
||||
node,
|
||||
map: StorageMap::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
39
node-graph/gstd/src/generic.rs
Normal file
39
node-graph/gstd/src/generic.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
use std::{borrow::Borrow, marker::PhantomData};
|
||||
|
||||
use graphene_core::Node;
|
||||
pub struct FnNode<T: Fn(&In) -> O, In, O>(T, PhantomData<In>, PhantomData<O>);
|
||||
impl<T: Fn(&In) -> O, In, O> Node for FnNode<T, In, O> {
|
||||
type Output<'a> = O where Self: 'a;
|
||||
type Input<'a> = In where Self: 'a;
|
||||
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
|
||||
self.0(input.borrow())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Fn(&In) -> O, In, O> FnNode<T, In, O> {
|
||||
pub fn new(f: T) -> Self {
|
||||
FnNode(f, PhantomData::default(), PhantomData::default())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FnNodeWithState<T: Fn(&In, &State) -> O, In, O, State>(
|
||||
T,
|
||||
State,
|
||||
PhantomData<In>,
|
||||
PhantomData<O>,
|
||||
);
|
||||
impl<T: Fn(&In, &State) -> O, In, O, State> Node for FnNodeWithState<T, In, O, State> {
|
||||
type Output<'a> = O where Self: 'a;
|
||||
type Input<'a> = In where Self: 'a;
|
||||
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
|
||||
self.0(input.borrow(), &self.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Fn(&In, &State) -> O, In, O, State> FnNodeWithState<T, In, O, State> {
|
||||
pub fn new(f: T, state: State) -> Self {
|
||||
FnNodeWithState(f, state, PhantomData::default(), PhantomData::default())
|
||||
}
|
||||
}
|
||||
10
node-graph/gstd/src/lib.rs
Normal file
10
node-graph/gstd/src/lib.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
#![feature(generic_associated_types)]
|
||||
|
||||
#[cfg(feature = "caching")]
|
||||
pub mod caching;
|
||||
pub mod generic;
|
||||
#[cfg(feature = "memoization")]
|
||||
pub mod memo;
|
||||
pub mod ops;
|
||||
pub mod structural;
|
||||
pub mod value;
|
||||
13
node-graph/gstd/src/main.rs
Normal file
13
node-graph/gstd/src/main.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
use graphene_core::{Exec, Node};
|
||||
use graphene_std::*;
|
||||
|
||||
fn main() {
|
||||
let int = value::IntNode::<32>;
|
||||
let _add: u32 = ops::AddNode::<u32>::default().eval((int.exec(), int.exec()));
|
||||
let fnode = generic::FnNode::new(|(a, b): &(i32, i32)| a - b);
|
||||
//let sub = fnode.any(&("a", 2));
|
||||
let cache = memo::CacheNode::new(&fnode);
|
||||
let cached_result = cache.eval(&(2, 3));
|
||||
|
||||
println!("{}", cached_result)
|
||||
}
|
||||
28
node-graph/gstd/src/memo.rs
Normal file
28
node-graph/gstd/src/memo.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
use graphene_core::Node;
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::borrow::Borrow;
|
||||
|
||||
/// Caches the output of a given Node and acts as a proxy
|
||||
pub struct CacheNode<'n, 'c, CachedNode: Node + 'c> {
|
||||
node: &'n CachedNode,
|
||||
cache: OnceCell<CachedNode::Output<'c>>,
|
||||
}
|
||||
impl<'n: 'c, 'c, CashedNode: Node> Node for CacheNode<'n, 'c, CashedNode> {
|
||||
type Output<'a> = &'a CashedNode::Output<'c> where 'c: 'a;
|
||||
type Input<'a> = CashedNode::Input<'c> where 'c: 'a;
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
|
||||
self.cache.get_or_init(|| self.node.eval(input))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'n, 'c, CachedNode: Node> CacheNode<'n, 'c, CachedNode> {
|
||||
pub fn clear(&'n mut self) {
|
||||
self.cache = OnceCell::new();
|
||||
}
|
||||
pub fn new(node: &'n CachedNode) -> CacheNode<'n, 'c, CachedNode> {
|
||||
CacheNode {
|
||||
node,
|
||||
cache: OnceCell::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
37
node-graph/gstd/src/ops.rs
Normal file
37
node-graph/gstd/src/ops.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use std::{borrow::Borrow, marker::PhantomData};
|
||||
|
||||
use graphene_core::Node;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct AddNode<T>(PhantomData<T>);
|
||||
impl<T: std::ops::Add + 'static + Copy> Node for AddNode<T> {
|
||||
type Output<'a> = <T as std::ops::Add>::Output;
|
||||
type Input<'a> = (T, T);
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> T::Output {
|
||||
input.borrow().0 + input.borrow().1
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
/// Destructures a Tuple of two values and returns the first one
|
||||
pub struct FstNode<T, U>(PhantomData<T>, PhantomData<U>);
|
||||
impl<T: Copy, U> Node for FstNode<T, U> {
|
||||
type Output<'a> = &'a T where Self: 'a;
|
||||
type Input<'a> = &'a (T, U) where Self: 'a;
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
|
||||
let &(ref a, _) = input.borrow();
|
||||
a
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
/// Destructures a Tuple of two values and returns the first one
|
||||
pub struct SndNode<T, U>(PhantomData<T>, PhantomData<U>);
|
||||
impl<T, U: Copy> Node for SndNode<T, U> {
|
||||
type Output<'a> = &'a U where Self: 'a;
|
||||
type Input<'a> = &'a (T, U) where Self: 'a;
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
|
||||
let &(_, ref b) = input.borrow();
|
||||
b
|
||||
}
|
||||
}
|
||||
60
node-graph/gstd/src/structural.rs
Normal file
60
node-graph/gstd/src/structural.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
use std::{any::Any, borrow::Borrow};
|
||||
|
||||
use graphene_core::{DynamicInput, Node};
|
||||
pub struct ComposeNode<'n, FIRST, SECOND> {
|
||||
first: &'n FIRST,
|
||||
second: &'n SECOND,
|
||||
}
|
||||
|
||||
impl<'n, FIRST, SECOND> Node for ComposeNode<'n, FIRST, SECOND>
|
||||
where
|
||||
FIRST: Node,
|
||||
SECOND: Node,
|
||||
for<'a> FIRST::Output<'a>: Borrow<SECOND::Input<'a>>,
|
||||
{
|
||||
type Input<'a> = FIRST::Input<'a> where Self: 'a;
|
||||
type Output<'a> = SECOND::Output<'a> where Self: 'a;
|
||||
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, input: I) -> Self::Output<'a> {
|
||||
// evaluate the first node with the given input
|
||||
// and then pipe the result from the first computation
|
||||
// into the second node
|
||||
let arg = self.first.eval(input);
|
||||
self.second.eval(arg)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'n, FIRST, SECOND> ComposeNode<'n, FIRST, SECOND>
|
||||
where
|
||||
FIRST: Node,
|
||||
{
|
||||
pub fn new(first: &'n FIRST, second: &'n SECOND) -> Self {
|
||||
ComposeNode::<'n, FIRST, SECOND> { first, second }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait After: Sized {
|
||||
fn after<'a, First: Node>(&'a self, first: &'a First) -> ComposeNode<'a, First, Self> {
|
||||
ComposeNode::new(first, self)
|
||||
}
|
||||
}
|
||||
impl<Second: Node> After for Second {}
|
||||
|
||||
pub struct ProxyNode<T: DynamicInput>(T);
|
||||
impl<T: DynamicInput> Node for ProxyNode<T> {
|
||||
type Output<'a> = &'a T where Self: 'a;
|
||||
type Input<'a> = &'a () where Self: 'a;
|
||||
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, _input: I) -> Self::Output<'a> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl<T: DynamicInput> DynamicInput for ProxyNode<T> {
|
||||
fn set_kwarg_by_name(&mut self, name: &str, value: &dyn Any) {
|
||||
self.0.set_kwarg_by_name(name, value)
|
||||
}
|
||||
|
||||
fn set_arg_by_index(&mut self, index: usize, value: &dyn Any) {
|
||||
self.0.set_arg_by_index(index, value)
|
||||
}
|
||||
}
|
||||
38
node-graph/gstd/src/value.rs
Normal file
38
node-graph/gstd/src/value.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use std::borrow::Borrow;
|
||||
|
||||
use graphene_core::Node;
|
||||
|
||||
pub struct IntNode<const N: u32>;
|
||||
impl<const N: u32> Node for IntNode<N> {
|
||||
type Output<'a> = u32;
|
||||
type Input<'a> = ();
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&self, _input: I) -> u32 {
|
||||
N
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ValueNode<T>(T);
|
||||
impl<T> Node for ValueNode<T> {
|
||||
type Output<'o> = &'o T where T: 'o;
|
||||
type Input<'i> = () where T: 'i;
|
||||
fn eval<'a, I: Borrow<Self::Input<'a>>>(&'a self, _input: I) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub trait OutputNode<'a, T>: Node<Output<'a> = T> where Self: 'a {}
|
||||
impl<T: std::default::Default> DefaultNode for T {}
|
||||
|
||||
impl<T> ValueNode<T> {
|
||||
pub fn new(value: T) -> ValueNode<T> {
|
||||
ValueNode(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DefaultNode: Default {
|
||||
fn default_node() -> ValueNode<Self> {
|
||||
ValueNode::new(Self::default())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user