From fb94d9980750780c03bd8dd970d127ee96b20465 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Tue, 11 Aug 2026 09:54:48 +0000 Subject: [PATCH] Port the stale math-nodes and raster-nodes tests onto record wires --- node-graph/nodes/math/src/lib.rs | 137 ++++++++++++++---- .../nodes/raster/src/image_color_palette.rs | 2 +- 2 files changed, 108 insertions(+), 31 deletions(-) diff --git a/node-graph/nodes/math/src/lib.rs b/node-graph/nodes/math/src/lib.rs index 469e2bff5d..413d876833 100644 --- a/node-graph/nodes/math/src/lib.rs +++ b/node-graph/nodes/math/src/lib.rs @@ -1060,9 +1060,10 @@ mod graphene_test { use core_types::context::{ContextImpl, EvalScope, ExtractIndex}; use core_types::gpoll::{Finality, GPoll}; use core_types::node::{BatchStatus, Node}; - use core_types::registry::{EdgeHandle, ErasedNode, construct}; + use core_types::record::{Layout, RecordLift, RecordValue, stack}; + use core_types::registry::{ErasedRecordNode, construct}; + use core_types::value::record_value_edge; use std::mem::MaybeUninit; - use std::sync::Arc; struct SourceNode(T); @@ -1088,14 +1089,42 @@ mod graphene_test { EvalScope::new(None, None, None, &[], arena) } + fn reserve_for(layouts: &[&Layout]) { + stack::reserve(layouts.iter().map(|layout| layout.frame_bytes()).sum::().max(1 << 12)); + } + + /// Lifts a plain-element test source onto a record wire, returned beside its + /// element-only layout for the generated node's constructor. + fn lifted(node: N) -> (RecordLift, Layout) + where + T: Clone + Send + Sync + 'static, + N: for<'c> Node, Output = T>, + { + let lift = RecordLift::::new(node); + let layout = Node::::layout(&lift).clone(); + (lift, layout) + } + + fn element(layout: &Layout, value: &RecordValue<'_>) -> T { + unsafe { layout.rec(value).element::() } + } + #[test] fn generated_add_evaluates_through_the_node_path() { let arena = Arena::new(64).unwrap(); let scope = scope_fixture(&arena); let ctx = ContextImpl::root(&scope); - let graph = AddNode::new(SourceNode(1.0f64), SourceNode(2.0f64)); - assert_eq!(Node::eval(&graph, &ctx), GPoll::Final(3.0)); + let (a, la) = lifted(SourceNode(1.0f64)); + let (b, lb) = lifted(SourceNode(2.0f64)); + let graph = AddNode::<_, _, f64, f64>::new(a, b, &la, &lb); + let out = Node::::layout(&graph).clone(); + reserve_for(&[&la, &lb, &out]); + + let GPoll::Final(value) = Node::eval(&graph, &ctx) else { + panic!("expected a final record"); + }; + assert_eq!(element::(&out, &value), 3.0); } #[test] @@ -1104,14 +1133,20 @@ mod graphene_test { let scope = scope_fixture(&arena); let ctx = ContextImpl::root(&scope); - let erased: Box> = Box::new(AddNode::new(IndexNode, SourceNode(10.0f64))); + let (index, li) = lifted(IndexNode); + let (src, ls) = lifted(SourceNode(10.0f64)); + let node = AddNode::<_, _, f64, f64>::new(index, src, &li, &ls); + let out = Node::::layout(&node).clone(); + reserve_for(&[&li, &ls, &out]); + + let erased: Box = Box::new(node); let mut scratch = [const { MaybeUninit::uninit() }; 4]; let status = erased.eval_batch(&ctx, 2..6, Some(&mut scratch)); let BatchStatus::Filled(batch, finality) = status else { panic!("expected filled, got {status:?}"); }; let mut got = Vec::new(); - batch.for_each(|_, lane| got.push(*lane)); + batch.for_each(|_, lane| got.push(unsafe { lane.element::() })); assert_eq!(got, vec![12.0, 13.0, 14.0, 15.0]); assert_eq!(finality, Finality::AllFinal); } @@ -1122,12 +1157,16 @@ mod graphene_test { let scope = scope_fixture(&arena); let ctx = ContextImpl::root(&scope); - let entries = logical_or_entries(); - let value = EdgeHandle::new(Arc::new(SourceNode(true)) as Arc>); - let other_value = EdgeHandle::new(Arc::new(SourceNode(false)) as Arc>); - let wired = construct(&entries[0], vec![value, other_value]).unwrap().downcast::().unwrap(); + let entries = super::_logical_or_mod::logical_or_entries(); + let wired = construct(&entries[0], vec![record_value_edge(true), record_value_edge(false)]).unwrap(); + let layout = wired.layout().unwrap().clone(); + let edge = wired.downcast_record::().unwrap(); + reserve_for(&[&layout]); - assert_eq!(Node::eval(&wired, &ctx), GPoll::Final(true)); + let GPoll::Final(value) = edge.eval(&ctx) else { + panic!("expected a final record"); + }; + assert!(element::(&layout, &value)); } #[test] @@ -1146,18 +1185,22 @@ mod graphene_test { let scope = scope_fixture(&arena); let ctx = ContextImpl::root(&scope); - let entries = add_entries(); + let entries = super::_add_mod::add_entries(); assert_eq!(entries.len(), 6); - assert_eq!(entries[0].io.inputs, vec![core_types::concrete!(f64), core_types::concrete!(f64)]); - assert_eq!(entries[0].io.return_value, core_types::concrete!(f64)); - assert_eq!(entries[3].io.inputs, vec![core_types::concrete!(DVec2), core_types::concrete!(DVec2)]); - assert_eq!(entries[3].io.return_value, core_types::concrete!(DVec2)); + assert_eq!(entries[0].io.inputs, vec![core_types::registry::record_edge_type::(), core_types::registry::record_edge_type::()]); + assert_eq!(entries[0].io.return_value, core_types::registry::record_type::()); + assert_eq!(entries[3].io.inputs, vec![core_types::registry::record_edge_type::(), core_types::registry::record_edge_type::()]); + assert_eq!(entries[3].io.return_value, core_types::registry::record_type::()); - let augend = EdgeHandle::new(Arc::new(SourceNode(1.5f64)) as Arc>); - let addend = EdgeHandle::new(Arc::new(SourceNode(2.5f64)) as Arc>); - let wired = construct(&entries[0], vec![augend, addend]).unwrap().downcast::().unwrap(); + let wired = construct(&entries[0], vec![record_value_edge(1.5f64), record_value_edge(2.5f64)]).unwrap(); + let layout = wired.layout().unwrap().clone(); + let edge = wired.downcast_record::().unwrap(); + reserve_for(&[&layout]); - assert_eq!(Node::eval(&wired, &ctx), GPoll::Final(4.0)); + let GPoll::Final(value) = edge.eval(&ctx) else { + panic!("expected a final record"); + }; + assert_eq!(element::(&layout, &value), 4.0); } #[test] @@ -1182,9 +1225,17 @@ mod graphene_test { let taken = Arc::new(AtomicU32::new(0)); let untaken = Arc::new(AtomicU32::new(0)); - let graph = SwitchNode::new(SourceNode(true), CountingSource(taken.clone(), 1.0), CountingSource(untaken.clone(), 2.0)); + let (cond, lc) = lifted(SourceNode(true)); + let (if_true, lt) = lifted(CountingSource(taken.clone(), 1.0)); + let (if_false, lf) = lifted(CountingSource(untaken.clone(), 2.0)); + let graph = SwitchNode::<_, _, _, f64>::new(cond, if_true, if_false, &lc, <, &lf); + let out = Node::::layout(&graph).clone(); + reserve_for(&[&lc, <, &lf, &out]); - assert_eq!(Node::eval(&graph, &ctx), GPoll::Final(1.0)); + let GPoll::Final(value) = Node::eval(&graph, &ctx) else { + panic!("expected a final record"); + }; + assert_eq!(element::(&out, &value), 1.0); assert_eq!(taken.load(Ordering::Relaxed), 1); assert_eq!(untaken.load(Ordering::Relaxed), 0); } @@ -1215,11 +1266,23 @@ mod graphene_test { let scope = scope_fixture(&arena); let ctx = ContextImpl::root(&scope); - let pending = SwitchNode::new(SourceNode(true), PendingSource, PartialSource); - assert_eq!(Node::eval(&pending, &ctx), GPoll::Pending); + let (c1, lc1) = lifted(SourceNode(true)); + let (p1, lp1) = lifted(PendingSource); + let (pa1, lpa1) = lifted(PartialSource); + let pending = SwitchNode::<_, _, _, f64>::new(c1, p1, pa1, &lc1, &lp1, &lpa1); - let partial = SwitchNode::new(SourceNode(false), PendingSource, PartialSource); - assert_eq!(Node::eval(&partial, &ctx), GPoll::Partial(7.0)); + let (c2, lc2) = lifted(SourceNode(false)); + let (p2, lp2) = lifted(PendingSource); + let (pa2, lpa2) = lifted(PartialSource); + let partial = SwitchNode::<_, _, _, f64>::new(c2, p2, pa2, &lc2, &lp2, &lpa2); + let out = Node::::layout(&partial).clone(); + reserve_for(&[&lc1, &lp1, &lpa1, &lc2, &lp2, &lpa2, &out]); + + assert!(matches!(Node::eval(&pending, &ctx), GPoll::Pending)); + let GPoll::Partial(value) = Node::eval(&partial, &ctx) else { + panic!("expected a partial record"); + }; + assert_eq!(element::(&out, &value), 7.0); } #[test] @@ -1238,8 +1301,17 @@ mod graphene_test { let scope = scope_fixture(&arena); let ctx = ContextImpl::root(&scope); - let graph = SwitchNode::new(PartialCondition, SourceNode(1.0f64), SourceNode(2.0f64)); - assert_eq!(Node::eval(&graph, &ctx), GPoll::Partial(1.0)); + let (cond, lc) = lifted(PartialCondition); + let (if_true, lt) = lifted(SourceNode(1.0f64)); + let (if_false, lf) = lifted(SourceNode(2.0f64)); + let graph = SwitchNode::<_, _, _, f64>::new(cond, if_true, if_false, &lc, <, &lf); + let out = Node::::layout(&graph).clone(); + reserve_for(&[&lc, <, &lf, &out]); + + let GPoll::Partial(value) = Node::eval(&graph, &ctx) else { + panic!("expected a partial record"); + }; + assert_eq!(element::(&out, &value), 1.0); } #[test] @@ -1258,11 +1330,16 @@ mod graphene_test { let scope = scope_fixture(&arena); let ctx = ContextImpl::root(&scope); - let graph = AddNode::new(FallbackNode, SourceNode(5.0f64)); + let (fallback, lfb) = lifted(FallbackNode); + let (src, ls) = lifted(SourceNode(5.0f64)); + let graph = AddNode::<_, _, f64, f64>::new(fallback, src, &lfb, &ls); + let out = Node::::layout(&graph).clone(); + reserve_for(&[&lfb, &ls, &out]); + let GPoll::Fallback(boxed) = Node::eval(&graph, &ctx) else { panic!("fallback must propagate with the computed stand-in"); }; - assert_eq!(boxed.0, 5.0); + assert_eq!(element::(&out, &boxed.0), 5.0); assert!(boxed.1.kind == "upstream failed"); assert_eq!(boxed.1.trace, vec![0]); } diff --git a/node-graph/nodes/raster/src/image_color_palette.rs b/node-graph/nodes/raster/src/image_color_palette.rs index 377810c6c0..f881bb77ed 100644 --- a/node-graph/nodes/raster/src/image_color_palette.rs +++ b/node-graph/nodes/raster/src/image_color_palette.rs @@ -69,7 +69,7 @@ mod test { fn test_image_color_palette() { let result = image_color_palette( &(), - List::new_from_element(Raster::new_cpu(Image { + &List::new_from_element(Raster::new_cpu(Image { width: 100, height: 100, data: vec![Color::from_rgbaf32(0., 0., 0., 1.).unwrap(); 10000],