Skip to main content

Annotated

Trait Annotated 

Source
pub trait Annotated: Resource<DynamicType = ()> {
    // Provided method
    fn annotation(&self, key: &str) -> Option<&str> { ... }
}
Expand description

Substrate-primitive trait for the ONE borrow-form annotation lookup every tatara CRD reconciler restated as the 3-line .metadata.annotations.as_ref().and_then(|m| m.get(key)).map(String::as_str) chain (or a .cloned() / .cloned().unwrap_or_default() variant of the same shape) on the K8s metadata.annotations map: returns Some(&str) iff the annotations block is present AND the key is present inside it; both missing corners collapse to None.

Peer to DeletionTombstoned + NamespacedApiCoordinates on the substrate-primitive-trait axis (kube-Resource blanket impls over DynamicType = ()), and peer to the pre-existing crate::prelude::Process::annotation inherent forwarder on the axis of “one annotation-lookup shape shared across every kube resource, tatara CRD or K8s built-in”. The inherent stays as a peer — Rust method resolution prefers an inherent over a trait’s blanket impl, so the three consumers already routed through Process::annotation (tatara-reconciler::signals::ingest, tatara-reconciler::phase_machine::released_from_annotation, tatara-pool-reconciler::controller_pool::process_belongs_to_pool) keep hitting the byte-identical code path — and the trait’s blanket impl closes the substrate corner for kube resources WITHOUT the inherent: post-lift the hand-authored .metadata.annotations.as_ref().and_then(|m| m.get(KEY))... chain in tatara-export-worker::main (on k8s_openapi’s ConfigMap, which has no tatara-owned inherent) routes through the trait at cm.annotation(KEY), and any future EphemeralPool / EphemeralAllocation (or new tatara CRD) consumer that needs an annotation lookup inherits the primitive for free — the same solve-once discipline the two peer traits already established.

Return-form axis: Option<&str> matches the borrow-first discipline of the peer metadata primitives (crate::prelude::Process::namespace_or_default, crate::prelude::Process::name_or_placeholder, crate::prelude::Process::coordinates_or_none, and the inherent crate::prelude::Process::annotation this trait mirrors). The two corners the pre-lift chain swallowed (missing annotations map, missing key inside the map) BOTH collapse to None so .is_some() / if let Some(_) / Option::map behave identically on a resource whose annotations block is None and on one whose annotations block is populated but omits the key — matching what the pre-lift .and_then(...) chain produced.

A future normalization step (a key-canonicalization pass, a case-fold lookup, a per-key alias table for renamed annotations across API versions, a per-namespace override substrate) lands at ONE trait method here and every downstream consumer — the four current sites plus every future CRD reconciler that inherits the blanket impl — picks up the upgrade mechanically. If the inherent is ever rewired to <Self as Annotated>::annotation(self, key) as a follow-up sweep, the three inherent-preferred callsites automatically inherit any trait-level upgrade too.

Theory anchor: THEORY.md §VI.1 (generation over composition — the annotation-lookup shape recurred as ONE inherent forwarder on Process PLUS a hand-authored chain on ConfigMap past the ★★ PRIME-DIRECTIVE ≥ 2 duplication trigger, and is lifted onto ONE trait method here). THEORY.md §II.1 invariant 5 (composition preserves proofs — the pins bind the missing-annotations corner + the missing-key corner + the borrow-form &str lifetime + the byte-identical parity with the pre-lift 3-line chain + the cross-primitive coherence with Process::annotation on the SAME Process value, so a regression that skewed either surface surfaces at annotated_tests::* rather than as silent operator- facing skew between the SIGNAL / RELEASED_FROM / POOL annotation readers on Process and the receipts-owner filter on ConfigMap).

Provided Methods§

Source

fn annotation(&self, key: &str) -> Option<&str>

Borrow one key from metadata.annotations. See the trait-level docs for the axis-family context, peer inherent method, and future-normalization anchor.

Dyn Compatibility§

This trait is not dyn compatible.

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

Implementors§

Source§

impl<T> Annotated for T
where T: Resource<DynamicType = ()>,