Skip to main content

dataflow_rs/expr/
output.rs

1//! Write destinations.
2
3use super::config::{CompileCx, ConfigField, FieldKind, Resolver, Visit};
4use super::expr::Expr;
5use super::path::Path;
6use crate::base::Result;
7use datavalue::OwnedDataValue;
8use serde_json::Value;
9
10/// A write destination: an `Expr<Path>`, folded when literal.
11///
12/// The engine records every destination it writes through, in each
13/// `Change`'s path, so a config's visit reports an `Output` as recorded
14/// whether or not its field says `records`.
15#[derive(Debug)]
16pub struct Output(Expr<Path>);
17
18impl Output {
19    /// The destination expression.
20    pub fn path(&self) -> &Expr<Path> {
21        &self.0
22    }
23
24    /// The destination when it is a literal path, resolved at compile time.
25    pub fn constant(&self) -> Option<&Path> {
26        self.0.constant()
27    }
28}
29
30impl ConfigField for Output {
31    const IS_OUTPUT: bool = true;
32    fn compile(raw: &Value, cx: &mut CompileCx<'_>) -> Option<Self> {
33        <Expr<Path>>::compile(raw, cx).map(Self)
34    }
35    /// Visited as recorded, wherever it sits: a destination lands in every
36    /// `Change` written through it, so it may not read a secret.
37    fn visit(&self, v: &mut Visit<'_>) {
38        v.recording(true, |v| v.expr(self.0.raw()));
39    }
40    /// The destination's dotted text, computed for this call when it is not
41    /// literal.
42    fn resolve(&self, r: &mut dyn Resolver) -> Result<Option<OwnedDataValue>> {
43        r.eval(&self.0).map(Some)
44    }
45    fn kind() -> FieldKind {
46        FieldKind::Output
47    }
48}