mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-26 03:28:12 +08:00
Construct value nodes as native record sources
This commit is contained in:
@@ -11,7 +11,7 @@ use core_types::node::Node;
|
|||||||
use core_types::registry::{EdgeHandle, edge_type};
|
use core_types::registry::{EdgeHandle, edge_type};
|
||||||
use core_types::transform::Footprint;
|
use core_types::transform::Footprint;
|
||||||
use core_types::uuid::NodeId;
|
use core_types::uuid::NodeId;
|
||||||
use core_types::value::value_edge;
|
use core_types::value::record_value_edge;
|
||||||
use core_types::{CacheHash, Color, ContextModification, MemoHash, Type, TypeDescriptor};
|
use core_types::{CacheHash, Color, ContextModification, MemoHash, Type, TypeDescriptor};
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
pub use dyn_any::StaticType;
|
pub use dyn_any::StaticType;
|
||||||
@@ -290,13 +290,13 @@ macro_rules! tagged_value {
|
|||||||
// ===============
|
// ===============
|
||||||
// MANUAL VARIANTS
|
// MANUAL VARIANTS
|
||||||
// ===============
|
// ===============
|
||||||
Self::None => Ok(value_edge(())),
|
Self::None => Ok(record_value_edge(())),
|
||||||
Self::TypeDefault(td) => {
|
Self::TypeDefault(td) => {
|
||||||
// Same direct-construction path as `to_dynany` for the same reason as in `to_dynany`.
|
// Same direct-construction path as `to_dynany` for the same reason as in `to_dynany`.
|
||||||
let name = td.name.as_ref();
|
let name = td.name.as_ref();
|
||||||
macro_rules! check {
|
macro_rules! check {
|
||||||
($type_default:ty) => {
|
($type_default:ty) => {
|
||||||
if name == std::any::type_name::<$type_default>() { return Ok(value_edge(<$type_default>::default())); }
|
if name == std::any::type_name::<$type_default>() { return Ok(record_value_edge(<$type_default>::default())); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
for_each_type_default!(check);
|
for_each_type_default!(check);
|
||||||
@@ -304,33 +304,33 @@ macro_rules! tagged_value {
|
|||||||
}
|
}
|
||||||
Self::F64Array(values) => {
|
Self::F64Array(values) => {
|
||||||
let list: List<f64> = values.into_iter().map(core_types::list::Item::new_from_element).collect();
|
let list: List<f64> = values.into_iter().map(core_types::list::Item::new_from_element).collect();
|
||||||
Ok(value_edge(list))
|
Ok(record_value_edge(list))
|
||||||
}
|
}
|
||||||
Self::Color(color) => {
|
Self::Color(color) => {
|
||||||
let list: List<Color> = color.into_iter().map(core_types::list::Item::new_from_element).collect();
|
let list: List<Color> = color.into_iter().map(core_types::list::Item::new_from_element).collect();
|
||||||
Ok(value_edge(list))
|
Ok(record_value_edge(list))
|
||||||
}
|
}
|
||||||
Self::Gradient(stops) => Ok(value_edge(List::<GradientStops>::new_from_element(stops))),
|
Self::Gradient(stops) => Ok(record_value_edge(List::<GradientStops>::new_from_element(stops))),
|
||||||
Self::BrushStrokes(strokes) => {
|
Self::BrushStrokes(strokes) => {
|
||||||
let list: List<BrushStroke> = strokes.into_iter().map(core_types::list::Item::new_from_element).collect();
|
let list: List<BrushStroke> = strokes.into_iter().map(core_types::list::Item::new_from_element).collect();
|
||||||
Ok(value_edge(list))
|
Ok(record_value_edge(list))
|
||||||
}
|
}
|
||||||
// =======================
|
// =======================
|
||||||
// AUTO-GENERATED VARIANTS
|
// AUTO-GENERATED VARIANTS
|
||||||
// =======================
|
// =======================
|
||||||
$( Self::$identifier(x) => Ok(value_edge(x)), )*
|
$( Self::$identifier(x) => Ok(record_value_edge(x)), )*
|
||||||
// =======================
|
// =======================
|
||||||
// NON-SERIALIZED VARIANTS
|
// NON-SERIALIZED VARIANTS
|
||||||
// =======================
|
// =======================
|
||||||
Self::RenderOutput(x) => Ok(value_edge(x)),
|
Self::RenderOutput(x) => Ok(record_value_edge(x)),
|
||||||
Self::NodeIdPath(path) => {
|
Self::NodeIdPath(path) => {
|
||||||
let list: List<NodeId> = path.into_iter().map(core_types::list::Item::new_from_element).collect();
|
let list: List<NodeId> = path.into_iter().map(core_types::list::Item::new_from_element).collect();
|
||||||
Ok(value_edge(list))
|
Ok(record_value_edge(list))
|
||||||
}
|
}
|
||||||
Self::DocumentNode(node) => Ok(value_edge(node)),
|
Self::DocumentNode(node) => Ok(record_value_edge(node)),
|
||||||
Self::ContextModification(modification) => Ok(value_edge(modification)),
|
Self::ContextModification(modification) => Ok(record_value_edge(modification)),
|
||||||
Self::EditorApi(x) => Ok(value_edge(x)),
|
Self::EditorApi(x) => Ok(record_value_edge(x)),
|
||||||
Self::ResourceHash(x) => Ok(value_edge(x)),
|
Self::ResourceHash(x) => Ok(record_value_edge(x)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -752,10 +752,10 @@ impl TypingContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let inputs = match node.construction_args {
|
let inputs = match node.construction_args {
|
||||||
// If the node has a value input we can infer the return type from it
|
// A value node is a native record source, so it types as a record
|
||||||
|
// of its value.
|
||||||
ConstructionArgs::Value(ref v) => {
|
ConstructionArgs::Value(ref v) => {
|
||||||
// TODO: This should return a reference to the value
|
let types = NodeIOTypes::new(concrete!(Context), Type::Record(Box::new(v.ty())), vec![]);
|
||||||
let types = NodeIOTypes::new(concrete!(Context), v.ty(), vec![]);
|
|
||||||
self.inferred.insert(node_id, types.clone());
|
self.inferred.insert(node_id, types.clone());
|
||||||
return Ok(types);
|
return Ok(types);
|
||||||
}
|
}
|
||||||
@@ -1327,9 +1327,9 @@ mod ref_adapter_test {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
ProtoNodeIdentifier::new("graphene_core::memo::LendNode"),
|
ProtoNodeIdentifier::new("core_types::record::RecordExtractLendNode"),
|
||||||
vec![RegistryEntry {
|
vec![RegistryEntry {
|
||||||
io: NodeIOTypes::new(concrete!(Context), ref_type::<String>(), vec![edge_type::<String>()]),
|
io: NodeIOTypes::new(concrete!(Context), ref_type::<String>(), vec![record_edge_type::<String>()]),
|
||||||
constructor: unused,
|
constructor: unused,
|
||||||
}],
|
}],
|
||||||
),
|
),
|
||||||
@@ -1366,7 +1366,7 @@ mod ref_adapter_test {
|
|||||||
|
|
||||||
assert_eq!(network.nodes.len(), 3);
|
assert_eq!(network.nodes.len(), 3);
|
||||||
let (adapter_id, adapter) = &network.nodes[1];
|
let (adapter_id, adapter) = &network.nodes[1];
|
||||||
assert_eq!(adapter.identifier.as_str(), "graphene_core::memo::LendNode");
|
assert_eq!(adapter.identifier.as_str(), "core_types::record::RecordExtractLendNode");
|
||||||
assert_eq!(adapter.unwrap_construction_nodes(), vec![NodeId(0)]);
|
assert_eq!(adapter.unwrap_construction_nodes(), vec![NodeId(0)]);
|
||||||
assert_eq!(network.nodes[2].1.unwrap_construction_nodes(), vec![*adapter_id]);
|
assert_eq!(network.nodes[2].1.unwrap_construction_nodes(), vec![*adapter_id]);
|
||||||
assert_eq!(typing.type_of(*adapter_id).unwrap().return_value, ref_type::<String>());
|
assert_eq!(typing.type_of(*adapter_id).unwrap().return_value, ref_type::<String>());
|
||||||
@@ -1392,7 +1392,7 @@ mod ref_adapter_test {
|
|||||||
let adapters: Vec<NodeId> = network
|
let adapters: Vec<NodeId> = network
|
||||||
.nodes
|
.nodes
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, node)| node.identifier.as_str() == "graphene_core::memo::LendNode")
|
.filter(|(_, node)| node.identifier.as_str() == "core_types::record::RecordExtractLendNode")
|
||||||
.map(|(id, _)| *id)
|
.map(|(id, _)| *id)
|
||||||
.collect();
|
.collect();
|
||||||
let [adapter_id] = adapters.as_slice() else {
|
let [adapter_id] = adapters.as_slice() else {
|
||||||
|
|||||||
@@ -555,14 +555,18 @@ mod test {
|
|||||||
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32).into()), vec![]);
|
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32).into()), vec![]);
|
||||||
let context = TypingContext::default();
|
let context = TypingContext::default();
|
||||||
tree.push_node(NodeId(0), val_1_protonode, &context).unwrap();
|
tree.push_node(NodeId(0), val_1_protonode, &context).unwrap();
|
||||||
let _node = tree.get(NodeId(0)).unwrap();
|
let handle = tree.get(NodeId(0)).unwrap();
|
||||||
|
let layout = handle.layout().unwrap().clone();
|
||||||
|
let edge = handle.duplicate().downcast_record::<u32>().unwrap();
|
||||||
|
|
||||||
let arena = Arena::new(64).unwrap();
|
let arena = Arena::new(64).unwrap();
|
||||||
let generations = [];
|
let generations = [];
|
||||||
let scope = EvalScope::new(None, None, None, &generations, &arena);
|
let scope = EvalScope::new(None, None, None, &generations, &arena);
|
||||||
let ctx = ContextImpl::root(&scope);
|
let ctx = ContextImpl::root(&scope);
|
||||||
let result: Option<GPoll<u32>> = tree.eval(NodeId(0), &ctx);
|
let GPoll::Final(value) = edge.eval(&ctx) else {
|
||||||
assert_eq!(result, Some(GPoll::Final(2)));
|
panic!("expected a final record");
|
||||||
|
};
|
||||||
|
assert_eq!(unsafe { core_types::record::read_element::<u32>(layout.rec(&value)) }, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn proto_node(identifier: &'static str, args: Vec<NodeId>) -> ProtoNode {
|
fn proto_node(identifier: &'static str, args: Vec<NodeId>) -> ProtoNode {
|
||||||
|
|||||||
@@ -13,6 +13,13 @@ pub fn value_edge<T: Clone + crate::WasmNotSend + crate::WasmNotSync + 'static>(
|
|||||||
crate::registry::EdgeHandle::new(std::sync::Arc::new(ClonedNode(value)) as std::sync::Arc<crate::registry::ErasedNode<T>>)
|
crate::registry::EdgeHandle::new(std::sync::Arc::new(ClonedNode(value)) as std::sync::Arc<crate::registry::ErasedNode<T>>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The native record edge of a constant: the element lifts onto the record
|
||||||
|
/// wire per evaluation, so value sources need no spliced adapter.
|
||||||
|
pub fn record_value_edge<T: Clone + Send + Sync + 'static>(value: T) -> crate::registry::EdgeHandle {
|
||||||
|
let node = crate::record::RecordLift::<T, _>::new(ClonedNode(value));
|
||||||
|
crate::registry::EdgeHandle::new_record::<T>(std::sync::Arc::new(node) as std::sync::Arc<crate::registry::ErasedRecordNode>)
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Clone> ClonedNode<T> {
|
impl<T: Clone> ClonedNode<T> {
|
||||||
pub const fn new(value: T) -> ClonedNode<T> {
|
pub const fn new(value: T) -> ClonedNode<T> {
|
||||||
ClonedNode(value)
|
ClonedNode(value)
|
||||||
|
|||||||
Reference in New Issue
Block a user