mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Retire the lend machinery and flip the clone node onto record wires
This commit is contained in:
@@ -930,12 +930,8 @@ fn ref_adapter(proposed: &Type, wanted: &Type) -> Option<ProtoNodeIdentifier> {
|
||||
return None;
|
||||
};
|
||||
match (proposed_output.as_ref(), wanted_output.as_ref()) {
|
||||
(Type::Ref(inner), wanted_output @ Type::Concrete(_)) if valid_type(inner, wanted_output) => Some(ProtoNodeIdentifier::new("graphene_core::debug::CloneNode")),
|
||||
(proposed_output @ Type::Concrete(_), Type::Ref(inner)) if valid_type(proposed_output, inner) => Some(ProtoNodeIdentifier::new("graphene_core::memo::LendNode")),
|
||||
(Type::Record(inner), wanted_output @ Type::Concrete(_)) if valid_type(inner, wanted_output) => Some(ProtoNodeIdentifier::new("core_types::record::RecordExtractNode")),
|
||||
(proposed_output @ Type::Concrete(_), Type::Record(inner)) if valid_type(proposed_output, inner) => Some(ProtoNodeIdentifier::new("core_types::record::RecordLiftNode")),
|
||||
(Type::Ref(inner), Type::Record(wanted_inner)) if valid_type(inner, wanted_inner) => Some(ProtoNodeIdentifier::new("core_types::record::RecordLiftLendNode")),
|
||||
(Type::Record(inner), Type::Ref(wanted_inner)) if valid_type(inner, wanted_inner) => Some(ProtoNodeIdentifier::new("core_types::record::RecordExtractLendNode")),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -1299,7 +1295,7 @@ mod test {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod ref_adapter_test {
|
||||
mod adapter_splice_test {
|
||||
use super::*;
|
||||
|
||||
fn adapter_lookup() -> &'static HashMap<ProtoNodeIdentifier, Vec<RegistryEntry>> {
|
||||
@@ -1307,29 +1303,29 @@ mod ref_adapter_test {
|
||||
let unused: NodeConstructor = |_| Err(ConstructionError::Arity { expected: 0, got: 0 });
|
||||
[
|
||||
(
|
||||
ProtoNodeIdentifier::new("wants_ref"),
|
||||
ProtoNodeIdentifier::new("wants_owned"),
|
||||
vec![RegistryEntry {
|
||||
io: NodeIOTypes::new(concrete!(Context), concrete!(String), vec![lend_edge_type::<String>()]),
|
||||
io: NodeIOTypes::new(concrete!(Context), concrete!(String), vec![edge_type::<String>()]),
|
||||
constructor: unused,
|
||||
}],
|
||||
),
|
||||
(
|
||||
ProtoNodeIdentifier::new("wants_ref_ambiguously"),
|
||||
ProtoNodeIdentifier::new("wants_owned_ambiguously"),
|
||||
vec![
|
||||
RegistryEntry {
|
||||
io: NodeIOTypes::new(concrete!(Context), concrete!(String), vec![lend_edge_type::<String>()]),
|
||||
io: NodeIOTypes::new(concrete!(Context), concrete!(String), vec![edge_type::<String>()]),
|
||||
constructor: unused,
|
||||
},
|
||||
RegistryEntry {
|
||||
io: NodeIOTypes::new(concrete!(Context), concrete!(f64), vec![lend_edge_type::<String>()]),
|
||||
io: NodeIOTypes::new(concrete!(Context), concrete!(f64), vec![edge_type::<String>()]),
|
||||
constructor: unused,
|
||||
},
|
||||
],
|
||||
),
|
||||
(
|
||||
ProtoNodeIdentifier::new("core_types::record::RecordExtractLendNode"),
|
||||
ProtoNodeIdentifier::new("core_types::record::RecordExtractNode"),
|
||||
vec![RegistryEntry {
|
||||
io: NodeIOTypes::new(concrete!(Context), ref_type::<String>(), vec![record_edge_type::<String>()]),
|
||||
io: NodeIOTypes::new(concrete!(Context), concrete!(String), vec![record_edge_type::<String>()]),
|
||||
constructor: unused,
|
||||
}],
|
||||
),
|
||||
@@ -1341,7 +1337,7 @@ mod ref_adapter_test {
|
||||
}
|
||||
|
||||
fn string_value() -> ProtoNode {
|
||||
ProtoNode::value(ConstructionArgs::Value(TaggedValue::String("lent".to_string()).into()), vec![])
|
||||
ProtoNode::value(ConstructionArgs::Value(TaggedValue::String("landed".to_string()).into()), vec![])
|
||||
}
|
||||
|
||||
fn consumer(identifier: &str, producer: NodeId) -> ProtoNode {
|
||||
@@ -1354,11 +1350,11 @@ mod ref_adapter_test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_ref_only_mismatch_splices_the_lend_adapter() {
|
||||
fn a_record_only_mismatch_splices_the_extract_adapter() {
|
||||
let mut network = ProtoNetwork {
|
||||
inputs: vec![],
|
||||
output: NodeId(1),
|
||||
nodes: vec![(NodeId(0), string_value()), (NodeId(1), consumer("wants_ref", NodeId(0)))],
|
||||
nodes: vec![(NodeId(0), string_value()), (NodeId(1), consumer("wants_owned", NodeId(0)))],
|
||||
};
|
||||
|
||||
let mut typing = TypingContext::new(adapter_lookup());
|
||||
@@ -1366,10 +1362,10 @@ mod ref_adapter_test {
|
||||
|
||||
assert_eq!(network.nodes.len(), 3);
|
||||
let (adapter_id, adapter) = &network.nodes[1];
|
||||
assert_eq!(adapter.identifier.as_str(), "core_types::record::RecordExtractLendNode");
|
||||
assert_eq!(adapter.identifier.as_str(), "core_types::record::RecordExtractNode");
|
||||
assert_eq!(adapter.unwrap_construction_nodes(), vec![NodeId(0)]);
|
||||
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, concrete!(String));
|
||||
assert_eq!(typing.type_of(NodeId(1)).unwrap().return_value, concrete!(String));
|
||||
}
|
||||
|
||||
@@ -1380,8 +1376,8 @@ mod ref_adapter_test {
|
||||
output: NodeId(2),
|
||||
nodes: vec![
|
||||
(NodeId(0), string_value()),
|
||||
(NodeId(1), consumer("wants_ref", NodeId(0))),
|
||||
(NodeId(2), consumer("wants_ref", NodeId(0))),
|
||||
(NodeId(1), consumer("wants_owned", NodeId(0))),
|
||||
(NodeId(2), consumer("wants_owned", NodeId(0))),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1392,7 +1388,7 @@ mod ref_adapter_test {
|
||||
let adapters: Vec<NodeId> = network
|
||||
.nodes
|
||||
.iter()
|
||||
.filter(|(_, node)| node.identifier.as_str() == "core_types::record::RecordExtractLendNode")
|
||||
.filter(|(_, node)| node.identifier.as_str() == "core_types::record::RecordExtractNode")
|
||||
.map(|(id, _)| *id)
|
||||
.collect();
|
||||
let [adapter_id] = adapters.as_slice() else {
|
||||
@@ -1401,18 +1397,18 @@ mod ref_adapter_test {
|
||||
let consumers: Vec<Vec<NodeId>> = network
|
||||
.nodes
|
||||
.iter()
|
||||
.filter(|(_, node)| node.identifier.as_str() == "wants_ref")
|
||||
.filter(|(_, node)| node.identifier.as_str() == "wants_owned")
|
||||
.map(|(_, node)| node.unwrap_construction_nodes())
|
||||
.collect();
|
||||
assert_eq!(consumers, vec![vec![*adapter_id], vec![*adapter_id]]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_ambiguous_ref_mismatch_stays_an_error() {
|
||||
fn an_ambiguous_record_mismatch_stays_an_error() {
|
||||
let mut network = ProtoNetwork {
|
||||
inputs: vec![],
|
||||
output: NodeId(1),
|
||||
nodes: vec![(NodeId(0), string_value()), (NodeId(1), consumer("wants_ref_ambiguously", NodeId(0)))],
|
||||
nodes: vec![(NodeId(0), string_value()), (NodeId(1), consumer("wants_owned_ambiguously", NodeId(0)))],
|
||||
};
|
||||
|
||||
let mut typing = TypingContext::new(adapter_lookup());
|
||||
|
||||
@@ -582,18 +582,25 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_lend_adapter_is_spliced_between_a_value_and_a_ref_consumer() {
|
||||
fn the_clone_node_clones_the_element_out_of_its_record_wire() {
|
||||
let raster_list = TaggedValue::from_type(&core_types::concrete!(graphene_std::list::List<graphene_std::raster_types::Raster<graphene_std::raster_types::CPU>>)).unwrap();
|
||||
let network = ProtoNetwork {
|
||||
inputs: vec![],
|
||||
output: NodeId(1),
|
||||
output: NodeId(2),
|
||||
nodes: vec![
|
||||
(NodeId(0), string_value("lent")),
|
||||
(NodeId(0), ProtoNode::value(ConstructionArgs::Value(raster_list.into()), vec![])),
|
||||
(NodeId(1), proto_node("graphene_core::debug::CloneNode", vec![NodeId(0)])),
|
||||
(NodeId(2), proto_node("core_types::record::RecordExtractNode", vec![NodeId(1)])),
|
||||
],
|
||||
};
|
||||
|
||||
let executor = DynamicExecutor::new(network).unwrap();
|
||||
assert_eq!((&executor).execute(()).unwrap(), GPoll::Final(TaggedValue::String("lent".to_string())));
|
||||
let arena = Arena::new(1 << 20).unwrap();
|
||||
let generations = [];
|
||||
let scope = EvalScope::new(None, None, None, &generations, &arena);
|
||||
let ctx = ContextImpl::root(&scope);
|
||||
let result: Option<GPoll<graphene_std::list::List<graphene_std::raster_types::Raster<graphene_std::raster_types::CPU>>>> = executor.tree().eval(NodeId(2), &ctx);
|
||||
assert!(matches!(result, Some(GPoll::Final(_))), "the flipped clone must evaluate over record wires, got {result:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -756,7 +763,7 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_clone_out_adapter_is_spliced_between_a_lending_producer_and_an_owned_consumer() {
|
||||
fn stacked_frame_memos_replay_over_record_wires() {
|
||||
let network = ProtoNetwork {
|
||||
inputs: vec![],
|
||||
output: NodeId(3),
|
||||
@@ -764,7 +771,7 @@ mod test {
|
||||
(NodeId(0), string_value("memoized")),
|
||||
(NodeId(1), proto_node("graphene_core::memo::FrameMemoNode", vec![NodeId(0)])),
|
||||
(NodeId(2), proto_node("graphene_core::memo::FrameMemoNode", vec![NodeId(1)])),
|
||||
(NodeId(3), proto_node("graphene_core::debug::CloneNode", vec![NodeId(2)])),
|
||||
(NodeId(3), proto_node("core_types::record::RecordExtractNode", vec![NodeId(2)])),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -773,7 +780,7 @@ mod test {
|
||||
assert_eq!(
|
||||
(&executor).execute(()).unwrap(),
|
||||
GPoll::Final(TaggedValue::String("memoized".to_string())),
|
||||
"the frame memo lend path must replay across evaluations"
|
||||
"the frame memo must replay across evaluations"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
use graph_craft::application_io::PlatformEditorApi;
|
||||
use graph_craft::document::DocumentNode;
|
||||
use graph_craft::document::value::RenderOutput;
|
||||
use graphene_std::brush::brush_stroke::BrushStroke;
|
||||
use graphene_std::gradient::GradientStops;
|
||||
use graphene_std::list::{AttributeDyn, AttributeValueDyn, List, ListDyn};
|
||||
#[cfg(target_family = "wasm")]
|
||||
@@ -12,14 +10,14 @@ use graphene_std::raster::GPU;
|
||||
use graphene_std::raster::color::Color;
|
||||
use graphene_std::raster::*;
|
||||
use graphene_std::raster::{CPU, Raster};
|
||||
use graphene_std::registry::{ConstructionError, EdgeHandle, ErasedLendNode, ErasedNode, NodeIOTypes, RegistryEntry, lend_edge_type, ref_type};
|
||||
use graphene_std::registry::{ConstructionError, EdgeHandle, ErasedNode, NodeIOTypes, RegistryEntry};
|
||||
use graphene_std::render_node::RenderIntermediate;
|
||||
use graphene_std::runtime::RuntimeHandle;
|
||||
use graphene_std::transform::Footprint;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::{Artboard, Context, Graphic, ProtoNodeIdentifier, SourceId, concrete, fn_type};
|
||||
use node_registry_macros::{clone_node, convert_node, into_node, lend_node, record_extract_node, record_lift_node};
|
||||
use node_registry_macros::{convert_node, into_node, record_extract_node, record_lift_node};
|
||||
use std::collections::HashMap;
|
||||
#[cfg(feature = "gpu")]
|
||||
use wgpu_executor::WgpuExecutorHandle;
|
||||
@@ -114,58 +112,9 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, Vec<RegistryEntry>> {
|
||||
// ============
|
||||
// REF ADAPTERS
|
||||
// ============
|
||||
lend_node!(()),
|
||||
clone_node!(()),
|
||||
lend_node!(RuntimeHandle),
|
||||
clone_node!(RuntimeHandle),
|
||||
lend_node!(SourceId),
|
||||
clone_node!(SourceId),
|
||||
lend_node!(bool),
|
||||
clone_node!(bool),
|
||||
lend_node!(List<Artboard>),
|
||||
clone_node!(List<Artboard>),
|
||||
lend_node!(List<Graphic>),
|
||||
clone_node!(List<Graphic>),
|
||||
lend_node!(List<Vector>),
|
||||
clone_node!(List<Vector>),
|
||||
lend_node!(List<Raster<CPU>>),
|
||||
clone_node!(List<Raster<CPU>>),
|
||||
lend_node!(List<Color>),
|
||||
clone_node!(List<Color>),
|
||||
lend_node!(Image<Color>),
|
||||
clone_node!(Image<Color>),
|
||||
lend_node!(List<GradientStops>),
|
||||
clone_node!(List<GradientStops>),
|
||||
lend_node!(List<String>),
|
||||
clone_node!(List<String>),
|
||||
lend_node!(List<NodeId>),
|
||||
clone_node!(List<NodeId>),
|
||||
lend_node!(List<f64>),
|
||||
clone_node!(List<f64>),
|
||||
lend_node!(List<u8>),
|
||||
clone_node!(List<u8>),
|
||||
lend_node!(List<bool>),
|
||||
clone_node!(List<bool>),
|
||||
lend_node!(List<DAffine2>),
|
||||
clone_node!(List<DAffine2>),
|
||||
lend_node!(List<BlendMode>),
|
||||
clone_node!(List<BlendMode>),
|
||||
lend_node!(List<graphene_std::vector::style::GradientType>),
|
||||
clone_node!(List<graphene_std::vector::style::GradientType>),
|
||||
lend_node!(List<graphene_std::vector::style::GradientSpreadMethod>),
|
||||
clone_node!(List<graphene_std::vector::style::GradientSpreadMethod>),
|
||||
lend_node!(AttributeDyn),
|
||||
clone_node!(AttributeDyn),
|
||||
lend_node!(AttributeValueDyn),
|
||||
clone_node!(AttributeValueDyn),
|
||||
lend_node!(ListDyn),
|
||||
clone_node!(ListDyn),
|
||||
#[cfg(target_family = "wasm")]
|
||||
lend_node!(CanvasHandle),
|
||||
#[cfg(target_family = "wasm")]
|
||||
clone_node!(CanvasHandle),
|
||||
#[cfg(target_family = "wasm")]
|
||||
lend_node!(f64),
|
||||
record_lift_node!(f64),
|
||||
record_extract_node!(f64),
|
||||
record_lift_node!(()),
|
||||
@@ -252,129 +201,6 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, Vec<RegistryEntry>> {
|
||||
record_lift_node!(wgpu_executor::WgpuPipelineCache),
|
||||
#[cfg(feature = "gpu")]
|
||||
record_extract_node!(wgpu_executor::WgpuPipelineCache),
|
||||
lend_node!(f32),
|
||||
clone_node!(f32),
|
||||
lend_node!(u32),
|
||||
clone_node!(u32),
|
||||
lend_node!(u64),
|
||||
clone_node!(u64),
|
||||
lend_node!(DVec2),
|
||||
clone_node!(DVec2),
|
||||
lend_node!(String),
|
||||
clone_node!(String),
|
||||
lend_node!(DAffine2),
|
||||
clone_node!(DAffine2),
|
||||
lend_node!(Footprint),
|
||||
clone_node!(Footprint),
|
||||
lend_node!(RenderOutput),
|
||||
clone_node!(RenderOutput),
|
||||
lend_node!(std::sync::Arc<PlatformEditorApi>),
|
||||
clone_node!(std::sync::Arc<PlatformEditorApi>),
|
||||
#[cfg(feature = "gpu")]
|
||||
lend_node!(List<Raster<GPU>>),
|
||||
#[cfg(feature = "gpu")]
|
||||
clone_node!(List<Raster<GPU>>),
|
||||
#[cfg(feature = "gpu")]
|
||||
lend_node!(Option<f64>),
|
||||
clone_node!(Option<f64>),
|
||||
lend_node!(Option<Color>),
|
||||
clone_node!(Option<Color>),
|
||||
lend_node!(Graphic),
|
||||
clone_node!(Graphic),
|
||||
lend_node!(glam::f32::Vec2),
|
||||
clone_node!(glam::f32::Vec2),
|
||||
lend_node!(glam::f32::Affine2),
|
||||
clone_node!(glam::f32::Affine2),
|
||||
lend_node!(graphene_std::vector::style::Stroke),
|
||||
clone_node!(graphene_std::vector::style::Stroke),
|
||||
lend_node!(graphene_std::text::Font),
|
||||
clone_node!(graphene_std::text::Font),
|
||||
lend_node!(List<BrushStroke>),
|
||||
clone_node!(List<BrushStroke>),
|
||||
lend_node!(DocumentNode),
|
||||
clone_node!(DocumentNode),
|
||||
lend_node!(graphene_std::ContextModification),
|
||||
clone_node!(graphene_std::ContextModification),
|
||||
lend_node!(graphene_std::transform::Footprint),
|
||||
clone_node!(graphene_std::transform::Footprint),
|
||||
lend_node!(Box<graphene_std::vector::VectorModification>),
|
||||
clone_node!(Box<graphene_std::vector::VectorModification>),
|
||||
lend_node!(graphene_std::blending::BlendMode),
|
||||
clone_node!(graphene_std::blending::BlendMode),
|
||||
lend_node!(graphene_std::raster::LuminanceCalculation),
|
||||
clone_node!(graphene_std::raster::LuminanceCalculation),
|
||||
lend_node!(graphene_std::vector::QRCodeErrorCorrectionLevel),
|
||||
clone_node!(graphene_std::vector::QRCodeErrorCorrectionLevel),
|
||||
lend_node!(graphene_std::extract_xy::XY),
|
||||
clone_node!(graphene_std::extract_xy::XY),
|
||||
lend_node!(graphene_std::text_nodes::StringCapitalization),
|
||||
clone_node!(graphene_std::text_nodes::StringCapitalization),
|
||||
lend_node!(graphene_std::raster::RedGreenBlue),
|
||||
clone_node!(graphene_std::raster::RedGreenBlue),
|
||||
lend_node!(graphene_std::raster::RedGreenBlueAlpha),
|
||||
clone_node!(graphene_std::raster::RedGreenBlueAlpha),
|
||||
lend_node!(graphene_std::animation::RealTimeMode),
|
||||
clone_node!(graphene_std::animation::RealTimeMode),
|
||||
lend_node!(graphene_std::raster::NoiseType),
|
||||
clone_node!(graphene_std::raster::NoiseType),
|
||||
lend_node!(graphene_std::raster::FractalType),
|
||||
clone_node!(graphene_std::raster::FractalType),
|
||||
lend_node!(graphene_std::raster::CellularDistanceFunction),
|
||||
clone_node!(graphene_std::raster::CellularDistanceFunction),
|
||||
lend_node!(graphene_std::raster::CellularReturnType),
|
||||
clone_node!(graphene_std::raster::CellularReturnType),
|
||||
lend_node!(graphene_std::raster::DomainWarpType),
|
||||
clone_node!(graphene_std::raster::DomainWarpType),
|
||||
lend_node!(graphene_std::raster::RelativeAbsolute),
|
||||
clone_node!(graphene_std::raster::RelativeAbsolute),
|
||||
lend_node!(graphene_std::raster::SelectiveColorChoice),
|
||||
clone_node!(graphene_std::raster::SelectiveColorChoice),
|
||||
lend_node!(graphene_std::vector::misc::GridType),
|
||||
clone_node!(graphene_std::vector::misc::GridType),
|
||||
lend_node!(graphene_std::vector::misc::ArcType),
|
||||
clone_node!(graphene_std::vector::misc::ArcType),
|
||||
lend_node!(graphene_std::vector::misc::RowsOrColumns),
|
||||
clone_node!(graphene_std::vector::misc::RowsOrColumns),
|
||||
lend_node!(graphene_std::vector::misc::MergeByDistanceAlgorithm),
|
||||
clone_node!(graphene_std::vector::misc::MergeByDistanceAlgorithm),
|
||||
lend_node!(graphene_std::vector::misc::ExtrudeJoiningAlgorithm),
|
||||
clone_node!(graphene_std::vector::misc::ExtrudeJoiningAlgorithm),
|
||||
lend_node!(graphene_std::vector::misc::PointSpacingType),
|
||||
clone_node!(graphene_std::vector::misc::PointSpacingType),
|
||||
lend_node!(graphene_std::vector::style::StrokeCap),
|
||||
clone_node!(graphene_std::vector::style::StrokeCap),
|
||||
lend_node!(graphene_std::vector::style::StrokeJoin),
|
||||
clone_node!(graphene_std::vector::style::StrokeJoin),
|
||||
lend_node!(graphene_std::vector::style::StrokeAlign),
|
||||
clone_node!(graphene_std::vector::style::StrokeAlign),
|
||||
lend_node!(graphene_std::vector::style::PaintOrder),
|
||||
clone_node!(graphene_std::vector::style::PaintOrder),
|
||||
lend_node!(graphene_std::vector::style::GradientType),
|
||||
clone_node!(graphene_std::vector::style::GradientType),
|
||||
lend_node!(graphene_std::vector::style::GradientSpreadMethod),
|
||||
clone_node!(graphene_std::vector::style::GradientSpreadMethod),
|
||||
lend_node!(Option<DAffine2>),
|
||||
clone_node!(Option<DAffine2>),
|
||||
lend_node!(graphene_std::transform::ReferencePoint),
|
||||
clone_node!(graphene_std::transform::ReferencePoint),
|
||||
lend_node!(graphene_std::vector::misc::CentroidType),
|
||||
clone_node!(graphene_std::vector::misc::CentroidType),
|
||||
lend_node!(graphene_std::vector::misc::BooleanOperation),
|
||||
clone_node!(graphene_std::vector::misc::BooleanOperation),
|
||||
lend_node!(graphene_std::text::TextAlign),
|
||||
clone_node!(graphene_std::text::TextAlign),
|
||||
lend_node!(graphene_std::transform::ScaleType),
|
||||
clone_node!(graphene_std::transform::ScaleType),
|
||||
lend_node!(graphene_std::vector::misc::InterpolationDistribution),
|
||||
clone_node!(graphene_std::vector::misc::InterpolationDistribution),
|
||||
lend_node!(RenderIntermediate),
|
||||
clone_node!(RenderIntermediate),
|
||||
lend_node!(wgpu_executor::WgpuExecutorHandle),
|
||||
clone_node!(wgpu_executor::WgpuExecutorHandle),
|
||||
lend_node!(Option<wgpu_executor::WgpuExecutorHandle>),
|
||||
clone_node!(Option<wgpu_executor::WgpuExecutorHandle>),
|
||||
lend_node!(wgpu_executor::WgpuPipelineCache),
|
||||
clone_node!(wgpu_executor::WgpuPipelineCache),
|
||||
];
|
||||
// =============
|
||||
// CONVERT NODES
|
||||
@@ -545,25 +371,6 @@ mod node_registry_macros {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! lend_node {
|
||||
($type:ty) => {
|
||||
(
|
||||
ProtoNodeIdentifier::new("graphene_core::memo::LendNode"),
|
||||
RegistryEntry {
|
||||
io: NodeIOTypes::new(concrete!(Context), ref_type::<$type>(), vec![fn_type!(Context, $type)]),
|
||||
constructor: |inputs| {
|
||||
if inputs.len() != 1 {
|
||||
return Err(ConstructionError::Arity { expected: 1, got: inputs.len() });
|
||||
}
|
||||
let mut inputs = inputs.into_iter();
|
||||
let node = graphene_core::memo::LendNode::new(inputs.next().unwrap().downcast::<$type>()?);
|
||||
Ok(EdgeHandle::new_ref(std::sync::Arc::new(node) as std::sync::Arc<ErasedLendNode<$type>>))
|
||||
},
|
||||
},
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! record_lift_node {
|
||||
($type:ty) => {
|
||||
(
|
||||
@@ -604,29 +411,8 @@ mod node_registry_macros {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! clone_node {
|
||||
($type:ty) => {
|
||||
(
|
||||
ProtoNodeIdentifier::new("graphene_core::debug::CloneNode"),
|
||||
RegistryEntry {
|
||||
io: NodeIOTypes::new(concrete!(Context), concrete!($type), vec![lend_edge_type::<$type>()]),
|
||||
constructor: |inputs| {
|
||||
if inputs.len() != 1 {
|
||||
return Err(ConstructionError::Arity { expected: 1, got: inputs.len() });
|
||||
}
|
||||
let mut inputs = inputs.into_iter();
|
||||
let node = graphene_core::debug::CloneNode::new(inputs.next().unwrap().downcast_lend::<$type>()?);
|
||||
Ok(EdgeHandle::new(std::sync::Arc::new(node) as std::sync::Arc<ErasedNode<$type>>))
|
||||
},
|
||||
},
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use clone_node;
|
||||
pub(crate) use convert_node;
|
||||
pub(crate) use into_node;
|
||||
pub(crate) use lend_node;
|
||||
pub(crate) use record_extract_node;
|
||||
pub(crate) use record_lift_node;
|
||||
}
|
||||
|
||||
@@ -905,111 +905,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Lifts a lending producer onto a record wire: a parked element carries the
|
||||
/// lent reference directly, a byte-carried one copies out of the borrow.
|
||||
pub struct RecordLiftLend<El, N> {
|
||||
edge: N,
|
||||
layout: Layout,
|
||||
_marker: std::marker::PhantomData<fn() -> El>,
|
||||
}
|
||||
|
||||
impl<El: Clone + Send + Sync + 'static, N> RecordLiftLend<El, N> {
|
||||
pub fn new(edge: N) -> Self {
|
||||
Self {
|
||||
edge,
|
||||
layout: Layout::default().with_writes(0, element_write::<El>(), &[]),
|
||||
_marker: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'e, C, El, N> Node<C> for RecordLiftLend<El, N>
|
||||
where
|
||||
C: crate::context::ExtractArena<ArenaRef = &'e crate::arena::Arena>,
|
||||
El: Send + Sync + 'static,
|
||||
N: Node<C, Output = &'e El>,
|
||||
{
|
||||
type Output = RecordValue<'e>;
|
||||
|
||||
fn eval(&self, input: &C) -> GPoll<RecordValue<'e>> {
|
||||
let build = |element: &'e El| {
|
||||
let write = |dst: *mut u8| match element_parked::<El>() {
|
||||
true => unsafe { dst.cast::<&El>().write(element) },
|
||||
false => unsafe { std::ptr::copy_nonoverlapping((element as *const El).cast::<u8>(), dst, size_of::<El>()) },
|
||||
};
|
||||
if self.layout.is_inline() {
|
||||
let mut value = RecordValue::zeroed();
|
||||
write(value.as_mut_ptr());
|
||||
value
|
||||
} else {
|
||||
let dst = stack::push(self.layout.frame_bytes());
|
||||
write(dst);
|
||||
stack::pop(dst);
|
||||
RecordValue::spilled(unsafe { Rec::new(dst.cast_const()) })
|
||||
}
|
||||
};
|
||||
self.edge.eval(input).map(build)
|
||||
}
|
||||
|
||||
fn layout(&self) -> Option<&Layout> {
|
||||
Some(&self.layout)
|
||||
}
|
||||
}
|
||||
|
||||
/// Lends a record wire's element: a parked element lends its arena-backed
|
||||
/// reference directly, a byte-carried one parks a copy so the borrow
|
||||
/// outlives the record.
|
||||
pub struct RecordExtractLend<El, N> {
|
||||
edge: N,
|
||||
layout: Layout,
|
||||
_marker: std::marker::PhantomData<fn() -> El>,
|
||||
}
|
||||
|
||||
impl<El, N> RecordExtractLend<El, N> {
|
||||
pub fn new(edge: N, layout: &Layout) -> Self {
|
||||
Self {
|
||||
edge,
|
||||
layout: layout.clone(),
|
||||
_marker: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'e, C, El, N> Node<C> for RecordExtractLend<El, N>
|
||||
where
|
||||
C: crate::context::ExtractArena<ArenaRef = &'e crate::arena::Arena>,
|
||||
El: Clone + Send + Sync + 'static,
|
||||
N: Node<C, Output = RecordValue<'e>>,
|
||||
{
|
||||
type Output = &'e El;
|
||||
|
||||
fn eval(&self, input: &C) -> GPoll<&'e El> {
|
||||
let exhausted = || {
|
||||
GPoll::Error(Box::new(crate::gpoll::GraphError {
|
||||
kind: crate::gpoll::ErrorKind::ArenaExhausted,
|
||||
trace: Vec::new(),
|
||||
}))
|
||||
};
|
||||
let lend = |value: RecordValue<'e>| {
|
||||
let rec = self.layout.rec(&value);
|
||||
match element_parked::<El>() {
|
||||
true => Some(unsafe { borrow_element::<El>(rec) }),
|
||||
false => input.arena().alloc(unsafe { read_element::<El>(rec) }).map(|(parked, _)| parked),
|
||||
}
|
||||
};
|
||||
match self.edge.eval(input) {
|
||||
GPoll::Final(value) => lend(value).map_or_else(exhausted, GPoll::Final),
|
||||
GPoll::Partial(value) => lend(value).map_or_else(exhausted, GPoll::Partial),
|
||||
GPoll::Fallback(boxed) => {
|
||||
let (value, error) = *boxed;
|
||||
lend(value).map_or_else(exhausted, |element| GPoll::Fallback(Box::new((element, error))))
|
||||
}
|
||||
GPoll::Pending => GPoll::Pending,
|
||||
GPoll::Error(error) => GPoll::Error(error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts the element from a record wire for a plain consumer, cloning out
|
||||
/// of the parked reference when the element carries drop glue.
|
||||
pub struct RecordExtract<El, N> {
|
||||
|
||||
@@ -290,15 +290,13 @@ pub struct RegistryEntry {
|
||||
pub constructor: NodeConstructor,
|
||||
}
|
||||
|
||||
/// The four bridge rows of `T`: plain and lend producers onto record wires,
|
||||
/// record wires into plain and lend consumers. One set exists per wire type
|
||||
/// while the worlds coexist.
|
||||
pub fn record_bridge_rows<T: Clone + Send + Sync + 'static>() -> [(crate::ProtoNodeIdentifier, RegistryEntry); 4] {
|
||||
/// The bridge rows of `T`: a plain producer onto a record wire and a record
|
||||
/// wire into a plain consumer. One pair exists per wire type while the
|
||||
/// deferred plain classes (shader, batch) coexist with record wires.
|
||||
pub fn record_bridge_rows<T: Clone + Send + Sync + 'static>() -> [(crate::ProtoNodeIdentifier, RegistryEntry); 2] {
|
||||
[
|
||||
(crate::ProtoNodeIdentifier::new("core_types::record::RecordLiftNode"), record_lift_entry::<T>()),
|
||||
(crate::ProtoNodeIdentifier::new("core_types::record::RecordExtractNode"), record_extract_entry::<T>()),
|
||||
(crate::ProtoNodeIdentifier::new("core_types::record::RecordLiftLendNode"), record_lift_lend_entry::<T>()),
|
||||
(crate::ProtoNodeIdentifier::new("core_types::record::RecordExtractLendNode"), record_extract_lend_entry::<T>()),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -335,38 +333,6 @@ pub fn record_extract_entry<T: Clone + Send + Sync + 'static>() -> RegistryEntry
|
||||
}
|
||||
}
|
||||
|
||||
/// The lend-lift bridge row for `T`: a lending producer onto a record wire.
|
||||
pub fn record_lift_lend_entry<T: Clone + Send + Sync + 'static>() -> RegistryEntry {
|
||||
RegistryEntry {
|
||||
io: NodeIOTypes::new(concrete!(Context), record_type::<T>(), vec![lend_edge_type::<T>()]),
|
||||
constructor: |inputs| {
|
||||
if inputs.len() != 1 {
|
||||
return Err(ConstructionError::Arity { expected: 1, got: inputs.len() });
|
||||
}
|
||||
let mut inputs = inputs.into_iter();
|
||||
let node = crate::record::RecordLiftLend::<T, _>::new(inputs.next().unwrap().downcast_lend::<T>()?);
|
||||
Ok(EdgeHandle::new_record::<T>(std::sync::Arc::new(node) as std::sync::Arc<ErasedRecordNode>))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// The lend-extract bridge row for `T`: a record wire into a lend consumer.
|
||||
pub fn record_extract_lend_entry<T: Clone + Send + Sync + 'static>() -> RegistryEntry {
|
||||
RegistryEntry {
|
||||
io: NodeIOTypes::new(concrete!(Context), ref_type::<T>(), vec![record_edge_type::<T>()]),
|
||||
constructor: |inputs| {
|
||||
if inputs.len() != 1 {
|
||||
return Err(ConstructionError::Arity { expected: 1, got: inputs.len() });
|
||||
}
|
||||
let mut inputs = inputs.into_iter();
|
||||
let edge = inputs.next().unwrap();
|
||||
let layout = edge.layout().ok_or(ConstructionError::MissingLayout)?.clone();
|
||||
let node = crate::record::RecordExtractLend::<T, _>::new(edge.downcast_record::<T>()?, &layout);
|
||||
Ok(EdgeHandle::new_ref(std::sync::Arc::new(node) as std::sync::Arc<ErasedLendNode<T>>))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn construct(entry: &RegistryEntry, inputs: Vec<EdgeHandle>) -> Result<EdgeHandle, ConstructionError> {
|
||||
if inputs.len() != entry.io.inputs.len() {
|
||||
return Err(ConstructionError::Arity {
|
||||
|
||||
@@ -780,27 +780,6 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
]);
|
||||
}
|
||||
|
||||
let has_lend = parsed.fields.iter().any(|field| matches!(&field.ty, ParsedFieldType::Regular(RegularParsedField { lend: Some(_), .. })));
|
||||
let declared_arena_lifetime = ctx_param.and_then(|ctx_param| {
|
||||
ctx_param.bounds.iter().find_map(|bound| {
|
||||
let TypeParamBound::Trait(trait_bound) = bound else { return None };
|
||||
let segment = trait_bound.path.segments.last()?;
|
||||
if segment.ident != "ExtractArena" {
|
||||
return None;
|
||||
}
|
||||
let PathArguments::AngleBracketed(args) = &segment.arguments else { return None };
|
||||
match args.args.first() {
|
||||
Some(GenericArgument::Lifetime(lifetime)) => Some(lifetime.clone()),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
});
|
||||
let introduced_lend_lifetime = (has_lend && !flip && declared_arena_lifetime.is_none()).then(|| Lifetime::new("'__lend", proc_macro2::Span::call_site()));
|
||||
let lend_lifetime = declared_arena_lifetime.or_else(|| introduced_lend_lifetime.clone());
|
||||
if let Some(lifetime) = &introduced_lend_lifetime {
|
||||
ctx_bounds.push(quote!(#core_types::context::ExtractArena<ArenaRef = &#lifetime #core_types::arena::Arena>));
|
||||
}
|
||||
|
||||
let derives = ctx_param.is_some_and(|ctx_param| {
|
||||
ctx_param.bounds.iter().any(|bound| match bound {
|
||||
TypeParamBound::Trait(trait_bound) => trait_bound.path.segments.last().is_some_and(|segment| segment.ident == "DeriveCtx"),
|
||||
@@ -850,10 +829,6 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
generics.push(ctx_generic.clone());
|
||||
impl_generics.push(ctx_generic);
|
||||
}
|
||||
if let Some(lifetime) = &introduced_lend_lifetime {
|
||||
generics.insert(0, quote!(#lifetime));
|
||||
impl_generics.insert(0, quote!(#lifetime));
|
||||
}
|
||||
if routing.is_some() || record.is_some() || flip {
|
||||
impl_generics.insert(0, quote!('__record));
|
||||
}
|
||||
@@ -1024,10 +999,6 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
},
|
||||
false => quote!(#node_generic: #core_types::node::Node<#ctx_ident, Output = #record_value_ty>),
|
||||
},
|
||||
ParsedFieldType::Regular(RegularParsedField { ty, lend: Some(_), .. }) => {
|
||||
let lifetime = lend_lifetime.as_ref().expect("lend fields imply the lend lifetime");
|
||||
quote!(#node_generic: #core_types::node::Node<#ctx_ident, Output = &#lifetime #ty>)
|
||||
}
|
||||
ParsedFieldType::Regular(_) if record.is_some() && !skips_carrier && index == 0 => {
|
||||
quote!(#node_generic: #core_types::node::Node<#ctx_ident, Output = #record_value_ty>)
|
||||
}
|
||||
@@ -1051,16 +1022,7 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
}
|
||||
});
|
||||
|
||||
let mut lend_outlives: Vec<TokenStream2> = regular_fields
|
||||
.iter()
|
||||
.filter_map(|field| match &field.ty {
|
||||
ParsedFieldType::Regular(RegularParsedField { ty, lend: Some(_), .. }) if !flip => {
|
||||
let lifetime = lend_lifetime.as_ref().expect("lend fields imply the lend lifetime");
|
||||
Some(quote!(#ty: #lifetime))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let mut lend_outlives: Vec<TokenStream2> = Vec::new();
|
||||
if let Type::Reference(reference) = &trait_output
|
||||
&& let Some(lifetime) = &reference.lifetime
|
||||
{
|
||||
@@ -1175,6 +1137,9 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
ParsedFieldType::Node(_) if flip && raw_lazy => quote!(&#name),
|
||||
ParsedFieldType::Node(NodeParsedField { output_type, .. }) if opaque && raw_lazy && is_record_value(output_type) => quote!(&#name),
|
||||
ParsedFieldType::Node(_) if raw_lazy => quote!(&self.#name),
|
||||
// A lend param binds an owned edge; the kernel borrows the
|
||||
// evaluated value.
|
||||
ParsedFieldType::Regular(RegularParsedField { lend: Some(_), .. }) if !flip => quote!(&#name),
|
||||
_ => quote!(#name),
|
||||
}
|
||||
});
|
||||
@@ -1367,7 +1332,12 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
.into_iter();
|
||||
let value_args = regular_fields.iter().skip(if shape.skips_carrier() { 0 } else { 1 }).map(|field| {
|
||||
let name = &field.pat_ident.ident;
|
||||
quote!(#name)
|
||||
match &field.ty {
|
||||
// A lend param binds an owned edge; the kernel borrows the
|
||||
// evaluated value.
|
||||
ParsedFieldType::Regular(RegularParsedField { lend: Some(_), .. }) => quote!(&#name),
|
||||
_ => quote!(#name),
|
||||
}
|
||||
});
|
||||
let attr_args = parsed.attribute_reads.iter().map(|read| {
|
||||
let pat = &read.pat_ident.ident;
|
||||
@@ -2615,7 +2585,7 @@ fn record_entries_tokens(parsed: &ParsedNodeFn, struct_name: &Ident, regular_fie
|
||||
let names: Vec<&Ident> = regular_fields.iter().map(|field| &field.pat_ident.ident).collect();
|
||||
|
||||
let input_types = regular_fields.iter().enumerate().map(|(index, field)| {
|
||||
let ParsedFieldType::Regular(RegularParsedField { ty, lend, .. }) = &field.ty else {
|
||||
let ParsedFieldType::Regular(RegularParsedField { ty, .. }) = &field.ty else {
|
||||
unreachable!("record nodes take no lazy inputs")
|
||||
};
|
||||
if carrier_in_fields && index == 0 {
|
||||
@@ -2628,14 +2598,11 @@ fn record_entries_tokens(parsed: &ParsedNodeFn, struct_name: &Ident, regular_fie
|
||||
RecordCarrier::None => unreachable!(),
|
||||
};
|
||||
}
|
||||
match lend.is_some() {
|
||||
true => quote!(gcore::registry::lend_edge_type::<#ty>()),
|
||||
false => quote!(gcore::registry::edge_type::<#ty>()),
|
||||
}
|
||||
quote!(gcore::registry::edge_type::<#ty>())
|
||||
});
|
||||
let downcasts = regular_fields.iter().enumerate().map(|(index, field)| {
|
||||
let name = &field.pat_ident.ident;
|
||||
let ParsedFieldType::Regular(RegularParsedField { ty, lend, .. }) = &field.ty else {
|
||||
let ParsedFieldType::Regular(RegularParsedField { ty, .. }) = &field.ty else {
|
||||
unreachable!("record nodes take no lazy inputs")
|
||||
};
|
||||
if carrier_in_fields && index == 0 {
|
||||
@@ -2648,10 +2615,7 @@ fn record_entries_tokens(parsed: &ParsedNodeFn, struct_name: &Ident, regular_fie
|
||||
let #name = __carrier_handle.downcast_erased::<gcore::registry::ErasedRecordNode>(__carrier_ty.clone())?;
|
||||
};
|
||||
}
|
||||
match lend.is_some() {
|
||||
true => quote!(let #name = inputs.next().unwrap().downcast_lend::<#ty>()?;),
|
||||
false => quote!(let #name = inputs.next().unwrap().downcast::<#ty>()?;),
|
||||
}
|
||||
quote!(let #name = inputs.next().unwrap().downcast::<#ty>()?;)
|
||||
});
|
||||
let wire_layout_arg = carrier_in_fields.then(|| quote!(&__carrier_layout,)).into_iter();
|
||||
let (io_output, construct_output) = match (&shape.carrier, &shape.element_write) {
|
||||
|
||||
@@ -29,9 +29,8 @@ fn unwrap_option<T: Default>(_: impl Ctx, #[implementations(Option<f64>, Option<
|
||||
input.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Clones the value borrowed from a lending edge. Doubles as the checker-inserted clone-out
|
||||
/// adapter, so it keeps the plain lowering while the record transition runs.
|
||||
#[node_macro::node(category("Debug"), plain)]
|
||||
/// Clones the element out of its record wire.
|
||||
#[node_macro::node(category("Debug"))]
|
||||
fn clone<T: Clone>(_: impl Ctx, #[implementations(List<Raster<CPU>>)] value: &T) -> T {
|
||||
value.clone()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use core_types::arena::{Arena, ArenaCell};
|
||||
use core_types::arena::ArenaCell;
|
||||
use core_types::context::{Ctx, CtxSnapshot, DeriveCtx, ExtractAll, ExtractArena};
|
||||
use core_types::frame_table::{FrameTable, Lookup};
|
||||
use core_types::gpoll::{Extent, Finality, GPoll};
|
||||
@@ -102,34 +102,6 @@ where
|
||||
node.content.extent(ctx)
|
||||
}
|
||||
|
||||
pub fn park<T: Send + Sync>(arena: &Arena, result: GPoll<T>) -> GPoll<&T> {
|
||||
match result {
|
||||
GPoll::Final(value) => match arena.alloc(value) {
|
||||
Some((parked, _)) => GPoll::Final(parked),
|
||||
None => GPoll::arena_exhausted(),
|
||||
},
|
||||
GPoll::Partial(value) => match arena.alloc(value) {
|
||||
Some((parked, _)) => GPoll::Partial(parked),
|
||||
None => GPoll::arena_exhausted(),
|
||||
},
|
||||
GPoll::Fallback(boxed) => {
|
||||
let (value, error) = *boxed;
|
||||
match arena.alloc(value) {
|
||||
Some((parked, _)) => GPoll::Fallback(Box::new((parked, error))),
|
||||
None => GPoll::arena_exhausted(),
|
||||
}
|
||||
}
|
||||
GPoll::Pending => GPoll::Pending,
|
||||
GPoll::Error(error) => GPoll::Error(error),
|
||||
}
|
||||
}
|
||||
|
||||
/// Adapts an owned edge to a lending one by parking each result in the eval arena.
|
||||
#[node_macro::node(category(""), path(graphene_core::memo), skip_impl)]
|
||||
fn lend<'e, T: Send + Sync>(ctx: impl Ctx + ExtractArena<'e>, value: T) -> GPoll<&'e T> {
|
||||
park(ctx.arena(), GPoll::Final(value))
|
||||
}
|
||||
|
||||
type MonitorValue = Arc<Mutex<Option<IORecord<CtxSnapshot, RecordCapture>>>>;
|
||||
|
||||
/// The Monitor node is used by the editor to access the data flowing through it.
|
||||
@@ -156,6 +128,7 @@ fn serialize_monitor(io: &MonitorValue) -> Option<Arc<dyn std::any::Any + Send +
|
||||
mod tests {
|
||||
use super::*;
|
||||
use core_types::SourceId;
|
||||
use core_types::arena::Arena;
|
||||
use core_types::context::{ContextImpl, EvalScope};
|
||||
use core_types::registry::{EdgeHandle, ErasedLendNode, ErasedNode, ErasedRecordNode};
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
@@ -81,7 +81,6 @@ fn forward_record<T>(_: impl Ctx, element: T) -> T {
|
||||
element
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -180,11 +179,7 @@ mod tests {
|
||||
let stacked = multiply_opacity_layout(&modified);
|
||||
reserve_for(&[&source_layout, &modified, &stacked]);
|
||||
|
||||
let chain = MultiplyOpacityNode::new(
|
||||
MultiplyOpacityNode::new(bare_source(&source_layout, 2.), ValueNode(0.5), &source_layout),
|
||||
ValueNode(0.5),
|
||||
&modified,
|
||||
);
|
||||
let chain = MultiplyOpacityNode::new(MultiplyOpacityNode::new(bare_source(&source_layout, 2.), ValueNode(0.5), &source_layout), ValueNode(0.5), &modified);
|
||||
assert_eq!(chain.layout(), Some(&stacked));
|
||||
let GPoll::Final(value) = chain.eval(&ctx) else {
|
||||
panic!("expected a final record");
|
||||
@@ -372,18 +367,6 @@ mod tests {
|
||||
assert!(error.kind == "negative factor");
|
||||
}
|
||||
|
||||
static FACTOR: f64 = 3.;
|
||||
|
||||
struct StaticLendNode(&'static f64);
|
||||
|
||||
impl<'e> Node<ContextImpl<'e>> for StaticLendNode {
|
||||
type Output = &'e f64;
|
||||
|
||||
fn eval(&self, _input: &ContextImpl<'e>) -> GPoll<&'e f64> {
|
||||
GPoll::Final(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lend_value_params_wire_into_record_kernels() {
|
||||
let arena = Arena::new(1024).unwrap();
|
||||
@@ -396,11 +379,7 @@ mod tests {
|
||||
let scaled = scale_layout(&modified);
|
||||
reserve_for(&[&source_layout, &modified, &scaled]);
|
||||
|
||||
let chain = ScaleNode::new(
|
||||
MultiplyOpacityNode::new(bare_source(&source_layout, 2.), ValueNode(0.5), &source_layout),
|
||||
StaticLendNode(&FACTOR),
|
||||
&modified,
|
||||
);
|
||||
let chain = ScaleNode::new(MultiplyOpacityNode::new(bare_source(&source_layout, 2.), ValueNode(0.5), &source_layout), ValueNode(3.), &modified);
|
||||
let GPoll::Final(value) = chain.eval(&ctx) else {
|
||||
panic!("expected a final record");
|
||||
};
|
||||
@@ -585,11 +564,7 @@ mod tests {
|
||||
reserve_for(&[&layout]);
|
||||
|
||||
let probed = |features: ContextFeatures| {
|
||||
let node = crate::context_modification::ContextModificationNode::new(
|
||||
RealTimeProbe { layout: layout.clone() },
|
||||
ValueNode(ContextModification::from_sources(features, &[])),
|
||||
&layout,
|
||||
);
|
||||
let node = crate::context_modification::ContextModificationNode::new(RealTimeProbe { layout: layout.clone() }, ValueNode(ContextModification::from_sources(features, &[])), &layout);
|
||||
assert_eq!(Node::<ContextImpl>::layout(&node), Some(&layout));
|
||||
let GPoll::Final(value) = node.eval(&ctx) else {
|
||||
panic!("expected a final record");
|
||||
|
||||
Reference in New Issue
Block a user