Capture the input context snapshot on the monitor io record

This commit is contained in:
Dennis Kobert
2026-08-06 09:37:24 +00:00
parent daf3f25d21
commit 612afb7ebb
5 changed files with 40 additions and 19 deletions

View File

@@ -1,8 +1,9 @@
use core_types::arena::{Arena, ArenaCell};
use core_types::context::{Ctx, ExtractArena};
use core_types::context::{Ctx, CtxSnapshot, DeriveCtx, ExtractAll, ExtractArena};
use core_types::frame_table::{FrameTable, Lookup};
use core_types::gpoll::{Extent, Finality, GPoll};
use core_types::graphene_hash::CacheHash;
use core_types::memo::IORecord;
use core_types::node::Node;
use core_types::record::{OwnedRecord, RecordCapture, RecordValue};
use core_types::registry::cache_key;
@@ -119,23 +120,26 @@ fn lend<'e, T: Send + Sync>(ctx: impl Ctx + ExtractArena<'e>, value: T) -> GPoll
park(ctx.arena(), GPoll::Final(value))
}
type MonitorValue = Arc<Mutex<Option<RecordCapture>>>;
type MonitorValue = Arc<Mutex<Option<IORecord<CtxSnapshot, RecordCapture>>>>;
/// The Monitor node is used by the editor to access the data flowing through it.
#[node_macro::node(category(""), path(graphene_core::memo), serialize(serialize_monitor), properties("monitor_properties"))]
fn monitor<'e>(ctx: impl Ctx + ExtractArena<'e>, #[data] capture: MonitorValue, content: impl Node<Context<'_>, Output = RecordValue<'e>>) -> GPoll<RecordValue<'e>> {
fn monitor<'e>(ctx: impl Ctx + DeriveCtx + ExtractAll + ExtractArena<'e>, #[data] io: MonitorValue, content: impl Node<Context<'_>, Output = RecordValue<'e>>) -> GPoll<RecordValue<'e>> {
let result = content.eval(&ctx);
if let GPoll::Final(value) | GPoll::Partial(value) = &result {
// SAFETY: the value came from this edge, so it carries the edge's layout.
let captured = unsafe { RecordCapture::capture(content.layout(), content.layout().rec(value), ctx.arena()) };
*capture.lock().unwrap() = captured;
*io.lock().unwrap() = captured.map(|output| IORecord {
input: CtxSnapshot::capture(ctx),
output,
});
}
result
}
fn serialize_monitor(capture: &MonitorValue) -> Option<Arc<dyn std::any::Any + Send + Sync>> {
let capture = capture.lock().unwrap();
capture.as_ref().map(|capture| Arc::new(capture.clone()) as Arc<dyn std::any::Any + Send + Sync>)
fn serialize_monitor(io: &MonitorValue) -> Option<Arc<dyn std::any::Any + Send + Sync>> {
let io = io.lock().unwrap();
io.as_ref().map(|io| Arc::new(io.clone()) as Arc<dyn std::any::Any + Send + Sync>)
}
#[cfg(test)]
@@ -201,9 +205,13 @@ mod tests {
panic!("expected a final record");
};
let capture = handle.serialize().expect("the eval landed a capture");
let capture = capture.downcast_ref::<RecordCapture>().expect("the capture is a record capture");
let element = capture.materialize_element(&arena).expect("the capture materializes inside the window");
let io = handle.serialize().expect("the eval landed a capture");
let io = io.downcast_ref::<IORecord<CtxSnapshot, RecordCapture>>().expect("the capture is the monitor io");
assert!(
core_types::context::ExtractFootprint::try_footprint(&io.input).is_none(),
"the root context has no footprint to capture"
);
let element = io.output.materialize_element(&arena).expect("the capture materializes inside the window");
assert_eq!(*element.downcast_ref::<u32>().unwrap(), 11);
}

View File

@@ -474,15 +474,17 @@ mod tests {
assert_eq!(unsafe { layout.rec(&value).element::<f64>() }, 4.);
}
let capture = Node::<ContextImpl>::serialize(&monitor).unwrap();
let capture = capture.downcast_ref::<core_types::record::RecordCapture>().unwrap();
let fields = capture.materialize(&arena).unwrap();
let io = Node::<ContextImpl>::serialize(&monitor).unwrap();
let io = io
.downcast_ref::<core_types::memo::IORecord<core_types::context::CtxSnapshot, core_types::record::RecordCapture>>()
.unwrap();
let fields = io.output.materialize(&arena).unwrap();
assert_eq!(fields.len(), 1);
assert_eq!(fields[0].0, "opacity");
assert_eq!(*fields[0].1.as_any().downcast_ref::<f64>().unwrap(), 0.25);
arena.reset();
assert!(capture.materialize(&arena).is_none(), "a dead generation materializes to nothing");
assert!(io.output.materialize(&arena).is_none(), "a dead generation materializes to nothing");
}
#[test]