Skip to main content

to_value_or_null

Function to_value_or_null 

Source
pub fn to_value_or_null<T: Serialize>(value: T) -> Value
Expand description

Serialise a T: Serialize into a serde_json::Value, folding the (in-practice unreachable) serde_json::to_value error to serde_json::Value::Null — the ONE substrate owner of the “serde- serialise a caller-supplied T into a JSON slot value, falling back to Value::Null on the residual Err arm the round-trip’s contract permits but no in-workspace payload triggers” shape.

Pre-lift the SAME serde_json::to_value(<T>).unwrap_or(Value::Null) chain was hand-authored at TWO consumer sites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold, each restating the same three-link chain (to_valueunwrap_orValue::Null fallback) to seed a JSON slot value from a caller-supplied serde-serialisable payload:

  • annotation_body — folds the caller’s value: impl Serialize into the metadata.annotations.<key> leaf on the single-annotation merge-body composer. Every downstream single-annotation writer (signals-strip, RELEASED_FROM stamp, return-trigger stamp) rides through this fold.
  • tatara_reconciler::patch::phase_status_with — folds the caller’s value: impl Serialize into the caller-named third slot on the phase-transition status-patch composer. Every downstream extra-slot phase-transition writer (Running-entry fluxResources attach, Attested-entry attestation attach, and — via [crate::patch::phase_status]’s Some arm delegating through the composer — the Forking-entry identity attach) rides through this fold. The reconciler-side callsite reaches THIS substrate primitive by fully-qualified name (tatara_process::patch::to_value_or_null).

Both sites walked the SAME three-link chain — serde_json::to_value on the caller-supplied T, Result::unwrap_or on the residual Err arm, serde_json::Value::Null as the fallback constant. Differing only in the T slot’s downstream consumer (an annotations.<key> leaf vs a phase_status_base sibling slot). Post-lift each callsite reads to_value_or_null(v) and the three-link chain lives at ONE substrate owner.

A future normalization of the fold discipline — a promotion of the Value::Null fallback to a typed error return so a caller’s Serialize impl that legitimately fails at runtime surfaces at the composer rather than being silently dropped to null; a canonicalization pass over the produced Value (a sort-map-keys walk for deterministic byte output, a whitespace-strip for size); a tracing::warn! span at the Err arm so the silent drop leaves an operator-visible breadcrumb; a switch to serde_json::to_value’s Cow-returning peer for zero-copy on already-Value inputs — lands at THIS ONE substrate primitive and both downstream fold consumers (plus every future JSON-slot-seeded-from-T: Serialize writer that grows a third consumer) inherit the upgrade mechanically. No per-site edit at annotation_body or at phase_status_with; a new consumer (a hypothetical typed labels composer, an annotations-batch composer, a per-slot status-patch composer) picks up the sibling primitive by name and inherits the same fold discipline.

Sibling to crate::three_pillar::pillar_bytes on the (T: Serialize → wire-shape) axis pair: pillar_bytes owns the serde_json::to_vec(<T>).unwrap_or_default() fold for the attestation-pillar bytes axis (returning Vec<u8> with a Vec::default() empty fallback); this primitive owns the serde_json::to_value(<T>).unwrap_or(Value::Null) fold for the JSON-slot value axis (returning Value with a Value::Null fallback). Both hold the invariant that a caller-supplied serde-serialisable payload folds into a wire-form value at ONE substrate owner rather than at each per-site hand-authored chain.

The T: Serialize bound accepts owned or borrowed values of any serde-serialisable type without widening the signature — matches annotation_body’s impl Serialize value slot verbatim and matches phase_status_with’s T: Serialize extra slot verbatim. A serialisation failure (the Err arm the serde_json::to_value contract permits) resolves to serde_json::Value::Null, matching the pre-lift discipline both callsites carried before this lift. In practice the shapes each callsite passes (a Value::Null, a String, a &'static str, an &Identity, a &Vec<FluxResourceRef>, a &ProcessAttestation) never fail to serialise; the fallback is a defensive guard against a future caller passing a T whose Serialize impl signals a runtime error at that boundary.

Theory anchor: THEORY.md §VI.1 (generation over composition — the 3-link serde_json::to_value(<T>).unwrap_or(Value::Null) chain recurred at 2 hand-authored sites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication trigger inside two workspace crates, and is lifted onto ONE substrate owner here). THEORY.md §II.1 invariant 5 (composition preserves proofs — the pin block below binds the composer at fail-before-pass-after granularity, so a regression that drifts the serialiser choice, flips the fallback constant, reshapes the return form, or narrows the T: Serialize bound surfaces HERE rather than as silent JSON-slot-value skew across the two consumer sites).