//! A minimal recording sink a downstream consumer would author (C8 sink role, //! C22: displayable = exactly what a sink recorded). //! //! It declares a single `f64` input with `Firing::Any`, an empty `output` //! (the pure-consumer declaration), and in `eval` pushes `(now, value)` to a //! destination it holds as a field — an out-of-graph side effect. Returns //! `None` (records nothing into the graph). use std::cell::RefCell; use std::rc::Rc; use aura_core::{Ctx, Firing, InputSpec, Node, NodeSchema, Scalar, ScalarKind, Timestamp}; /// Shared, out-of-graph destination the recorder writes into. pub type Tape = Rc>>; pub struct Recorder { tape: Tape, } impl Recorder { pub fn new(tape: Tape) -> Self { Self { tape } } } impl Node for Recorder { fn schema(&self) -> NodeSchema { NodeSchema { inputs: vec![InputSpec { kind: ScalarKind::F64, lookback: 1, firing: Firing::Any, }], output: vec![], // pure consumer (sink) } } fn eval(&mut self, ctx: Ctx<'_>) -> Option<&[Scalar]> { if let Some(v) = ctx.f64_in(0).get(0) { self.tape.borrow_mut().push((ctx.now(), v)); } None } }