Skip to main content

JsonMapObjectEntryExt

Trait JsonMapObjectEntryExt 

Source
pub trait JsonMapObjectEntryExt {
    // Required method
    fn object_slot_mut_or(
        &mut self,
        slot: &'static str,
    ) -> Result<&mut Map<String, Value>>;
}
Expand description

Substrate extension trait over serde_json::Map<String, Value> — the ONE substrate owner of the .entry(<key>).or_insert_with(|| Value::Object(<empty>)) seed-then-guard shape every JSON-mutating helper hand-authored at the “walk into this object slot on the parent map, seeding an empty object if the slot is absent, or fail loud if the slot exists but is a non-object” boundary.

Peer of ValueObjectExt::as_object_mut_or and JsonMapStrExt::insert_str on the JSON-mutation axis; split by SHAPE + SITE. ValueObjectExt::as_object_mut_or owns the “guard a Value handle into its object interior” step at ONE level; JsonMapStrExt::insert_str owns the “stamp a Value::String at a string-typed key” write shape; this trait owns the compound “get-or-seed the object at a slot, then guard” step every SSA-time re-injection walks when the caller intends to reach a nested object slot without asserting whether the parent has already populated it (a caller composing a fresh resource-body carries no metadata / metadata.annotations slot pre-seed; a caller composing atop a pre-populated resource does — both paths reach the same primitive).

Pre-lift the compound shape was hand-authored at TWO adjacent private helpers in tatara-reconciler::ssapply past the ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold, both walking the SAME 3-step let X = <map>.entry(<slot>).or_insert_with(|| Value::Object (<empty>)); X.as_object_mut_or(<slot>)? incantation:

  • metadata_object_mut(resource) — the metadata slot seed-then- guard step at the root of every SSA-time re-injection walk (inject_owner_reference + inject_annotations reach it).
  • inject_annotations(resource, process) — the annotations slot seed-then-guard step nested one level deeper under the metadata object the primitive above returned.

Both restated the SAME 3-line shape verbatim: .entry(<slot>) on a Map<String, Value> handle known to be an object, then .or_insert_with(|| Value::Object(<empty>)) to synthesize an empty object at the slot when absent, then a .as_object_mut_or (<slot>)? guard on the returned &mut Value to fail loud when the existing slot is a non-object. TWO byte-for-byte identical blocks past the ★★ PRIME-DIRECTIVE ≥ 2 duplication threshold, differing only in the &'static str slot name each callsite stamped ("metadata" / "annotations") — and the slot name is used at BOTH the entry key AND the guard error message so a regression that drifted the two apart at one callsite (a typo stamping "metadata" into the entry key + "metadatas" into the error message) would silently pass one pin and fail the other. Post-lift each callsite reads <map>.object_slot_mut_or (<slot>)? and the compound shape lives at ONE substrate owner here — the slot name is stamped ONCE per call and reaches both the entry key and the guard error slot mechanically.

§Composability

  • Slot name is &'static str — pre-lift both callsites stamped &'static str literals ("metadata" / "annotations"); a dynamic-slot caller (a callsite that reached this primitive with a String key computed at runtime) has no pre-lift precedent in the ssapply/render axis, so the &'static str bound stays honest to the pre-lift shape. A future caller needing a runtime slot name can widen this to impl Into<String> at the substrate; the pre-lift consumers inherit it mechanically.
  • Returns anyhow::Result<&mut Map<String, Value>> — matches the sibling ValueObjectExt::as_object_mut_or shape so the downstream .entry(...).or_insert_with(...) / .insert(...) mutation threads through ? onto the caller’s Result<_, anyhow::Error> return exactly as pre-lift.
  • Ok-arm returns the SAME &mut Map<String, Value> the pre-lift .as_object_mut_or(<slot>) step returned — no clone, no key- order reshape, no synthesis.

§Naming — object_slot_mut_or, not entry_object or

get_or_insert_object_mut

Same discipline as the two sibling traits above — the trait method deliberately does NOT collide with the inherent Map::entry / Map::get_mut / Map::insert methods (any of which a caller who has this trait in scope could resolve to by accident, silently dropping the type-guard step). The _or suffix names the intent (guard the Option → Result step at the same call, matching the pre-lift .as_object_mut_or(<slot>)? guard); object_slot_mut names the target shape (return an &mut object-typed Map at the slot). Together they read as “guard the slot into a mutable object interior or fail loud”, matching the pre-lift semantics exactly.

§#[must_use]

Every consumer threads the ? short-circuit onto its handler’s Result<_, anyhow::Error> return — dropping the guard swallows the underlying type-mismatch entirely, which is never the intended semantic at either pre-lift consumer (each downstream .entry(...).or_insert_with(...) / .insert(...) mutation depends on the returned &mut Map reference).

Theory anchor: THEORY.md §VI.1 (generation over composition — the 3-line .entry(<slot>).or_insert_with(|| Value::Object(<empty>)) .as_object_mut_or(<slot>)? compound shape recurred at two hand-authored sites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication trigger, and is lifted to ONE substrate owner here). THEORY.md §II.1 invariant 5 (composition preserves proofs — a regression that drifted the entry-key slot vs. the guard-error slot at ONE site would silently pass one downstream pin and fail the other; post-lift the primitive stamps the slot ONCE per call so the substrate itself owns the entry-key ↔ guard-error name coherence).

Required Methods§

Source

fn object_slot_mut_or( &mut self, slot: &'static str, ) -> Result<&mut Map<String, Value>>

Get-or-seed the object at slot in this JSON map, then guard that the resulting handle is an object; returns &mut Map<String, Value> on the object arm, and an anyhow::Error whose Display reads "<slot> is not an object" on the non-object arm (byte- identical to the pre-lift .as_object_mut_or(<slot>)? guard, sourced from the sibling ValueObjectExt::as_object_mut_or).

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementations on Foreign Types§

Source§

impl JsonMapObjectEntryExt for Map<String, Value>

Source§

fn object_slot_mut_or( &mut self, slot: &'static str, ) -> Result<&mut Map<String, Value>>

Implementors§