pub struct Lifetime {
pub permanent: Option<PermanentLifetime>,
pub ephemeral: Option<EphemeralLifetime>,
}Expand description
Lifetime slot on ProcessSpec. Exactly one variant should be populated;
when both are unset the resolver returns Permanent.
Fields§
§permanent: Option<PermanentLifetime>§ephemeral: Option<EphemeralLifetime>Implementations§
Source§impl Lifetime
impl Lifetime
Sourcepub fn is_default(&self) -> bool
pub fn is_default(&self) -> bool
True when no variant is set — treated as Permanent by the resolver.
Sourcepub fn permanent() -> Self
pub fn permanent() -> Self
Permanent-only Lifetime — the permanent slot is populated with
the zero-sized PermanentLifetime marker and the ephemeral slot
is None. Peer of Self::ephemeral on the LifetimeKind closed
set; the two composers between them cover every non-ambiguous
non-empty corner of the two-slot tagged-union wire shape.
Pre-lift the 4-token Lifetime { permanent: Some(PermanentLifetime {}), ephemeral: None } (equivalently Lifetime { permanent: Some(PermanentLifetime {}), ..Lifetime::default() }) fixture
literal was hand-authored at FOUR workspace-wide sites past the
★★ PRIME-DIRECTIVE ≥ 2 duplication threshold:
- [
crate::crd::tests::permanent_only_process] —Processfixture with the permanent-only lifetime slot for theresolved_ephemeralprojection test matrix. - [
tests::resolved_ephemeral_projects_only_the_unambiguous_ephemeral_slot] — the “Permanent-only” branch of the same matrix in this module. - [
tests::single_slot_lifetime] — closed-set helper’sPermanentarm, shared across property tests that walkLifetimeKind::ALL. tatara-pool-reconciler::controller_pool::process_from_template— production seed of a pool-member Process’s lifetime slot on the fork path (Pool member starts Permanent; allocation flips it).
Post-lift every callsite reads Lifetime::permanent() and the
substrate owns the shape. A future normalization (a warn-log on
callers that construct a permanent-only lifetime past a hardening
window, an audit trail that stamps a compile-generation onto the
zero-sized PermanentLifetime, or a deprecation of the empty
marker in favor of a richer permanent variant) lands at THIS ONE
substrate function and every downstream consumer inherits the
upgrade mechanically.
The ambiguous corner (both permanent AND ephemeral set) is
deliberately NOT reachable through this composer — the composer’s
contract is “the resolver picks Permanent”, and an ambiguous
Lifetime resolves to LifetimeError::Ambiguous, not to
Permanent. Tests that exercise the ambiguous corner (e.g.
[crate::crd::tests::ambiguous_lifetime_process],
[tests::ambiguous_lifetime_errors]) stay hand-authored as
struct literals — they need to violate the “exactly one slot”
invariant this composer preserves.
Sibling composer: Self::ephemeral on the Ephemeral arm of
the same LifetimeKind closed set.
Theory anchor: THEORY.md §VI.1 (generation over composition —
the Lifetime { permanent: Some(PermanentLifetime {}), .. }
shape recurred at four hand-authored sites past the ★★
PRIME-DIRECTIVE ≥ 2 duplication trigger, and is lifted to ONE
owner here). THEORY.md §II.1 invariant 5 (composition preserves
proofs — the pins bind the resolved-variant corner AND the
discriminator kind AND the round-trip through Self::variant
so a regression that drifted any surface fails at
tests::permanent_composer_* here rather than as silent
operator-facing skew between the fork-path production seed and
the test-side fixture literals).
Sourcepub fn ephemeral(e: EphemeralLifetime) -> Self
pub fn ephemeral(e: EphemeralLifetime) -> Self
Ephemeral-only Lifetime — the ephemeral slot is populated
with the supplied EphemeralLifetime and the permanent slot
is None. Peer of Self::permanent on the LifetimeKind
closed set.
Pre-lift the 4-token Lifetime { permanent: None, ephemeral: Some(<e>) } (equivalently Lifetime { ephemeral: Some(<e>), ..Lifetime::default() }) fixture literal was hand-authored at
ELEVEN+ workspace-wide sites past the ★★ PRIME-DIRECTIVE ≥ 2
duplication threshold, split across production seeds
(tatara-process::ephemeral::From<EphemeralSpec> for ProcessSpec
— the (defephemeral …) Lisp form’s typed lowering;
tatara-pool-reconciler::controller_allocation — the allocator
Bind arm flipping a pool-member Process from Permanent to
Ephemeral with the requestor’s TTL) and test fixtures across
crate::crd, crate::lifetime_clock, this module,
tatara-pool-reconciler, and tatara-reconciler::render.
Post-lift every callsite reads Lifetime::ephemeral(<e>) and
the substrate owns the shape. A future normalization (a
per-fleet TTL floor stamp before storing the inner
EphemeralLifetime, an audit trail that records the composed
lifetime’s provenance, a shared warn on empty exports at
Attested-terminal phases) lands at THIS ONE substrate function
and every downstream consumer inherits the upgrade mechanically.
Return-form axis: takes an owned EphemeralLifetime rather
than a &EphemeralLifetime, matching every current caller
(each constructs the inner EphemeralLifetime directly at the
call site as a rvalue-shape struct literal, then hands it to
the composer).
The ambiguous corner (both slots set) is NOT reachable through
this composer — see Self::permanent’s docs for the parity
with the peer + the rationale for keeping ambiguous-corner
tests as hand-authored struct literals.
Sibling composer: Self::permanent on the Permanent arm of
the same LifetimeKind closed set.
Theory anchor: same as Self::permanent — THEORY.md §VI.1
(generation over composition) + §II.1 invariant 5 (composition
preserves proofs).
Sourcepub fn variant(&self) -> Result<LifetimeVariant<'_>, LifetimeError>
pub fn variant(&self) -> Result<LifetimeVariant<'_>, LifetimeError>
Resolve to a variant view. Empty resolves to Permanent (a static
borrow on the embedded DEFAULT_PERMANENT); ambiguous (both set) is
an error.
Sweeps over LifetimeKind::ALL so a third variant added with an
ALL entry is structurally honored at this site — no parallel
is_some() count, no per-variant if-let chain.
Sourcepub fn is_ephemeral(&self) -> bool
pub fn is_ephemeral(&self) -> bool
True iff ephemeral is set.
Sourcepub fn resolved_ephemeral(&self) -> Option<&EphemeralLifetime>
pub fn resolved_ephemeral(&self) -> Option<&EphemeralLifetime>
Compound projection: Some(&e) iff Self::variant resolves
unambiguously to Ephemeral(e); None for every other outcome
(empty → Permanent default, Permanent slot only, or
LifetimeError::Ambiguous when BOTH slots are set).
The ambiguous case is deliberately collapsed to None: an
operator-authored spec with both permanent: and ephemeral:
populated is a mis-configuration, and every production consumer
of the pair crate::lifetime_clock::evaluate +
crate::lifetime_clock::requeue_with_ttl previously
hand-rolled the SAME two-step projection
(variant().ok()?.as_ephemeral()) whose Err-arm and
Permanent-arm both fell through to the same “no ephemeral
action” outcome (AutoTerminate::Skip / default requeue).
Lifting that chained collapse to ONE substrate primitive puts
“the ephemeral spec now, iff the resolver picked it” behind a
single call site and closes the possibility of a per-consumer
drift where one branch honors ambiguity and the other doesn’t.
A future third variant added to Lifetime (e.g. Burst for
budget-capped non-TTL lifetimes) reaches this projection
through the SAME Self::variant resolver + the SAME
LifetimeVariant::as_ephemeral discriminator, so the
ephemeral-only projection stays intact without a new arm here.
Pinned by
resolved_ephemeral_projects_only_the_unambiguous_ephemeral_slot.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Lifetime
impl<'de> Deserialize<'de> for Lifetime
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl JsonSchema for Lifetime
impl JsonSchema for Lifetime
Source§fn schema_name() -> String
fn schema_name() -> String
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn is_referenceable() -> bool
fn is_referenceable() -> bool
$ref keyword. Read moreAuto Trait Implementations§
impl Freeze for Lifetime
impl RefUnwindSafe for Lifetime
impl Send for Lifetime
impl Sync for Lifetime
impl Unpin for Lifetime
impl UnsafeUnpin for Lifetime
impl UnwindSafe for Lifetime
Blanket Implementations§
impl<T> AppData for Twhere
T: OptionalSend + OptionalSync + 'static + OptionalSerde,
impl<T> AppDataResponse for Twhere
T: OptionalSend + OptionalSync + 'static + OptionalSerde,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreimpl<T> OptionalSend for T
impl<T> OptionalSync for T
Source§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi Quirk value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);