mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Restore serialize-based introspection through the typed edges
This commit is contained in:
@@ -282,11 +282,11 @@ impl BorrowTree {
|
||||
self.nodes.insert(id, (node, path));
|
||||
}
|
||||
|
||||
/// Returns the introspection record for that specific node, for example the cached value for a monitor node. The node path must match the document node path.
|
||||
/// Calls the `GNode::serialize` for that specific node, returning for example the captured io record for a monitor node. The node path must match the document node path.
|
||||
pub fn introspect(&self, node_path: &[NodeId]) -> Result<Arc<dyn std::any::Any + Send + Sync + 'static>, IntrospectError> {
|
||||
let (id, _) = self.source_map.get(node_path).ok_or_else(|| IntrospectError::PathNotFound(node_path.to_vec()))?;
|
||||
let (_node, _path) = self.nodes.get(id).ok_or(IntrospectError::ProtoNodeNotFound(*id))?;
|
||||
Err(IntrospectError::NoData)
|
||||
let (node, _path) = self.nodes.get(id).ok_or(IntrospectError::ProtoNodeNotFound(*id))?;
|
||||
node.serialize().ok_or(IntrospectError::NoData)
|
||||
}
|
||||
|
||||
pub fn get(&self, id: NodeId) -> Option<EdgeHandle> {
|
||||
|
||||
@@ -31,6 +31,11 @@ pub trait GNode<Input> {
|
||||
GPoll::Final(Extent::Free)
|
||||
}
|
||||
|
||||
/// Introspection access to node-resident records, for example the monitor's captured io; `None` for ordinary nodes.
|
||||
fn serialize(&self) -> Option<std::sync::Arc<dyn std::any::Any + Send + Sync>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn eval_batch<'a>(&self, input: &'a Input, range: Range<u64>, scratch: Option<&'a mut [MaybeUninit<Self::Output>]>) -> BatchStatus<'a, Self::Output>
|
||||
where
|
||||
Input: InjectIndex + Copy,
|
||||
|
||||
@@ -148,6 +148,11 @@ where
|
||||
unsafe { self.ptr.as_ref() }.extent(input)
|
||||
}
|
||||
|
||||
fn serialize(&self) -> Option<std::sync::Arc<dyn std::any::Any + Send + Sync>> {
|
||||
// SAFETY: as in eval.
|
||||
unsafe { self.ptr.as_ref() }.serialize()
|
||||
}
|
||||
|
||||
fn eval_batch<'a>(
|
||||
&self,
|
||||
input: &'a Input,
|
||||
@@ -165,6 +170,7 @@ where
|
||||
pub struct EdgeHandle {
|
||||
node: Box<DynEdge>,
|
||||
share: fn(&DynEdge) -> Box<DynEdge>,
|
||||
serialize: fn(&DynEdge) -> Option<std::sync::Arc<dyn std::any::Any + Send + Sync>>,
|
||||
ty: Type,
|
||||
}
|
||||
|
||||
@@ -185,11 +191,13 @@ impl EdgeHandle {
|
||||
|
||||
pub fn new_erased<N: ?Sized + 'static>(node: std::sync::Arc<N>, ty: Type) -> Self
|
||||
where
|
||||
N: for<'c> GNode<ContextImpl<'c>>,
|
||||
SharedEdge<N>: WasmNotSend + WasmNotSync,
|
||||
{
|
||||
Self {
|
||||
node: Box::new(SharedEdge::new(node)),
|
||||
share: |edge| Box::new(edge.downcast_ref::<SharedEdge<N>>().expect("share hook matches the stored edge type").share()),
|
||||
serialize: |edge| GNode::<ContextImpl>::serialize(edge.downcast_ref::<SharedEdge<N>>().expect("serialize hook matches the stored edge type")),
|
||||
ty,
|
||||
}
|
||||
}
|
||||
@@ -202,10 +210,15 @@ impl EdgeHandle {
|
||||
Self {
|
||||
node: (self.share)(&*self.node),
|
||||
share: self.share,
|
||||
serialize: self.serialize,
|
||||
ty: self.ty.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize(&self) -> Option<std::sync::Arc<dyn std::any::Any + Send + Sync>> {
|
||||
(self.serialize)(&*self.node)
|
||||
}
|
||||
|
||||
pub fn downcast<T: 'static>(self) -> Result<SharedEdge<ErasedGNode<T>>, ConstructionError> {
|
||||
self.downcast_erased(edge_type::<T>())
|
||||
}
|
||||
|
||||
@@ -234,6 +234,18 @@ pub(crate) fn generate_gnode_code(crate_ident: &CrateIdent, parsed: &ParsedNodeF
|
||||
}
|
||||
};
|
||||
|
||||
let serialize_impl = match &parsed.attributes.serialize {
|
||||
Some(path) => {
|
||||
let data_refs = data_names.iter().map(|name| quote!(&self.#name));
|
||||
quote! {
|
||||
fn serialize(&self) -> Option<::std::sync::Arc<dyn ::std::any::Any + Send + Sync>> {
|
||||
#path(#(#data_refs),*)
|
||||
}
|
||||
}
|
||||
}
|
||||
None => quote!(),
|
||||
};
|
||||
|
||||
let batch_impl = match &parsed.attributes.batch {
|
||||
Some(path) => quote! {
|
||||
fn eval_batch<'__batch>(
|
||||
@@ -432,6 +444,8 @@ pub(crate) fn generate_gnode_code(crate_ident: &CrateIdent, parsed: &ParsedNodeF
|
||||
|
||||
#extent_impl
|
||||
|
||||
#serialize_impl
|
||||
|
||||
#batch_impl
|
||||
}
|
||||
};
|
||||
|
||||
@@ -170,6 +170,24 @@ mod tests {
|
||||
EvalScope::new(Some(0.5), None, None, generations, arena)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn monitor_serialize_exposes_the_io_record_through_the_edge() {
|
||||
let arena = Arena::new(1024);
|
||||
let generations = [];
|
||||
let scope = scope_fixture(&generations, &arena);
|
||||
let ctx = ContextImpl::root(&scope);
|
||||
|
||||
let handle = EdgeHandle::new(Arc::new(MonitorNode::new(ValueNode(11u32))) as Arc<ErasedGNode<u32>>);
|
||||
assert!(handle.serialize().is_none(), "no record before the first eval");
|
||||
|
||||
let edge = handle.duplicate().downcast::<u32>().unwrap();
|
||||
assert_eq!(edge.eval(&ctx), GPoll::Final(11));
|
||||
|
||||
let record = handle.serialize().expect("the eval landed a record");
|
||||
let record = record.downcast_ref::<IORecord<CtxSnapshot, u32>>().expect("the record is the monitor io");
|
||||
assert_eq!(record.output, 11);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn memoize_caches_across_evals() {
|
||||
let arena = Arena::new(1024);
|
||||
@@ -236,7 +254,7 @@ mod tests {
|
||||
|
||||
let edge = EdgeHandle::new(Arc::new(ValueNode("lent out".to_string())) as Arc<ErasedGNode<String>>);
|
||||
let lending = EdgeHandle::new_ref(Arc::new(FrameMemoNode::new(edge.downcast::<String>().unwrap())) as Arc<ErasedLendGNode<String>>);
|
||||
assert_eq!(*lending.ty(), Type::Ref(Box::new(concrete!(String))));
|
||||
assert_eq!(*lending.ty(), core_types::registry::lend_edge_type::<String>());
|
||||
|
||||
let node = lending.downcast_lend::<String>().unwrap();
|
||||
let GPoll::Final(first) = node.eval(&ctx) else {
|
||||
|
||||
Reference in New Issue
Block a user