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§
Sourcefn annotation(&self, key: &str) -> Option<&str>
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".