Skip to main content

lumen_engine/node/processing/
memo.rs

1use crate::node::{NodeId, NodeProperty, PortRef};
2
3use crate::gpu::{
4    BoundFrame, CompiledOutput, FrameBindContext, FrameBinding, GpuCompileNode, GpuFrameBindNode,
5};
6
7/// Aliases a raster input through a stable cache boundary.
8#[derive(Debug, Clone, lumen_macros::Node)]
9#[node(kind = "memo", name = "Memo", category = "processing")]
10pub struct Memo {
11    pub id: NodeId,
12    /// Stable cache identifier for this memo boundary.
13    #[property(kind = "string", name = "Cache key", role = "cache_id")]
14    pub cache_id: NodeProperty,
15    /// Allows property expressions to be evaluated across this memo boundary.
16    #[property(kind = "bool")]
17    pub allow_expressions: NodeProperty,
18    #[input()]
19    pub source: PortRef,
20}
21
22impl Default for Memo {
23    fn default() -> Self {
24        Self {
25            id: NodeId::new(0),
26            cache_id: NodeProperty::String(String::new()),
27            allow_expressions: NodeProperty::Bool(false),
28            source: PortRef::empty(),
29        }
30    }
31}
32
33impl GpuCompileNode for Memo {
34    fn compile_gpu(
35        &self,
36        ctx: &mut crate::gpu::CompileContext<'_>,
37        port: &PortRef,
38    ) -> crate::Result<CompiledOutput> {
39        if port.port != "output" {
40            return Err(ctx.missing_output(self.id, &port.port));
41        }
42        let source = ctx.compile_port(&self.source)?;
43        ctx.push_frame_binding(FrameBinding::Memo {
44            node_id: self.id,
45            cache_id: self.cache_id.clone(),
46            allow_expressions: self.allow_expressions.clone(),
47        });
48        Ok(source)
49    }
50}
51
52impl GpuFrameBindNode for Memo {
53    fn bind_gpu_frame(
54        &self,
55        ctx: &FrameBindContext<'_>,
56        binding: &FrameBinding,
57        _bound: &mut BoundFrame,
58    ) -> crate::Result<()> {
59        let FrameBinding::Memo {
60            node_id,
61            cache_id,
62            allow_expressions,
63        } = binding
64        else {
65            return Ok(());
66        };
67        let _ = cache_id.resolve_string(
68            *node_id,
69            "cache_id",
70            &ctx.expr_context(*node_id, "cache_id"),
71        )?;
72        let _ = allow_expressions.resolve_bool(
73            *node_id,
74            "allow_expressions",
75            &ctx.expr_context(*node_id, "allow_expressions"),
76        )?;
77        Ok(())
78    }
79}