dataflow_rs/expr/output.rs
1//! Write destinations.
2
3use super::config::{CompileCx, ConfigField, FieldKind, OutputOverride, 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 ///
43 /// A resolver that supplies the callee's primary output answers before
44 /// the expression is evaluated, so a computed destination that yields
45 /// `null` need not fail an input a layer only reads
46 /// ([`Ctx::input_with_primary_output`](crate::Ctx::input_with_primary_output)).
47 fn resolve(&self, r: &mut dyn Resolver) -> Result<Option<OwnedDataValue>> {
48 if let Some(supplied) = r.output_override(self) {
49 return Ok(match supplied {
50 OutputOverride::Omit => None,
51 OutputOverride::Value(value) => Some(value),
52 });
53 }
54 r.eval(&self.0).map(Some)
55 }
56 fn kind() -> FieldKind {
57 FieldKind::Output
58 }
59}