caixa_core/version.rs
1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4use thiserror::Error;
5
6/// A caixa's pinned version — a thin typed wrapper over a String that parses
7/// as [`semver::Version`] on demand.
8///
9/// Stored as a String at rest so authoring a `caixa.lisp` stays a single
10/// quoted literal. The typed form is reached through [`Self::parse`].
11#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
12#[serde(transparent)]
13pub struct CaixaVersion(pub String);
14
15impl CaixaVersion {
16 /// Parse and validate the wrapped string as semver.
17 pub fn parse(&self) -> Result<semver::Version, VersionError> {
18 semver::Version::parse(&self.0)
19 .map_err(|e| VersionError::semver(self.0.clone(), e.to_string()))
20 }
21
22 /// Borrow the string form.
23 #[must_use]
24 pub const fn as_str(&self) -> &str {
25 self.0.as_str()
26 }
27}
28
29impl fmt::Display for CaixaVersion {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 f.write_str(&self.0)
32 }
33}
34
35impl From<String> for CaixaVersion {
36 fn from(s: String) -> Self {
37 Self(s)
38 }
39}
40
41impl From<&str> for CaixaVersion {
42 fn from(s: &str) -> Self {
43 Self(s.to_string())
44 }
45}
46
47/// Substrate-canonical [`AsRef<str>`] projection on the [`CaixaVersion`]
48/// typed newtype — routes through the same [`CaixaVersion::as_str`]
49/// `pub const fn` scalar accessor the sibling [`fmt::Display`] impl
50/// and every downstream `&str`-shaped consumer already keys off, so
51/// any future consumer that binds a [`CaixaVersion`] through the
52/// standard-library `impl AsRef<str>` bound (a `Path`-shaped file-
53/// system reader on the operator side that accepts the version body
54/// as one segment of a per-caixa `versao/<v>/...` on-disk cache path,
55/// a builder-shaped API on the future `feira publish` writer verb
56/// that composes `<prefix><versao>` through a git-tag builder crate's
57/// `impl AsRef<str>` join step, a `HashMap<CaixaVersion, _>` lookup
58/// through the `map.get::<str>(v.as_ref())` shape a future
59/// version-keyed dispatch table lands on) reaches the wrapped
60/// [`String`] through one substrate-primitive dispatch rather than
61/// through the pre-lift `.as_str()` open-coded projection at every
62/// wire-up.
63///
64/// Peer of the sibling [`fmt::Display`] impl on the same primitive —
65/// both delegate to the shared [`CaixaVersion::as_str`] `pub const
66/// fn` accessor, so [`format!("{v}")`], `v.as_str()`, and
67/// `<CaixaVersion as AsRef<str>>::as_ref(&v)` resolve to the same
68/// byte-string per instance by construction. A future rebrand of the
69/// wrapped storage (a hypothetical widening to a typed [`semver::Version`]
70/// slot the roadmap acknowledges once eager parse-on-construct
71/// discipline lands, an internal normalization step that trims
72/// leading zeroes off pre-release identifiers, a per-cluster overlay
73/// the operator pins through a future `:versao-overrides` slot) that
74/// changes what [`CaixaVersion::as_str`] returns migrates every
75/// consumer of every one of the three paths in lockstep.
76///
77/// Same "route the trait impl through the substrate-primitive
78/// accessor" discipline the sibling [`fmt::Display`] impl on this
79/// type already carries — extends it onto the standard-library
80/// [`AsRef<str>`] projection axis every third-party API that takes
81/// `impl AsRef<str>` (the [`std::path::Path::new`] / [`std::fs`]
82/// interop surface, [`std::process::Command::arg`], the peer
83/// `tracing::field::Value` recorder's `Str`-arm, every `clap`-side
84/// `value_parser!` fold that accepts an owned newtype through
85/// `impl AsRef<str>`) already binds through. Rust-side newtype
86/// convention pairs `AsRef<str>` and [`fmt::Display`] on the same
87/// primitive so a caller who has one has both; before this lift,
88/// [`CaixaVersion`] carried [`fmt::Display`] but not the paired
89/// [`AsRef<str>`] impl the convention names.
90///
91/// The first standard-library trait added to [`CaixaVersion`] beyond
92/// the pre-existing [`serde::Serialize`] / [`serde::Deserialize`] /
93/// [`Debug`] / [`Clone`] / [`PartialEq`] / [`Eq`] / [`Hash`] derives
94/// and the paired [`fmt::Display`] / [`From<String>`] / [`From<&str>`]
95/// hand-written impls. Pinned load-bearing by
96/// [`tests::caixa_version_as_ref_str_routes_through_as_str_accessor`]
97/// (byte-parity pin against [`CaixaVersion::as_str`]) — any future
98/// silent detour that routes the impl through a divergent projection
99/// (a `Cow<'_, str>` intermediate, a stray `.to_lowercase()`
100/// normalization, a swap onto a per-arm inline `&self.0.as_str()`
101/// re-inlining) trips at caixa-core test time under `assert_eq!`
102/// rather than at a downstream `impl AsRef<str>`-bound consumer's
103/// silent split.
104impl AsRef<str> for CaixaVersion {
105 fn as_ref(&self) -> &str {
106 self.as_str()
107 }
108}
109
110/// Trait-idiomatic *HashMap-key-shaped* borrow projection on the
111/// [`CaixaVersion`] newtype primitive — the standard-library
112/// [`std::borrow::Borrow<str>`] companion to the paired sibling
113/// [`AsRef<str>`] impl (a086 lift) on the same borrow-projection axis of
114/// this primitive. Routes byte-for-byte through the substrate-primitive
115/// [`CaixaVersion::as_str`] `pub const fn` accessor — the same accessor
116/// the paired [`AsRef<str>`] and [`fmt::Display`] impls already delegate
117/// through — so every consumer that binds a [`CaixaVersion`] through the
118/// standard-library `Borrow<str>` bound reaches the wrapped byte-string
119/// through one substrate-primitive dispatch rather than through a
120/// pre-lift `.as_str()` open-coded projection at every wire-up.
121///
122/// A future consumer that wants to key a map or set by
123/// [`CaixaVersion`] and look up entries by a borrowed [`&str`] — a
124/// per-`:versao` compatibility matrix `HashMap<CaixaVersion, PolicyRow>`
125/// where the reconciliation loop's per-cycle `.get(current_versao_str)`
126/// probes the map with the raw `&str` view of the current cluster
127/// snapshot's version body (the `HashMap::get<Q: ?Sized>` signature is
128/// `where K: Borrow<Q>, Q: Hash + Eq`; without this impl the caller must
129/// wrap the borrowed `&str` in a fresh [`CaixaVersion`] allocation on
130/// every probe), a future `BTreeMap<CaixaVersion, _>::range(..)` sweep
131/// over a per-versao index that accepts a borrowed `&str` range bound
132/// through the same `Borrow<str>` bound, a
133/// `HashSet<CaixaVersion>::contains(&str)` membership probe on a
134/// per-versao denylist keyed by owned [`CaixaVersion`] but queried by
135/// the borrowed view — reaches the wrapped byte-string through this one
136/// dispatch on the substrate primitive, without the pre-lift
137/// `CaixaVersion::from(<&str>)` per-probe allocation the paired forward
138/// [`From<&str> for CaixaVersion`] constructor would otherwise force at
139/// every lookup site.
140///
141/// Peer of the sibling [`AsRef<str>`] impl on the same borrow-projection
142/// axis — both project a borrowed `&self` binding onto a borrowed `&str`
143/// via the shared substrate-primitive [`CaixaVersion::as_str`] accessor.
144/// Rust's standard library deliberately splits the two trait axes on the
145/// two bounds they carry: [`AsRef<str>`] is the *conversion* bound used
146/// by APIs that accept `impl AsRef<str>` and view the input as a `&str`
147/// projection (the [`std::path::Path::new`] / [`std::fs`] interop
148/// surface, [`std::process::Command::arg`], [`clap`]-side
149/// `value_parser!` folds), while [`std::borrow::Borrow<str>`] is the
150/// stricter *identity* bound the collection APIs
151/// ([`std::collections::HashMap`], [`std::collections::BTreeMap`],
152/// [`std::collections::HashSet`], [`std::collections::BTreeSet`]) key
153/// their lookup surfaces off — [`std::borrow::Borrow`] additionally
154/// promises that a borrowed view produced through [`Borrow::borrow`]
155/// hashes and compares byte-identically to the owned form, which is the
156/// contract [`std::collections::HashMap::get`] relies on when it hashes
157/// the query key through `Q` (`str`) and matches against slot keys
158/// hashed through `K` ([`CaixaVersion`]). The [`CaixaVersion`] newtype
159/// meets that contract by construction: the derived [`Hash`] impl hashes
160/// the wrapped [`String`] field, which (through the standard-library
161/// `impl Hash for String { fn hash(...) { (**self).hash(...) } }`
162/// pass-through) dispatches to [`str::hash`] on the raw bytes — the same
163/// dispatch a direct `.hash()` on the `&str` returned by
164/// [`Self::borrow`] would take. The derived [`PartialEq`] and [`Eq`]
165/// impls compare field-wise (byte-equal on the wrapped [`String`]), so
166/// `cv1 == cv2` reduces to `cv1.borrow() == cv2.borrow()` at the
167/// `&str`-projection axis. Both invariants — hash-agrees and
168/// eq-agrees — hold structurally, so this impl is sound under the
169/// [`std::borrow::Borrow`] documented safety contract.
170///
171/// Same "one substrate-primitive dispatch, one shared accessor" discipline
172/// the paired [`AsRef<str>`] impl on this primitive already carries —
173/// extends it onto the [`std::borrow::Borrow<str>`] projection axis the
174/// standard-library collection APIs key their `.get::<Q>` /
175/// `.contains::<Q>` / `.range::<R, T>` / `.remove::<Q>` lookup surfaces
176/// off. Rust's standard library mirrors this exact pairing on its own
177/// [`String`] primitive (`impl AsRef<str> for String` +
178/// `impl Borrow<str> for String`), so a newtype that carries one axis
179/// but not the other splits off the convention that lets every
180/// [`String`]-shaped consumer swap the newtype in without re-shaping
181/// its bounds.
182///
183/// Pinned load-bearing by
184/// [`tests::caixa_version_borrow_str_routes_through_as_str_accessor`]
185/// (byte-parity pin against [`CaixaVersion::as_str`] on the same
186/// instance),
187/// [`tests::caixa_version_borrow_str_and_as_ref_str_agree_on_every_shape`]
188/// (cross-axis partition pin against the paired [`AsRef<str>`] impl,
189/// closing the "borrow-axis two-corner split" bifurcation on the same
190/// wrapped body), and
191/// [`tests::caixa_version_borrow_str_enables_hashmap_lookup_by_borrowed_key`]
192/// (contract-witness pin routing a [`std::collections::HashMap::get`]
193/// probe against a `&str` key through the `Borrow<str>` bound on a map
194/// keyed by owned [`CaixaVersion`], asserting the collection APIs reach
195/// the same slot the borrowed and owned forms compose the same hash for).
196impl std::borrow::Borrow<str> for CaixaVersion {
197 fn borrow(&self) -> &str {
198 self.as_str()
199 }
200}
201
202/// Trait-idiomatic *owned-`String`* reverse projection on the
203/// [`CaixaVersion`] newtype primitive — the owned-heap-string inverse
204/// of the pre-existing [`From<String> for CaixaVersion`] /
205/// [`From<&str> for CaixaVersion`] forward-projection pair on this
206/// primitive. Returns the wrapped [`String`] verbatim ([`Self::0`],
207/// a move of the pre-existing heap allocation — no re-copy of the
208/// per-instance version body's bytes), so every consumer that binds a
209/// [`CaixaVersion`] through the standard-library `.into()` /
210/// [`From<Self> for String`] (equivalently [`Into<String>`]) axis
211/// reaches the wrapped byte-string through one substrate-primitive
212/// dispatch rather than through a `.as_str().to_owned()` /
213/// `.to_string()` allocating detour whose bounds have no compile-time
214/// link back to the newtype's storage.
215///
216/// A future consumer that wants to unwrap a [`CaixaVersion`] into an
217/// owned [`String`] — a `serde_json::Value::String(versao.into())`
218/// structured-payload composer where the `Value::String` arm typing
219/// demands an owned [`String`] and the sibling
220/// [`AsRef<str>`]-borrowed axis forces an explicit `.to_owned()`
221/// restatement at every call site, a future
222/// `HashMap::<String, _>::from_iter([(versao.into(), _)])` per-versao
223/// lookup where the map's key type is owned [`String`] rather than
224/// [`&str`] borrowed from a stashed [`CaixaVersion`], a future
225/// `Cow::<'static, str>::Owned(versao.into())` composer where the
226/// owned arm typing rules out the borrowed [`AsRef<str>`] return —
227/// reaches the wrapped [`String`] through this one dispatch, avoiding
228/// the pre-lift double-allocation (`.as_str().to_owned()` on the owned
229/// path would allocate a fresh [`String`] rather than reuse the
230/// wrapper's own heap allocation).
231///
232/// Opens the trait-idiomatic *owned-`String`* reverse-projection axis
233/// on the substrate's core String-wrapper newtype primitive
234/// [`CaixaVersion`], mirroring the paired owned-`String` forward-
235/// projection family the sibling closed-set fieldless typed enums
236/// ([`crate::supervisor::RestartStrategy`] (7baa18a, first-mover),
237/// [`crate::supervisor::RestartPolicy`] (7851725),
238/// [`crate::CaixaKind`] (per its own doc block, third peer), plus the
239/// remaining twelve closed-set enums) already carry — Rust's standard
240/// library does not derive `From<Self> for String` from `From<String>
241/// for Self`, so every newtype that carries a forward `From<String>`
242/// constructor but not the paired reverse-unwrap axis forces every
243/// call site through a `.to_string()` / `.as_str().to_owned()` detour
244/// that allocates fresh bytes rather than moving the wrapper's own
245/// heap allocation.
246///
247/// Preserves the two-path split on the wrapped byte-string: the paired
248/// [`AsRef<str>`] and [`fmt::Display`] impls stay reachable for the
249/// borrowed `&str` and formatter-output paths, this impl closes the
250/// owned-`String` reverse axis. Same "one dispatch on the substrate
251/// primitive" discipline the peer forward `From<String> for
252/// CaixaVersion` / `From<&str> for CaixaVersion` constructors carry,
253/// now extended onto the owned-heap-string reverse projection.
254///
255/// Pinned load-bearing by
256/// [`tests::caixa_version_from_into_owned_string_returns_wrapped_body`]
257/// (byte-parity pin against [`CaixaVersion::as_str`] on the same
258/// instance) and
259/// [`tests::caixa_version_from_into_owned_string_and_as_str_agree_on_every_shape`]
260/// (cross-axis partition pin against the paired borrowed
261/// [`AsRef<str>`] impl and the sibling [`fmt::Display`]-routed
262/// [`ToString::to_string`] surface, plus a round-trip witness through
263/// the paired forward [`From<String> for CaixaVersion`] constructor
264/// closing the two-way `Self → String → Self` cycle by construction).
265impl From<CaixaVersion> for String {
266 fn from(v: CaixaVersion) -> String {
267 v.0
268 }
269}
270
271/// Trait-idiomatic *borrowed-input, owned-`String` output* reverse
272/// projection on the [`CaixaVersion`] newtype primitive — the
273/// borrowed-input companion to the paired owned-input
274/// [`From<CaixaVersion> for String`] impl immediately above. Routes
275/// byte-for-byte through the substrate-primitive
276/// [`CaixaVersion::as_str`] `pub const fn` accessor (via
277/// [`str::to_owned`]) so every consumer that holds a
278/// borrowed [`&CaixaVersion`] and needs an owned [`String`] — a
279/// `[…].iter().map(String::from).collect::<Vec<_>>()` per-instance
280/// materializer over `&[CaixaVersion]` (whose iterator yields
281/// `&CaixaVersion`, not `CaixaVersion`, so the owned-input
282/// [`From<CaixaVersion> for String`] axis alone forces every call site
283/// through an explicit `.clone()` / dereference restatement), a future
284/// `HashMap::<String, _>::from_iter` that keys off a borrowed-
285/// iteration axis where cloning the wrapper would allocate one
286/// [`String`] beyond the map entry's own, a future
287/// `serde_json::Value::String(String::from(&caixa.versao))`
288/// structured-payload composer that owns the emit-path without moving
289/// out of a borrowed field — reaches the wrapped byte-string through
290/// this one dispatch on the substrate primitive.
291///
292/// Second corner on the `{Self, &Self} → String` reverse-projection
293/// family opened on the paired owned-input
294/// [`From<CaixaVersion> for String`] impl immediately above. Rust's
295/// `From` trait does not derive the `From<&Self>` sibling from a
296/// `From<Self>` impl (the blanket
297/// `impl<T, U> From<&T> for U where T: Clone, U: From<T>` does not
298/// exist in `core`), so every newtype that carries the owned-input
299/// reverse axis but not the borrowed-input axis forces every borrowed
300/// call site through a `.clone()` / `<String>::from(v.clone())` detour
301/// whose type bounds have no compile-time link back to the newtype.
302///
303/// Pinned load-bearing by
304/// [`tests::caixa_version_from_borrowed_into_owned_string_routes_through_as_str_accessor`]
305/// (byte-parity pin against [`CaixaVersion::as_str`] via a borrowed
306/// input) and
307/// [`tests::caixa_version_from_owned_and_borrowed_into_string_agree_on_every_shape`]
308/// (cross-axis partition pin against the paired owned-input
309/// [`From<CaixaVersion> for String`] impl on the same instance,
310/// closing the "owned-input move vs. borrowed-input clone" bifurcation
311/// on the same wrapped body).
312impl From<&CaixaVersion> for String {
313 fn from(v: &CaixaVersion) -> String {
314 v.as_str().to_owned()
315 }
316}
317
318/// Trait-idiomatic *owned-input, [`std::borrow::Cow<'static, str>`]
319/// output* reverse projection on the [`CaixaVersion`] newtype
320/// primitive — the [`Cow<'static, str>`] companion to the paired
321/// owned-input [`From<CaixaVersion> for String`] impl (999a310) on
322/// the same primitive. Routes through
323/// [`std::borrow::Cow::Owned`]`(v.0)`, moving the wrapper's own heap
324/// allocation through verbatim (no re-copy of the per-instance version
325/// body's bytes, no allocating detour through
326/// [`CaixaVersion::as_str`] + [`str::to_owned`]) — so every consumer
327/// that binds a [`CaixaVersion`] through the standard-library `.into()`
328/// / [`From<Self> for Cow<'static, str>`] axis reaches the wrapped
329/// byte-string through one substrate-primitive dispatch on the exact
330/// same heap allocation the manifest-parse forward
331/// [`From<String> for CaixaVersion`] constructor accepted.
332///
333/// A future consumer that wants a [`Cow<'static, str>`]-typed handle
334/// on a [`CaixaVersion`] — a
335/// `metric_label: Cow<'static, str> = versao.into()` structured-log
336/// key on a future per-caixa `caixa-operator` reconciliation counter
337/// (whose emit surface types metric keys as `Cow<'static, str>` so
338/// static compile-time literals and dynamic version bodies share the
339/// same key-slot without an unconditional heap allocation on the
340/// literal path), a future
341/// `HashMap::<Cow<'static, str>, _>::from_iter([(versao.into(), _)])`
342/// per-versao lookup where the map's key type is
343/// [`Cow<'static, str>`] rather than owned [`String`] so
344/// literal-lifetime keys can share the same map without wrapping in an
345/// extra [`String`] allocation, a future M4 admission-webhook
346/// rejection body whose per-arm error message composes through
347/// `format!("{}", Cow::<'static, str>::from(caixa.versao))` where the
348/// [`Cow<'static, str>`] intermediate is what the sibling error-frame
349/// composer accepts — reaches the wrapped byte-string through this
350/// one dispatch, without the pre-lift `.to_string().into()` /
351/// `Cow::Owned(String::from(v))` double-hop that would allocate a
352/// fresh intermediary [`String`] on the way to the same
353/// [`Cow::Owned`] arm.
354///
355/// Deliberately returns [`std::borrow::Cow::Owned`] rather than
356/// [`std::borrow::Cow::Borrowed`] — the substrate-primitive
357/// [`CaixaVersion::as_str`] accessor's return does not carry the
358/// `&'static str` lifetime by construction (the wrapped [`String`]
359/// storage is a runtime heap allocation, not a compile-time literal),
360/// so the [`Cow<'static, str>`] output shape rules out the borrowed
361/// arm and the owned arm is the type-correct projection. Peer of the
362/// paired owned-input [`From<CaixaVersion> for String`] impl on the
363/// same primitive — both route through the wrapper's own heap
364/// allocation via a move on `v.0`, preserving the zero-copy
365/// discipline the substrate opens on its String-wrapper newtype
366/// primitive.
367///
368/// Opens the trait-idiomatic *owned-input, [`Cow<'static, str>`]*
369/// reverse-projection axis on the substrate's core String-wrapper
370/// newtype primitive [`CaixaVersion`], mirroring the paired
371/// [`Cow<'static, str>`] *forward*-projection family the sibling
372/// closed-set fieldless typed enums (via
373/// [`crate::supervisor::RestartStrategy`],
374/// [`crate::supervisor::RestartPolicy`], and the remaining twelve
375/// closed-set enums) already carry — on the enum peers, the paired
376/// axis returns [`Cow::Borrowed`] because the accessor returns
377/// `&'static str`; on this newtype the paired axis returns
378/// [`Cow::Owned`] because the wrapped storage is runtime-allocated.
379/// Rust's standard library does not derive `From<Self> for
380/// Cow<'static, str>` from `From<Self> for String` (nor derive
381/// `From<&Self>` from `From<Self>`), so every newtype that carries a
382/// reverse `From<Self> for String` unwrap axis but not the paired
383/// [`Cow<'static, str>`] axis forces every
384/// [`Cow<'static, str>`]-typed call site through a `.to_string().into()`
385/// double-allocation detour that heap-allocates a fresh intermediary
386/// [`String`] between the wrapper and the [`Cow::Owned`] arm.
387///
388/// Pinned load-bearing by
389/// [`tests::caixa_version_from_into_owned_cow_str_returns_owned_wrapped_body`]
390/// (byte-parity + [`Cow::Owned`]-arm pin against
391/// [`CaixaVersion::as_str`] on the same instance, plus a round-trip
392/// witness through the paired [`From<String> for CaixaVersion`]
393/// constructor) and
394/// [`tests::caixa_version_from_into_owned_cow_str_and_string_agree_on_every_shape`]
395/// (cross-axis partition pin against the paired owned-input
396/// [`From<CaixaVersion> for String`] impl on the same instance,
397/// closing the "owned-input into [`String`] vs. owned-input into
398/// [`Cow<'static, str>`]" bifurcation on the same wrapped body).
399impl From<CaixaVersion> for std::borrow::Cow<'static, str> {
400 fn from(v: CaixaVersion) -> std::borrow::Cow<'static, str> {
401 std::borrow::Cow::Owned(v.0)
402 }
403}
404
405/// Trait-idiomatic *borrowed-input, [`std::borrow::Cow<'static, str>`]
406/// output* reverse projection on the [`CaixaVersion`] newtype
407/// primitive — the borrowed-input companion to the paired owned-input
408/// [`From<CaixaVersion> for std::borrow::Cow<'static, str>`] impl
409/// immediately above. Routes byte-for-byte through the
410/// substrate-primitive [`CaixaVersion::as_str`] `pub const fn`
411/// accessor (via [`str::to_owned`] wrapped in
412/// [`std::borrow::Cow::Owned`]) so every consumer that holds a
413/// borrowed [`&CaixaVersion`] and needs a [`Cow<'static, str>`] —
414/// a `[…].iter().map(Cow::<'static, str>::from).collect::<Vec<_>>()`
415/// per-instance materializer over `&[CaixaVersion]` (whose iterator
416/// yields `&CaixaVersion`, not `CaixaVersion`, so the paired
417/// owned-input [`From<CaixaVersion> for Cow<'static, str>`] axis
418/// alone forces every call site through an explicit `.clone()` /
419/// dereference restatement), a future
420/// `HashMap::<Cow<'static, str>, _>::from_iter` that keys off a
421/// borrowed-iteration axis where cloning the wrapper would allocate
422/// one [`String`] beyond the eventual [`Cow::Owned`] arm's own, a
423/// future generic
424/// `<T: for<'a> Into<Cow<'static, str>>>`-bound emitter on a
425/// per-caixa diagnostic column that walks the
426/// `iter().map(Into::into)` shape verbatim — reaches the wrapped
427/// byte-string through this one dispatch on the substrate primitive.
428///
429/// Deliberately returns [`std::borrow::Cow::Owned`] rather than
430/// [`std::borrow::Cow::Borrowed`] — the substrate-primitive
431/// [`CaixaVersion::as_str`] accessor's return does not carry the
432/// `&'static str` lifetime by construction, so the
433/// [`Cow<'static, str>`] output shape rules out the borrowed arm and
434/// the owned arm is the type-correct projection (mirroring the paired
435/// owned-input impl's own [`Cow::Owned`] discipline). Second corner
436/// on the `{Self, &Self} → Cow<'static, str>` reverse-projection
437/// family opened on the paired owned-input impl immediately above.
438/// Rust's `From` trait does not derive the `From<&Self>` sibling from
439/// a `From<Self>` impl (the blanket
440/// `impl<T, U> From<&T> for U where T: Clone, U: From<T>` does not
441/// exist in `core`), so every newtype that carries the owned-input
442/// reverse [`Cow<'static, str>`] axis but not the borrowed-input axis
443/// forces every borrowed call site through a `.clone()` /
444/// `<Cow<'static, str>>::from(v.clone())` detour whose type bounds
445/// have no compile-time link back to the newtype.
446///
447/// Pinned load-bearing by
448/// [`tests::caixa_version_from_borrowed_into_owned_cow_str_routes_through_as_str_accessor`]
449/// (byte-parity + [`Cow::Owned`]-arm pin against
450/// [`CaixaVersion::as_str`] via a borrowed input, plus a
451/// source-survival witness against silent move-out) and
452/// [`tests::caixa_version_from_owned_and_borrowed_into_cow_str_agree_on_every_shape`]
453/// (cross-axis partition pin against the paired owned-input impl on
454/// the same instance, closing the "owned-input move vs. borrowed-input
455/// clone" bifurcation on the same wrapped body through the
456/// [`Cow<'static, str>`] axis).
457impl From<&CaixaVersion> for std::borrow::Cow<'static, str> {
458 fn from(v: &CaixaVersion) -> std::borrow::Cow<'static, str> {
459 std::borrow::Cow::Owned(v.as_str().to_owned())
460 }
461}
462
463/// Trait-idiomatic *owned-input, [`Box<str>`] output* reverse projection
464/// on the [`CaixaVersion`] newtype primitive — the [`Box<str>`] companion
465/// to the paired owned-input [`From<CaixaVersion> for String`] (999a310)
466/// and [`From<CaixaVersion> for std::borrow::Cow<'static, str>`] (55532e5)
467/// impls on the same primitive. Routes through
468/// [`String::into_boxed_str`]`(v.0)`, shrinking the wrapper's own heap
469/// allocation to a fit-to-length boxed slice — no re-copy of the
470/// per-instance version body's bytes on the fixed-capacity path
471/// (`String::into_boxed_str` reuses the underlying `Vec<u8>` buffer
472/// verbatim when the length matches its capacity; when the [`String`]
473/// carries slack it reallocates once to shrink), so every consumer that
474/// binds a [`CaixaVersion`] through the standard-library `.into()` /
475/// [`From<Self> for Box<str>`] axis reaches the wrapped byte-string
476/// through one substrate-primitive dispatch on the same underlying heap
477/// storage the manifest-parse forward [`From<String> for CaixaVersion`]
478/// constructor accepted.
479///
480/// A future consumer that wants a [`Box<str>`]-typed handle on a
481/// [`CaixaVersion`] — a per-caixa struct field typed `Box<str>` rather
482/// than [`String`] to trim the sixteen-byte length + capacity header
483/// down to eight bytes on the pointer + length pair (a shape the
484/// substrate acknowledges as the natural fixed-length storage for
485/// once-written-never-mutated version strings held across the whole
486/// operator reconciliation cycle), a future
487/// `HashMap::<Box<str>, _>::from_iter([(versao.into(), _)])` per-versao
488/// lookup where the map's key type is [`Box<str>`] rather than owned
489/// [`String`] so the map's per-entry key-slot carries the sixteen-byte
490/// [`Box<str>`] header instead of the twenty-four-byte [`String`]
491/// header, a future M4 admission-webhook rejection body whose per-arm
492/// error-frame composer accepts a [`Box<str>`] intermediate for the
493/// same reason — reaches the wrapped byte-string through this one
494/// dispatch, without the pre-lift `.to_string().into_boxed_str()`
495/// double-hop that would allocate a fresh intermediary [`String`] on
496/// the way to the same [`Box<str>`] slot.
497///
498/// Peer of the paired owned-input [`From<CaixaVersion> for String`]
499/// (999a310) and [`From<CaixaVersion> for Cow<'static, str>`] (55532e5)
500/// impls on the same primitive — all three route through `v.0`
501/// (the [`String`] axis returns the wrapped buffer verbatim; the
502/// [`Cow<'static, str>`] axis wraps it in [`Cow::Owned`]; this axis
503/// shrinks it to a fit-to-length boxed slice via [`String::into_boxed_str`]),
504/// preserving the zero-copy discipline the substrate opens on its
505/// String-wrapper newtype primitive across the three reverse-projection
506/// axes. Rust's standard library does not derive `From<Self> for
507/// Box<str>` from `From<Self> for String` (nor from `From<Self> for
508/// Cow<'static, str>`), so every newtype that carries the paired
509/// reverse `From<Self> for String` axis but not the paired
510/// [`Box<str>`] axis forces every [`Box<str>`]-typed call site through
511/// a `.to_string().into_boxed_str()` double-allocation detour that
512/// heap-allocates a fresh intermediary [`String`] between the wrapper
513/// and the [`Box<str>`] slot.
514///
515/// Opens the trait-idiomatic *owned-input, [`Box<str>`]*
516/// reverse-projection axis on the substrate's core String-wrapper
517/// newtype primitive [`CaixaVersion`], extending the reverse-projection
518/// matrix from the two axes already opened on this primitive (999a310
519/// on the [`String`] axis, 55532e5 on the [`Cow<'static, str>`] axis)
520/// onto the third. The fourth and final axis on the matrix
521/// ([`std::sync::Arc<str>`]) is closed by the sibling paired
522/// [`From<CaixaVersion> for std::sync::Arc<str>`] +
523/// [`From<&CaixaVersion> for std::sync::Arc<str>`] impls immediately below.
524///
525/// Pinned load-bearing by
526/// [`tests::caixa_version_from_into_owned_box_str_returns_wrapped_body`]
527/// (byte-parity pin against [`CaixaVersion::as_str`] on the same
528/// instance, plus a round-trip witness through the paired
529/// [`From<String> for CaixaVersion`] constructor closing the two-way
530/// `Self → Box<str> → Self` cycle by construction) and
531/// [`tests::caixa_version_from_into_owned_box_str_and_string_agree_on_every_shape`]
532/// (cross-axis partition pin against the paired owned-input
533/// [`From<CaixaVersion> for String`] and
534/// [`From<CaixaVersion> for Cow<'static, str>`] impls on the same
535/// instance, closing the "owned-input into [`String`] vs. owned-input
536/// into [`Cow<'static, str>`] vs. owned-input into [`Box<str>`]"
537/// three-corner bifurcation on the same wrapped body).
538impl From<CaixaVersion> for Box<str> {
539 fn from(v: CaixaVersion) -> Box<str> {
540 v.0.into_boxed_str()
541 }
542}
543
544/// Trait-idiomatic *borrowed-input, [`Box<str>`] output* reverse
545/// projection on the [`CaixaVersion`] newtype primitive — the
546/// borrowed-input companion to the paired owned-input
547/// [`From<CaixaVersion> for Box<str>`] impl immediately above. Routes
548/// byte-for-byte through the substrate-primitive
549/// [`CaixaVersion::as_str`] `pub const fn` accessor (via
550/// [`Box::<str>::from`]`(&str)`, which allocates a fit-to-length boxed
551/// slice from the borrowed `&str` in one heap allocation without an
552/// intermediary [`String`]) so every consumer that holds a borrowed
553/// [`&CaixaVersion`] and needs a [`Box<str>`] — a
554/// `[…].iter().map(Box::<str>::from).collect::<Vec<_>>()` per-instance
555/// materializer over `&[CaixaVersion]` (whose iterator yields
556/// `&CaixaVersion`, not `CaixaVersion`, so the paired owned-input
557/// [`From<CaixaVersion> for Box<str>`] axis alone forces every call
558/// site through an explicit `.clone()` / dereference restatement), a
559/// future `HashMap::<Box<str>, _>::from_iter` that keys off a
560/// borrowed-iteration axis, a future generic
561/// `<T: for<'a> Into<Box<str>>>`-bound emitter on a per-caixa
562/// diagnostic column that walks the `iter().map(Into::into)` shape
563/// verbatim — reaches the wrapped byte-string through this one dispatch
564/// on the substrate primitive.
565///
566/// Second corner on the `{Self, &Self} → Box<str>` reverse-projection
567/// family opened on the paired owned-input impl immediately above.
568/// Rust's `From` trait does not derive the `From<&Self>` sibling from
569/// a `From<Self>` impl (the blanket
570/// `impl<T, U> From<&T> for U where T: Clone, U: From<T>` does not
571/// exist in `core`), so every newtype that carries the owned-input
572/// reverse [`Box<str>`] axis but not the borrowed-input axis forces
573/// every borrowed call site through a `.clone()` /
574/// `<Box<str>>::from(v.clone())` detour whose type bounds have no
575/// compile-time link back to the newtype.
576///
577/// Pinned load-bearing by
578/// [`tests::caixa_version_from_borrowed_into_owned_box_str_routes_through_as_str_accessor`]
579/// (byte-parity pin against [`CaixaVersion::as_str`] via a borrowed
580/// input, plus a source-survival witness against silent move-out) and
581/// [`tests::caixa_version_from_owned_and_borrowed_into_box_str_agree_on_every_shape`]
582/// (cross-corner partition pin between owned-input move and
583/// borrowed-input clone on the same wrapped body through the
584/// [`Box<str>`] axis).
585impl From<&CaixaVersion> for Box<str> {
586 fn from(v: &CaixaVersion) -> Box<str> {
587 Box::<str>::from(v.as_str())
588 }
589}
590
591/// Trait-idiomatic *owned-input, [`std::sync::Arc<str>`] output* reverse
592/// projection on the [`CaixaVersion`] newtype primitive — the
593/// [`std::sync::Arc<str>`] companion to the paired owned-input
594/// [`From<CaixaVersion> for String`] (999a310),
595/// [`From<CaixaVersion> for std::borrow::Cow<'static, str>`] (55532e5),
596/// and [`From<CaixaVersion> for Box<str>`] (32d861a) impls on the same
597/// primitive. Routes through [`std::sync::Arc::<str>::from`]`(v.0)`,
598/// which allocates a fresh atomically-refcounted heap slab whose data
599/// slot byte-equals the wrapper's own [`String`] storage — the wrapped
600/// bytes move through by value into the `Arc<str>` layout in one heap
601/// allocation (the [`std::sync::Arc<str>`] layout carries a strong
602/// count + weak count header ahead of the byte slice, so a copy is
603/// required regardless of the input axis; no intermediary [`String`]
604/// or [`Box<str>`] is materialized on the owned-input path).
605///
606/// A future consumer that wants a [`std::sync::Arc<str>`]-typed handle
607/// on a [`CaixaVersion`] — a share-through-clone version body held
608/// across a per-caixa `caixa-operator` reconcile task where every
609/// spawn point wants a cheap `.clone()` on the version handle without
610/// each task re-allocating its own [`String`] copy (the
611/// [`std::sync::Arc::clone`] path bumps the atomic refcount in place
612/// and returns a pointer-width handle), a future
613/// `HashMap::<std::sync::Arc<str>, _>::from_iter` per-versao lookup
614/// where the map's key type is [`std::sync::Arc<str>`] so the same
615/// version-body pointer can key both the map and the payload without a
616/// second heap allocation, a future M4 admission-webhook decoder that
617/// materializes decoded version strings as [`std::sync::Arc<str>`]
618/// slices so downstream verdict-composer tasks running on separate
619/// worker threads can share the immutable body without a
620/// per-consumer [`String::clone`] — reaches the wrapped byte-string
621/// through this one dispatch, without the pre-lift
622/// `.to_string().into::<std::sync::Arc<str>>()` double-hop that would
623/// still allocate the same [`Arc<str>`] slab plus one intermediary
624/// [`String`] between the wrapper and the [`std::sync::Arc<str>`] slot.
625///
626/// Peer of the paired owned-input [`From<CaixaVersion> for String`]
627/// (999a310), [`From<CaixaVersion> for Cow<'static, str>`] (55532e5),
628/// and [`From<CaixaVersion> for Box<str>`] (32d861a) impls on the same
629/// primitive — all four route through `v.0` (the [`String`] axis
630/// returns the wrapped buffer verbatim; the [`Cow<'static, str>`] axis
631/// wraps it in [`Cow::Owned`]; the [`Box<str>`] axis shrinks it to a
632/// fit-to-length boxed slice; this axis copies the bytes into a fresh
633/// atomically-refcounted slab whose header carries the atomic strong +
634/// weak counters the [`std::sync::Arc<str>`] layout requires),
635/// preserving the substrate's single-dispatch reverse-projection
636/// discipline across the four axes. Rust's standard library does not
637/// derive `From<Self> for Arc<str>` from `From<Self> for String` (nor
638/// from `From<Self> for Box<str>` or `From<Self> for Cow<'static, str>`),
639/// so every newtype that carries the paired reverse `From<Self> for
640/// String` / `Box<str>` / `Cow<'static, str>` axes but not the paired
641/// [`std::sync::Arc<str>`] axis forces every
642/// [`std::sync::Arc<str>`]-typed call site through a
643/// `.to_string().into()` / `Arc::<str>::from(v.to_string())`
644/// double-allocation detour that heap-allocates a fresh intermediary
645/// [`String`] between the wrapper and the [`std::sync::Arc<str>`] slot.
646///
647/// Closes the trait-idiomatic *owned-input, [`std::sync::Arc<str>`]*
648/// reverse-projection axis on the substrate's core String-wrapper
649/// newtype primitive [`CaixaVersion`], completing the reverse-projection
650/// matrix on this primitive across the full `{String, Cow<'static, str>,
651/// Box<str>, Arc<str>}` roster — the fourth and final axis (999a310 on
652/// the [`String`] axis, 55532e5 on the [`Cow<'static, str>`] axis,
653/// 32d861a on the [`Box<str>`] axis, this axis on the
654/// [`std::sync::Arc<str>`] axis).
655///
656/// Pinned load-bearing by
657/// [`tests::caixa_version_from_into_owned_arc_str_returns_wrapped_body`]
658/// (byte-parity pin against [`CaixaVersion::as_str`] on the same
659/// instance, plus a round-trip witness through the paired
660/// [`From<String> for CaixaVersion`] constructor closing the two-way
661/// `Self → Arc<str> → Self` cycle by construction) and
662/// [`tests::caixa_version_from_into_owned_arc_str_and_string_agree_on_every_shape`]
663/// (cross-axis partition pin against the paired owned-input
664/// [`From<CaixaVersion> for String`], [`From<CaixaVersion> for Cow<'static, str>`],
665/// and [`From<CaixaVersion> for Box<str>`] impls on the same instance,
666/// closing the four-corner "owned-input into `String` vs. `Cow<'static, str>`
667/// vs. `Box<str>` vs. `Arc<str>`" partition on the same wrapped body).
668impl From<CaixaVersion> for std::sync::Arc<str> {
669 fn from(v: CaixaVersion) -> std::sync::Arc<str> {
670 std::sync::Arc::<str>::from(v.0)
671 }
672}
673
674/// Trait-idiomatic *borrowed-input, [`std::sync::Arc<str>`] output*
675/// reverse projection on the [`CaixaVersion`] newtype primitive — the
676/// borrowed-input companion to the paired owned-input
677/// [`From<CaixaVersion> for std::sync::Arc<str>`] impl immediately
678/// above. Routes byte-for-byte through the substrate-primitive
679/// [`CaixaVersion::as_str`] `pub const fn` accessor (via
680/// [`std::sync::Arc::<str>::from`]`(&str)`, which allocates a fresh
681/// atomically-refcounted heap slab from the borrowed `&str` in one
682/// heap allocation without an intermediary [`String`] or [`Box<str>`])
683/// so every consumer that holds a borrowed [`&CaixaVersion`] and needs
684/// a [`std::sync::Arc<str>`] — a
685/// `[…].iter().map(std::sync::Arc::<str>::from).collect::<Vec<_>>()`
686/// per-instance materializer over `&[CaixaVersion]` (whose iterator
687/// yields `&CaixaVersion`, not `CaixaVersion`, so the paired
688/// owned-input [`From<CaixaVersion> for std::sync::Arc<str>`] axis
689/// alone forces every call site through an explicit `.clone()` /
690/// dereference restatement), a future
691/// `HashMap::<std::sync::Arc<str>, _>::from_iter` that keys off a
692/// borrowed-iteration axis, a future generic
693/// `<T: for<'a> Into<std::sync::Arc<str>>>`-bound emitter on a
694/// per-caixa diagnostic column that walks the
695/// `iter().map(Into::into)` shape verbatim — reaches the wrapped
696/// byte-string through this one dispatch on the substrate primitive.
697///
698/// Second corner on the `{Self, &Self} → std::sync::Arc<str>`
699/// reverse-projection family opened on the paired owned-input impl
700/// immediately above. Rust's `From` trait does not derive the
701/// `From<&Self>` sibling from a `From<Self>` impl (the blanket
702/// `impl<T, U> From<&T> for U where T: Clone, U: From<T>` does not
703/// exist in `core`), so every newtype that carries the owned-input
704/// reverse [`std::sync::Arc<str>`] axis but not the borrowed-input
705/// axis forces every borrowed call site through a `.clone()` /
706/// `<std::sync::Arc<str>>::from(v.clone())` detour whose type bounds
707/// have no compile-time link back to the newtype.
708///
709/// Pinned load-bearing by
710/// [`tests::caixa_version_from_borrowed_into_owned_arc_str_routes_through_as_str_accessor`]
711/// (byte-parity pin against [`CaixaVersion::as_str`] via a borrowed
712/// input, plus a source-survival witness against silent move-out) and
713/// [`tests::caixa_version_from_owned_and_borrowed_into_arc_str_agree_on_every_shape`]
714/// (cross-corner partition pin between owned-input move and
715/// borrowed-input clone on the same wrapped body through the
716/// [`std::sync::Arc<str>`] axis).
717impl From<&CaixaVersion> for std::sync::Arc<str> {
718 fn from(v: &CaixaVersion) -> std::sync::Arc<str> {
719 std::sync::Arc::<str>::from(v.as_str())
720 }
721}
722
723/// Trait-idiomatic *owned-input, [`std::rc::Rc<str>`] output* reverse
724/// projection on the [`CaixaVersion`] newtype primitive — the owned-heap-
725/// string, single-threaded-reference-counted inverse of the pre-existing
726/// [`From<String> for CaixaVersion`] / [`From<&str> for CaixaVersion`]
727/// forward-projection pair on this primitive. Consumes the owned wrapper
728/// by value, moves the wrapped [`String`] into the [`std::rc::Rc<str>`]
729/// layout in one heap allocation (the [`std::rc::Rc<str>`] layout carries
730/// a strong count + weak count header ahead of the byte slice, so the copy
731/// is required regardless of the input axis; no intermediary [`String`] or
732/// [`Box<str>`] is materialized on the owned-input path) — the exact
733/// single-threaded mirror of the paired
734/// [`From<CaixaVersion> for std::sync::Arc<str>`] impl (3e67756) on the
735/// atomically-refcounted axis.
736///
737/// A future consumer that wants a [`std::rc::Rc<str>`]-typed handle on a
738/// [`CaixaVersion`] — a per-`feira` verb's single-threaded diagnostic
739/// composer that clones the version body across a chain of Nord-themed
740/// column emitters without paying either the [`String::clone`]
741/// full-allocation cost (every step re-allocates its own buffer) or the
742/// atomic-refcount overhead the paired [`std::sync::Arc<str>`] axis
743/// forces (the [`std::rc::Rc::clone`] path bumps a non-atomic refcount in
744/// place and returns a pointer-width handle, cheaper than the paired
745/// atomic increment on the sibling [`std::sync::Arc<str>`] axis by a
746/// measurable margin on hot single-threaded call sites), a future single-
747/// threaded `HashMap::<std::rc::Rc<str>, _>::from_iter` per-versao lookup
748/// where the map's key type is [`std::rc::Rc<str>`] so the same version-
749/// body pointer can key both the map and the payload without a second heap
750/// allocation, a future `feira lint` per-caixa diagnostic table whose
751/// per-column `Cell<std::rc::Rc<str>>` payload carries the version body
752/// across the row-composer + column-composer + wrapper phases through the
753/// pointer-width handle rather than a [`String`] per phase — reaches the
754/// wrapped byte-string through this one dispatch, without the pre-lift
755/// `.to_string().into::<std::rc::Rc<str>>()` double-hop that would still
756/// allocate the same [`Rc<str>`] slab plus one intermediary [`String`]
757/// between the wrapper and the [`std::rc::Rc<str>`] slot.
758///
759/// Peer of the paired owned-input [`From<CaixaVersion> for String`]
760/// (999a310), [`From<CaixaVersion> for Cow<'static, str>`] (55532e5),
761/// [`From<CaixaVersion> for Box<str>`] (32d861a), and
762/// [`From<CaixaVersion> for std::sync::Arc<str>`] (3e67756) impls on the
763/// same primitive — all five route through `v.0` (the [`String`] axis
764/// returns the wrapped buffer verbatim; the [`Cow<'static, str>`] axis
765/// wraps it in [`Cow::Owned`]; the [`Box<str>`] axis shrinks it to a
766/// fit-to-length boxed slice; the [`Arc<str>`] axis copies the bytes into
767/// a fresh atomically-refcounted slab; this axis copies the bytes into a
768/// fresh single-threaded-refcounted slab whose header carries the non-
769/// atomic strong + weak counters the [`std::rc::Rc<str>`] layout
770/// requires), preserving the substrate's single-dispatch reverse-
771/// projection discipline across the five axes. Rust's standard library
772/// does not derive `From<Self> for Rc<str>` from `From<Self> for Arc<str>`
773/// (the [`std::sync::Arc<str>`] and [`std::rc::Rc<str>`] layouts share the
774/// same on-disk shape but the trait tables are disjoint, and no blanket
775/// `impl<T> From<T> for Rc<str> where Arc<str>: From<T>` exists in
776/// `core`), so every newtype that carries the paired
777/// [`std::sync::Arc<str>`] axis but not the paired [`std::rc::Rc<str>`]
778/// axis forces every single-threaded [`std::rc::Rc<str>`]-typed call site
779/// through a `.to_string().into()` / `Rc::<str>::from(v.to_string())`
780/// double-allocation detour that heap-allocates a fresh intermediary
781/// [`String`] between the wrapper and the [`std::rc::Rc<str>`] slot.
782///
783/// Extends the trait-idiomatic *owned-input* reverse-projection matrix on
784/// the substrate's core String-wrapper newtype primitive [`CaixaVersion`]
785/// onto the single-threaded reference-counted axis — the fifth axis
786/// (999a310 on [`String`], 55532e5 on [`Cow<'static, str>`], 32d861a on
787/// [`Box<str>`], 3e67756 on [`std::sync::Arc<str>`], this axis on
788/// [`std::rc::Rc<str>`]).
789///
790/// Pinned load-bearing by
791/// [`tests::caixa_version_from_into_owned_rc_str_returns_wrapped_body`]
792/// (byte-parity pin against [`CaixaVersion::as_str`] on the same instance,
793/// plus a round-trip witness through the paired [`From<String> for
794/// CaixaVersion`] constructor closing the two-way `Self → Rc<str> → Self`
795/// cycle by construction) and
796/// [`tests::caixa_version_from_into_owned_rc_str_and_arc_str_agree_on_every_shape`]
797/// (cross-axis partition pin against the paired owned-input
798/// [`From<CaixaVersion> for String`],
799/// [`From<CaixaVersion> for Cow<'static, str>`],
800/// [`From<CaixaVersion> for Box<str>`], and
801/// [`From<CaixaVersion> for std::sync::Arc<str>`] impls on the same
802/// instance, closing the five-corner "owned-input into `String` vs.
803/// `Cow<'static, str>` vs. `Box<str>` vs. `Arc<str>` vs. `Rc<str>`"
804/// partition on the same wrapped body).
805impl From<CaixaVersion> for std::rc::Rc<str> {
806 fn from(v: CaixaVersion) -> std::rc::Rc<str> {
807 std::rc::Rc::<str>::from(v.0)
808 }
809}
810
811/// Trait-idiomatic *borrowed-input, [`std::rc::Rc<str>`] output* reverse
812/// projection on the [`CaixaVersion`] newtype primitive — the borrowed-
813/// input companion to the paired owned-input
814/// [`From<CaixaVersion> for std::rc::Rc<str>`] impl immediately above.
815/// Routes byte-for-byte through the substrate-primitive
816/// [`CaixaVersion::as_str`] `pub const fn` accessor (via
817/// [`std::rc::Rc::<str>::from`]`(&str)`, which allocates a fresh
818/// single-threaded-refcounted heap slab from the borrowed `&str` in one
819/// heap allocation without an intermediary [`String`] or [`Box<str>`]) so
820/// every consumer that holds a borrowed [`&CaixaVersion`] and needs a
821/// [`std::rc::Rc<str>`] — a
822/// `[…].iter().map(std::rc::Rc::<str>::from).collect::<Vec<_>>()`
823/// per-instance materializer over `&[CaixaVersion]` (whose iterator yields
824/// `&CaixaVersion`, not `CaixaVersion`, so the paired owned-input
825/// [`From<CaixaVersion> for std::rc::Rc<str>`] axis alone forces every
826/// call site through an explicit `.clone()` / dereference restatement), a
827/// future single-threaded `HashMap::<std::rc::Rc<str>, _>::from_iter` that
828/// keys off a borrowed-iteration axis, a future generic
829/// `<T: for<'a> Into<std::rc::Rc<str>>>`-bound emitter on a per-caixa
830/// diagnostic column that walks the `iter().map(Into::into)` shape
831/// verbatim — reaches the wrapped byte-string through this one dispatch on
832/// the substrate primitive.
833///
834/// Second corner on the `{Self, &Self} → std::rc::Rc<str>` reverse-
835/// projection family opened on the paired owned-input impl immediately
836/// above. Rust's `From` trait does not derive the `From<&Self>` sibling
837/// from a `From<Self>` impl (the blanket `impl<T, U> From<&T> for U where
838/// T: Clone, U: From<T>` does not exist in `core`), so every newtype that
839/// carries the owned-input reverse [`std::rc::Rc<str>`] axis but not the
840/// borrowed-input axis forces every borrowed call site through a
841/// `.clone()` / `<std::rc::Rc<str>>::from(v.clone())` detour whose type
842/// bounds have no compile-time link back to the newtype.
843///
844/// Pinned load-bearing by
845/// [`tests::caixa_version_from_borrowed_into_owned_rc_str_routes_through_as_str_accessor`]
846/// (byte-parity pin against [`CaixaVersion::as_str`] via a borrowed input,
847/// plus a source-survival witness against silent move-out) and
848/// [`tests::caixa_version_from_owned_and_borrowed_into_rc_str_agree_on_every_shape`]
849/// (cross-corner partition pin between owned-input move and borrowed-
850/// input clone on the same wrapped body through the [`std::rc::Rc<str>`]
851/// axis).
852impl From<&CaixaVersion> for std::rc::Rc<str> {
853 fn from(v: &CaixaVersion) -> std::rc::Rc<str> {
854 std::rc::Rc::<str>::from(v.as_str())
855 }
856}
857
858/// Canonical Zig-style git-tag prefix every `feira publish` run writes
859/// and every downstream consumer of a published caixa reads. A caixa
860/// published at `:versao "0.1.0"` lands as a git tag `v0.1.0` on the
861/// source repo's `origin` remote — the [`crate::CaixaVersion`] value
862/// gates the version body, this constant gates the prefix the body
863/// composes under.
864///
865/// Two production-code consumers carry this prefix on the same git
866/// remote axis:
867///
868/// 1. [`caixa-feira`]'s `feira publish` verb (caixa-feira/src/cmd/publish.rs)
869/// — the writer. Its `--prefix` clap flag defaults to this string
870/// and the verb computes the tag as `format!("{prefix}{versao}")`
871/// before `git tag -a <tag>` + `git push origin <tag>`.
872/// 2. [`caixa-flux`]'s [`caixa-flux::cluster_bundle`] renderer
873/// (caixa-flux/src/lib.rs) — the reader. Its
874/// `ClusterBundleOpts::for_caixa` constructor defaults
875/// `git_ref: GitRefSpec::Tag(...)` to `<prefix><versao>` so the
876/// rendered `gitrepository.yaml` carries `ref: { tag: v<versao> }`
877/// pointing `FluxCD`'s `GitRepository` reconciler at the exact tag
878/// the publisher just wrote.
879///
880/// Until this lift landed both consumers carried the bare `"v"` byte
881/// inline — `caixa-feira/src/cmd/publish.rs:22`'s clap
882/// `default_value = "v"` and `caixa-flux/src/lib.rs:335`'s
883/// `format!("v{}", caixa.versao)` literal. A future Zig-style-tag
884/// convention rebrand (the substrate moving to plain `<versao>` tags
885/// once the GitHub releases UI normalizes around the bare form, to
886/// `release/<versao>` once a sibling forge convention adopts the
887/// `<type>/<value>` slash-namespaced shape, or to a per-edition
888/// override the operator pins through a future `:placement
889/// :tag-prefix` slot) without a coordinated edit on both sides would
890/// silently emit a `feira publish`-side tag at one shape (e.g.
891/// `release/0.1.0`) and a `cluster_bundle`-side `ref: { tag: v0.1.0 }`
892/// pointing at the prior shape — Flux's `GitRepository` reconciler
893/// would loop forever looking for an upstream `v0.1.0` ref the publish
894/// remote no longer carries, the dependent `HelmRelease`'s `chart:
895/// sourceRef` would never resolve, every per-Servico apply would
896/// silently come up with the prior reconciled state, and the failure
897/// would surface at `kubectl describe gitrepository` time (the
898/// `Status: Stalled` / `Reason: Failed` arm) far from the rebrand
899/// commit's source.
900///
901/// Lifting the literal to one `&'static str` constant closes the drift
902/// footgun structurally — both consumers read from the same memory,
903/// so any future rebrand reaches both sites by construction and a CI
904/// build that re-introduces a sibling inline `"v"` literal trips the
905/// peer pinning tests
906/// ([`caixa-feira`]'s `publish_prefix_default_pins_lifted_caixa_core_constant`,
907/// [`caixa-flux`]'s `cluster_bundle_default_git_tag_uses_lifted_caixa_core_prefix`)
908/// at the build-time fail-before-deploy posture every prior
909/// load-bearing-string lift on this surface
910/// ([`crate::DEFAULT_NAMESPACE`] a085b26,
911/// [`crate::DEFAULT_LIBRARY_NAME`] 41438dc,
912/// [`crate::DEFAULT_SERVICO_PORT`] 1e22add) establishes.
913///
914/// Authoring-side `:versao` gates already refuse the `"v"`-prefixed
915/// publish tag shape leaking back into a version body — every typed
916/// `:versao` surface (top-level `:versao`, `:upgrade-from :from`,
917/// `:deps :versao`, `:deps-dev :versao`, `:membros :versao`,
918/// `:children :versao`) routes through `semver::Version::parse` /
919/// [`parse_requirement`], both of which reject the `v`-prefix as
920/// invalid `SemVer`. The split — bare `SemVer` at the `:versao` slot,
921/// `v<versao>` at the published git-tag axis — is the convention this
922/// constant pins.
923pub const DEFAULT_PUBLISH_TAG_PREFIX: &str = "v";
924
925/// Canonical git remote name every `feira` writer-side verb pushes to —
926/// the destination handle the operator-out-of-the-loop publish + deploy
927/// chain (`feira publish`, `feira deploy --apply`, `feira app deploy
928/// --apply`) names when it invokes `git push <remote> <ref>` against
929/// the local clone of the source / k8s GitOps repo.
930///
931/// Three production-code consumers carry this remote name on the same
932/// `git push` axis:
933///
934/// 1. [`caixa-feira`]'s `feira publish` verb (caixa-feira/src/cmd/publish.rs)
935/// — the writer-side publish path. Its `--remote` clap flag defaults
936/// to this string and the verb runs `git push <remote> <tag>` to push
937/// the freshly written `v<versao>` tag upstream.
938/// 2. [`caixa-feira`]'s `feira deploy --apply` verb
939/// (caixa-feira/src/cmd/deploy.rs) — the writer-side Servico cluster-
940/// deploy path. Its `push_origin` helper runs `git push origin HEAD`
941/// against the k8s GitOps repo's working tree after upserting the
942/// Servico's entry into the cluster's lareira-fleet-programs
943/// HelmRelease values.
944/// 3. [`caixa-feira`]'s `feira app deploy --apply` verb
945/// (caixa-feira/src/cmd/app.rs) — the writer-side Aplicacao
946/// cluster-deploy path. Its `push_origin` helper runs the same
947/// `git push origin HEAD` against the k8s GitOps repo after writing
948/// the rendered multi-doc YAML (programs.yaml entries + Cilium
949/// NetworkPolicies + Gateway/HTTPRoute) to the cluster's tree.
950///
951/// Until this lift landed all three consumers carried the bare
952/// `"origin"` byte inline — `publish.rs`'s clap `default_value = "origin"`,
953/// `deploy.rs`'s `git(repo, ["push", "origin", "HEAD"])`, and
954/// `app.rs`'s `git(repo, ["push", "origin", "HEAD"])`. A future
955/// remote-naming-convention rebrand on any one side (the substrate
956/// moving to `upstream` for forge-mirror clusters, to a per-tenant
957/// remote naming convention once the operator-flux pipeline grows the
958/// `:placement :remote` slot, or to the canonical multi-remote
959/// `release` + `mirror` split every Erlang/OTP `release_handler` /
960/// `relup` shop converges on once their git surface grows past one
961/// upstream) without a coordinated edit on the other two would have
962/// silently emitted a `git push` against a remote that doesn't exist
963/// on the operator's clone (`fatal: '<remote>' does not appear to be
964/// a git repository`) on one writer verb while the other two still
965/// pushed to the old remote — operator-observed symptom: the publish
966/// landed but the deploy didn't, or vice-versa, with the failure
967/// surfacing as a partial-state rollout far from the rebrand commit's
968/// source.
969///
970/// Lifting the literal to one `&'static str` constant closes the drift
971/// footgun structurally — all three consumers read from the same
972/// memory, so any future remote-naming rebrand reaches every writer
973/// verb by construction and a CI build that re-introduces a sibling
974/// inline `"origin"` literal trips the peer pinning tests
975/// ([`caixa-feira`]'s `publish_remote_default_pins_lifted_caixa_core_constant`
976/// on the clap-default axis, the sibling structural pins on the two
977/// `push_origin` helpers) at the build-time fail-before-deploy
978/// posture every prior load-bearing-string lift on this surface
979/// ([`crate::DEFAULT_NAMESPACE`] a085b26, [`crate::DEFAULT_LIBRARY_NAME`]
980/// 41438dc, [`crate::DEFAULT_SERVICO_PORT`] 1e22add,
981/// [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] 0a6a602,
982/// [`crate::DEFAULT_FLUX_SYSTEM_NAMESPACE`] 7197d38) establishes.
983///
984/// Pairs with [`DEFAULT_PUBLISH_TAG_PREFIX`] on the same git remote
985/// axis — `feira publish` runs `git push <DEFAULT_GIT_REMOTE>
986/// <DEFAULT_PUBLISH_TAG_PREFIX><versao>` to push the typed `:versao`
987/// body composed under the canonical prefix to the canonical remote.
988/// Both halves of the publish-side convention now live in one place.
989pub const DEFAULT_GIT_REMOTE: &str = "origin";
990
991/// Canonical GitHub org name the pleme-io substrate defaults every un-
992/// pinned caixa's source repo to — the org handle the two substrate-side
993/// "no `:repositorio` / no `:fonte` declared, fall back to the canonical
994/// org" paths compose their `github:<org>/<nome>` shorthand + full
995/// `https://github.com/<org>/<nome>` URL under.
996///
997/// Two production-code consumers carry this org name on the same
998/// canonical-substrate-default-git-org axis:
999///
1000/// 1. [`caixa-feira`]'s `feira lock` verb's `resolve_stub` (caixa-feira/src/cmd/lock.rs)
1001/// — the resolver-side default. When a declared dep has no
1002/// `:fonte` block the stub resolver composes
1003/// `caixa_core::DepSource::default_github(<org>, &dep.nome)` to fill
1004/// the shorthand `github:<org>/<nome>` fallback the phase 1.B
1005/// `feira resolve` walker will resolve against upstream.
1006/// 2. [`caixa-flux`]'s [`caixa-flux::cluster_bundle`] renderer
1007/// (caixa-flux/src/lib.rs) — the renderer-side default. Its
1008/// `ClusterBundleOpts::for_caixa` constructor defaults
1009/// `git_url` to `format!("https://github.com/{org}/{}", caixa.nome)`
1010/// when the caixa carries no `:repositorio`, so the rendered
1011/// `gitrepository.yaml` points `FluxCD`'s `GitRepository`
1012/// reconciler at the substrate's canonical git host for un-pinned
1013/// caixas.
1014///
1015/// Until this lift landed both consumers carried the bare `"pleme-io"`
1016/// byte inline — `caixa-feira/src/cmd/lock.rs:61`'s
1017/// `default_github("pleme-io", …)` call and `caixa-flux/src/lib.rs`'s
1018/// `format!("https://github.com/pleme-io/{}", …)` literal. A future
1019/// substrate-side git-org migration (the pleme-io org renaming to a
1020/// short form, forking to a per-tenant `<org>-<tenant>` shape once the
1021/// operator-flux pipeline grows a `:placement :org` slot, or moving to
1022/// a self-hosted forge under a wholly-owned org name once the
1023/// substrate's forge-gen roadmap graduates past GitHub) without a
1024/// coordinated edit on both sides would silently emit a `feira lock`-
1025/// side `github:<old-org>/<nome>` fallback shorthand while the
1026/// `cluster_bundle`-side `gitrepository.yaml` pointed at the new org's
1027/// `<nome>` — the phase 1.B `feira resolve` walker would probe the
1028/// prior org's git host for a repo that migrated with the org, or vice-
1029/// versa: Flux's `GitRepository` reconciler would loop forever looking
1030/// for an upstream repo the old org handle no longer maps to, the
1031/// dependent `HelmRelease`'s `chart: sourceRef` would never resolve,
1032/// every per-Servico apply would silently come up with the prior
1033/// reconciled state, and the failure would surface at `kubectl describe
1034/// gitrepository` time (the `Status: Stalled` / `Reason: Failed` arm)
1035/// far from the org-migration commit's source.
1036///
1037/// Lifting the literal to one `&'static str` constant closes the drift
1038/// footgun structurally — both consumers read from the same memory, so
1039/// any future org migration reaches both sites by construction and a CI
1040/// build that re-introduces a sibling inline `"pleme-io"` literal trips
1041/// the peer pinning tests at the build-time fail-before-deploy posture
1042/// every prior load-bearing-string lift on this surface
1043/// ([`crate::DEFAULT_NAMESPACE`] a085b26,
1044/// [`crate::DEFAULT_LIBRARY_NAME`] 41438dc,
1045/// [`crate::DEFAULT_SERVICO_PORT`] 1e22add,
1046/// [`DEFAULT_PUBLISH_TAG_PREFIX`] 0a6a602,
1047/// [`DEFAULT_GIT_REMOTE`],
1048/// [`crate::DEFAULT_FLUX_SYSTEM_NAMESPACE`] 7197d38) establishes.
1049///
1050/// Distinct from the [`crate::PLEME_LABEL_PREFIX`] canonical pleme-io
1051/// label-namespace prefix (`"pleme.pleme.io"`, the K8s label-namespace
1052/// axis every substrate-emitted cluster object's `LABEL_APLICACAO` /
1053/// `LABEL_PROGRAM` / `LABEL_CONTRATO` axis shares) — these constants
1054/// sit on separate schema-contract surfaces (the git-host org handle
1055/// vs. the K8s label-namespace prefix) governed by independent rebrand
1056/// cycles, so a git-org rename must not couple the K8s label-namespace
1057/// axis to the git-host axis (or vice-versa). Splitting the two lets
1058/// each schema's future rebrand land independently at its canonical
1059/// const definition without silently coupling the surfaces — same
1060/// "byte-distinct, semantically distinct" discipline the
1061/// [`crate::PLEME_LABEL_PREFIX`] / [`crate::LABEL_APLICACAO`] /
1062/// [`crate::LABEL_PROGRAM`] / [`crate::LABEL_CONTRATO`] set establishes
1063/// on the peer per-K8s-label-namespace canonical-string surface.
1064pub const DEFAULT_PLEME_GIT_ORG: &str = "pleme-io";
1065
1066/// Parse a dep's `:versao` string as a [`semver::VersionReq`].
1067///
1068/// Treats the literal `"*"` as "any version" (semver's wildcard).
1069pub fn parse_requirement(s: &str) -> Result<semver::VersionReq, VersionError> {
1070 if s == "*" {
1071 return Ok(semver::VersionReq::STAR);
1072 }
1073 semver::VersionReq::parse(s).map_err(|e| VersionError::requirement(s, e.to_string()))
1074}
1075
1076#[derive(Debug, Error, PartialEq, Eq)]
1077pub enum VersionError {
1078 #[error("invalid version '{0}': {1}")]
1079 Semver(String, String),
1080 #[error("invalid version requirement '{0}': {1}")]
1081 Requirement(String, String),
1082}
1083
1084// Fold the sole `VersionError::Semver(<into-String-expr>, <into-String-expr>)`
1085// wire-up site on [`CaixaVersion::parse`]'s [`semver::Version::parse`]
1086// `map_err` arm onto one substrate primitive — the paired
1087// `(String, String)` two-slot tuple-newtype [`VersionError::Semver`] on
1088// the [`CaixaVersion`] parser surface, the first of the two variants on
1089// the [`VersionError`] envelope's paired `(String, String)` tuple-newtype
1090// codec-magnitude family (its peer is [`VersionError::Requirement`] on
1091// the sibling [`parse_requirement`] surface). Same discipline the peer
1092// per-variant lifts on [`AplicacaoError`] / [`SupervisorError`] /
1093// [`UpgradeError`] / [`LayoutError`] / [`DepError`] / [`ManifestError`]
1094// / [`LimitsError`] / [`BehaviorError`] / [`DialetoError`] have
1095// converged through the "one substrate primitive per emit-site variant"
1096// ratchet: the sole wire-up site opens the identical
1097// `VersionError::Semver(<into-String-expr>, <into-String-expr>)` block
1098// against the parser-scoped `String` binding (`self.0.clone()`) and the
1099// derived `String` binding (`e.to_string()`) on the failing
1100// [`semver::Version::parse`] arm, so the fold routes the site through
1101// one dispatch on a uniform pair of `impl Into<String>` params,
1102// byte-equal to the pre-lift tuple-newtype construction on the same
1103// arguments. The `impl Into<String>` bound covers both the pre-lift
1104// `String` bindings and any future `&str` binding a downstream consumer
1105// might carry without forcing the caller to spell the `.into()`
1106// conversion at the wire-up site — the same shape the peer
1107// [`LimitsError::empty_byte_size`] / [`LimitsError::empty_duration`] /
1108// [`DialetoError::leitura`] folds carry on the single-slot `(String)`
1109// tuple-newtype cousins of the same tuple-newtype error-envelope family
1110// on the sibling parser surfaces. `#[must_use]` fires a compile warning
1111// at any wire-up that mistakenly discards the constructed error. The
1112// added [`PartialEq`] / [`Eq`] derives on the envelope (peer with the
1113// sibling [`LimitsError`] / [`DialetoError`] / [`DepError`] envelopes
1114// on the same axis) let the fail-before-pass-after byte-equality pins
1115// below trip a de-lift regression at caixa-core test time under
1116// `PartialEq` rather than at a downstream diagnostic shape drift.
1117//
1118// Every future consumer that wants to construct this variant outside
1119// [`CaixaVersion::parse`] (a deferred `feira lint --canonical-versao`
1120// per-caixa admission verb probing each authored top-level `:versao`
1121// value against the same [`semver::Version::parse`] gate, an M4 typed
1122// `mesh.pleme.io/v1alpha1/Servico` CR materializer's per-manifest
1123// admission validator re-checking one edited `:versao` slot against
1124// the [`CaixaVersion::parse`] semver floor, a per-`caixa.lisp` value-
1125// shape pre-emitter probing each declared `:versao` magnitude ahead of
1126// the operator's admit-cycle) now reaches the variant through one call
1127// rather than re-inlining the two-slot tuple-newtype block in lockstep.
1128impl VersionError {
1129 /// Construct a [`VersionError::Semver`] carrying the offending
1130 /// authoring string `value` and the underlying [`semver::Version::parse`]
1131 /// `reason` verbatim in the variant's two-slot tuple-newtype payload.
1132 /// Folds the uniform `Self::Semver(value.into(), reason.into())`
1133 /// tuple-newtype construction onto one substrate primitive so every
1134 /// wire-up on the variant reads through one dispatch rather than the
1135 /// pre-lift open-coded
1136 /// `VersionError::Semver(<into-String-expr>, <into-String-expr>)`
1137 /// block. The paired `impl Into<String>` bounds cover the pre-lift
1138 /// `String` wire-up shape on [`CaixaVersion::parse`]
1139 /// (`self.0.clone()` on the parser-scoped `String` field, `e.to_string()`
1140 /// on the derived `String` from the failing
1141 /// [`semver::Version::parse`] arm) without forcing the caller to
1142 /// spell the conversion at the wire-up site. Peer to the sibling
1143 /// [`VersionError::Requirement`] variant on the [`parse_requirement`]
1144 /// surface — the same `(String, String)` two-slot tuple-newtype axis
1145 /// of the paired [`VersionError`] envelope, but on the `SemVer`
1146 /// version-body parser surface rather than the version-requirement
1147 /// parser surface.
1148 #[must_use]
1149 pub fn semver(value: impl Into<String>, reason: impl Into<String>) -> Self {
1150 Self::Semver(value.into(), reason.into())
1151 }
1152
1153 /// Construct a [`VersionError::Requirement`] carrying the offending
1154 /// authoring string `value` and the underlying
1155 /// [`semver::VersionReq::parse`] `reason` verbatim in the variant's
1156 /// two-slot tuple-newtype payload. Folds the uniform
1157 /// `Self::Requirement(value.into(), reason.into())` tuple-newtype
1158 /// construction onto one substrate primitive so every wire-up on the
1159 /// variant reads through one dispatch rather than the pre-lift open-
1160 /// coded `VersionError::Requirement(<into-String-expr>,
1161 /// <into-String-expr>)` block. Peer to the sibling
1162 /// [`VersionError::semver`] ctor on the [`CaixaVersion::parse`]
1163 /// surface — the same `(String, String)` two-slot tuple-newtype axis
1164 /// of the paired [`VersionError`] envelope, but on the version-
1165 /// requirement parser surface rather than the semver-version-body
1166 /// parser surface. Closes the last un-lifted variant on the
1167 /// [`VersionError`] envelope: every arm now reaches its emit site
1168 /// through one substrate-primitive dispatch, matching the "one
1169 /// substrate primitive per emit-site variant" ratchet the peer per-
1170 /// variant lifts on [`crate::AplicacaoError`] /
1171 /// [`crate::SupervisorError`] / [`crate::UpgradeError`] /
1172 /// [`crate::LayoutError`] / [`crate::DepError`] /
1173 /// [`crate::ManifestError`] / [`crate::LimitsError`] /
1174 /// [`crate::BehaviorError`] / [`crate::DialetoError`] have converged
1175 /// onto.
1176 #[must_use]
1177 pub fn requirement(value: impl Into<String>, reason: impl Into<String>) -> Self {
1178 Self::Requirement(value.into(), reason.into())
1179 }
1180}
1181
1182#[cfg(test)]
1183mod tests {
1184 use super::*;
1185
1186 #[test]
1187 fn version_round_trip() {
1188 let v: CaixaVersion = "1.2.3".into();
1189 assert_eq!(v.as_str(), "1.2.3");
1190 assert_eq!(v.parse().unwrap().to_string(), "1.2.3");
1191 }
1192
1193 #[test]
1194 fn caixa_version_as_str_accessor_is_const_fn() {
1195 // Fail-before-pass-after pin on [`CaixaVersion::as_str`]'s
1196 // `const`-eval-surface posture. The accessor projects the typed
1197 // newtype's inner [`String`] through the `pub const fn`
1198 // [`String::as_str`] (const-stable since Rust 1.87, well within
1199 // the workspace MSRV) — any future accidental downgrade to
1200 // non-`const` fails `as_str_via_const_fn` at caixa-core build
1201 // time with E0015 (`cannot call non-const method`), strictly
1202 // stronger than a runtime `assert!`. Sibling of the peer
1203 // per-M2/M3/universal-axis `String → &str` scalar-accessor
1204 // family pins on the sibling `const`-eval-surface passes
1205 // ([`crate::Caixa::nome`] / [`crate::Caixa::versao`] at the
1206 // top-level manifest, [`crate::aplicacao::Membro::nome`] /
1207 // [`crate::aplicacao::Membro::versao_requirement`] at the M3
1208 // membership axis, [`crate::aplicacao::Entrada::hostname`] /
1209 // [`crate::aplicacao::Entrada::destination`] at the M3 ingress
1210 // axis, [`crate::supervisor::ChildSpec::nome`] /
1211 // [`crate::supervisor::ChildSpec::versao_requirement`] at the
1212 // M2 supervisor-tree axis,
1213 // [`crate::upgrade::UpgradeFromEntry::prior_versao`] at the M2
1214 // upgrade axis, [`crate::dep::Dep::nome`] /
1215 // [`crate::dep::Dep::versao_requirement`] at the dep-graph
1216 // axis, and the peer per-`:contratos` [`crate::aplicacao::WitContract::source`] /
1217 // [`crate::aplicacao::WitContract::destination`] /
1218 // [`crate::aplicacao::WitContract::world_ref`] trio the
1219 // sibling pin at 279823b already anchors).
1220 const fn as_str_via_const_fn(v: &CaixaVersion) -> &str {
1221 v.as_str()
1222 }
1223 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
1224 let v: CaixaVersion = versao.into();
1225 assert_eq!(as_str_via_const_fn(&v), v.as_str());
1226 assert_eq!(v.as_str(), versao);
1227 }
1228 }
1229
1230 #[test]
1231 fn star_is_any() {
1232 let r = parse_requirement("*").unwrap();
1233 assert!(r.matches(&"0.1.0".parse().unwrap()));
1234 assert!(r.matches(&"99.0.0".parse().unwrap()));
1235 }
1236
1237 #[test]
1238 fn caret_matches_minor_range() {
1239 let r = parse_requirement("^0.1").unwrap();
1240 assert!(r.matches(&"0.1.0".parse().unwrap()));
1241 assert!(r.matches(&"0.1.99".parse().unwrap()));
1242 assert!(!r.matches(&"0.2.0".parse().unwrap()));
1243 }
1244
1245 #[test]
1246 fn invalid_version_errors() {
1247 let v: CaixaVersion = "not-a-version".into();
1248 assert!(v.parse().is_err());
1249 }
1250
1251 #[test]
1252 fn semver_ctor_matches_tuple_literal_wrap_on_str_binding() {
1253 // Fail-before-pass-after byte-equality pin: the lifted
1254 // [`VersionError::semver`] inherent ctor projects a `&str`
1255 // binding pair through the paired `impl Into<String>` bounds
1256 // byte-equal to the pre-lift open-coded
1257 // `VersionError::Semver(<into-String-expr>, <into-String-expr>)`
1258 // tuple-literal on the same fixture, so any future silent
1259 // regression that swaps `.into()` for a divergent conversion
1260 // (a stray `String::from(str::trim(v))` normalization, a
1261 // parity-lossy `.to_lowercase()` fold, a `Cow<'_, str>` detour)
1262 // trips at caixa-core test time under `PartialEq` rather than
1263 // at a downstream diagnostic-shape drift on a consumer surface.
1264 // Same shape the peer
1265 // [`crate::LimitsError::empty_byte_size_ctor_matches_tuple_literal_wrap_on_str_binding`]
1266 // / [`crate::DialetoError::leitura_ctor_matches_tuple_literal_wrap_on_str_binding`]
1267 // pins carry on the sibling single-slot `(String)` tuple-newtype
1268 // cousins of the same tuple-newtype error-envelope family on the
1269 // sibling parser surfaces.
1270 let value: &str = "not-a-version";
1271 let reason: &str = "unexpected character 'n' while parsing major version number";
1272 assert_eq!(
1273 VersionError::semver(value, reason),
1274 VersionError::Semver(value.to_string(), reason.to_string()),
1275 "generated semver ctor over `&str` bindings must match \
1276 the pre-lift tuple-literal wrap on the same fixture",
1277 );
1278 }
1279
1280 #[test]
1281 fn semver_ctor_matches_tuple_literal_wrap_on_string_binding() {
1282 // Fail-before-pass-after byte-equality pin on the paired owned-
1283 // `String` shape — the actual wire-up shape on
1284 // [`CaixaVersion::parse`] (`self.0.clone()` +
1285 // `e.to_string()`). Peer to the `&str` variant above; refuses
1286 // any future de-lift that inlines a divergent construction on
1287 // the owned-`String` path (a stray `.trim().to_string()`
1288 // normalization on either slot, a swap that routes the ctor
1289 // through the sibling [`VersionError::Requirement`] variant on
1290 // the paired parser surface).
1291 let value: String = String::from("1.2");
1292 let reason: String =
1293 String::from("unexpected end of input while parsing minor version number");
1294 assert_eq!(
1295 VersionError::semver(value.clone(), reason.clone()),
1296 VersionError::Semver(value, reason),
1297 "generated semver ctor over owned-`String` bindings must \
1298 match the pre-lift tuple-literal wrap on the same fixture",
1299 );
1300 }
1301
1302 #[test]
1303 fn parse_semver_error_routes_through_semver_ctor() {
1304 // Fail-before-pass-after routes-through pin: refuses any future
1305 // de-lift of [`CaixaVersion::parse`]'s
1306 // [`semver::Version::parse`] `map_err` arm off the substrate
1307 // primitive. Sweeps three malformed authoring shapes (a bare
1308 // non-numeric, a partial `major.minor` shape, a stray leading
1309 // `v`-prefix that the [`DEFAULT_PUBLISH_TAG_PREFIX`] git-tag
1310 // convention rejects at the version-body slot) through the
1311 // parser and asserts the emitted [`VersionError`] equals the
1312 // ctor-built error verbatim under `PartialEq`, so any future
1313 // swap of the wire-up (an inline `Self::Semver(...)`
1314 // re-inlining, a routing detour through the sibling
1315 // [`VersionError::Requirement`] variant on the paired parser
1316 // surface, a swap of the ordering on the paired arguments)
1317 // trips at caixa-core test time rather than at a downstream
1318 // diagnostic drift on a `feira lint` / operator admission
1319 // callsite.
1320 for bad in ["not-a-version", "1.2", "v0.1.0"] {
1321 let v: CaixaVersion = bad.into();
1322 let err = v
1323 .parse()
1324 .expect_err("malformed versao fixture must fail semver parsing");
1325 let semver_reason = match semver::Version::parse(bad) {
1326 Err(e) => e.to_string(),
1327 Ok(_) => unreachable!(
1328 "fixture `{bad}` is documented as a `SemVer` \
1329 rejection but parsed cleanly — the pin's oracle \
1330 drifted from `semver`'s current shape",
1331 ),
1332 };
1333 assert_eq!(
1334 err,
1335 VersionError::semver(bad, semver_reason),
1336 "CaixaVersion::parse must route its semver `map_err` \
1337 arm through the lifted VersionError::semver ctor on \
1338 the same offending value and semver reason",
1339 );
1340 }
1341 }
1342
1343 #[test]
1344 fn default_git_remote_pins_canonical_origin_byte() {
1345 // Bridge-arm pin: [`DEFAULT_GIT_REMOTE`] resolves to the
1346 // canonical `"origin"` byte today, the same remote-handle every
1347 // `git clone <url>` invocation populates by default and every
1348 // peer `feira` writer-side verb (`feira publish`, `feira deploy
1349 // --apply`, `feira app deploy --apply`) names when it invokes
1350 // `git push <remote> <ref>` against the local clone. Pin the
1351 // literal here (peer with the
1352 // [`DEFAULT_PUBLISH_TAG_PREFIX`] / [`crate::DEFAULT_SERVICO_PORT`]
1353 // / [`crate::DEFAULT_NAMESPACE`] / [`crate::DEFAULT_LIBRARY_NAME`]
1354 // / [`crate::DEFAULT_FLUX_SYSTEM_NAMESPACE`] canonical-literal
1355 // pins on the sibling lifted-constant surfaces) so a future
1356 // remote-naming rebrand surfaces here as a coordinated edit-
1357 // point: the sibling [`caixa-feira`]
1358 // `publish_remote_default_pins_lifted_caixa_core_constant`
1359 // pinning test already pins the equality at the clap-default
1360 // axis; this pin closes the second coordinate of the
1361 // triangle by anchoring the lifted constant's current byte
1362 // to the canonical git-default-remote convention's documented
1363 // shape.
1364 assert_eq!(DEFAULT_GIT_REMOTE, "origin");
1365 }
1366
1367 #[test]
1368 fn default_pleme_git_org_pins_canonical_pleme_io_byte() {
1369 // Bridge-arm pin: [`DEFAULT_PLEME_GIT_ORG`] resolves to the
1370 // canonical `"pleme-io"` GitHub-org-handle today, the same org
1371 // name every peer substrate-side default-git-source consumer
1372 // ([`caixa-feira`]'s `feira lock` `resolve_stub` for the
1373 // per-dep `:fonte`-elided `github:<org>/<nome>` fallback,
1374 // [`caixa-flux`]'s `ClusterBundleOpts::for_caixa` constructor
1375 // for the per-caixa `:repositorio`-elided
1376 // `https://github.com/<org>/<nome>` fallback) fills into its
1377 // per-consumer render/resolve compose site. Pin the literal
1378 // here (peer with the [`DEFAULT_PUBLISH_TAG_PREFIX`] /
1379 // [`DEFAULT_GIT_REMOTE`] canonical-literal pins on the sibling
1380 // lifted-constant surfaces) so a future substrate-side git-org
1381 // migration surfaces here as a coordinated edit-point: both
1382 // sibling consumer sites already thread through the same
1383 // `&'static str`, this pin anchors the lifted constant's
1384 // current byte to the canonical substrate-git-org convention's
1385 // documented shape.
1386 assert_eq!(DEFAULT_PLEME_GIT_ORG, "pleme-io");
1387 }
1388
1389 #[test]
1390 fn requirement_ctor_matches_tuple_literal_wrap_on_str_binding() {
1391 // Fail-before-pass-after byte-equality pin: the lifted
1392 // [`VersionError::requirement`] inherent ctor projects a `&str`
1393 // binding pair through the paired `impl Into<String>` bounds
1394 // byte-equal to the pre-lift open-coded
1395 // `VersionError::Requirement(<into-String-expr>, <into-String-expr>)`
1396 // tuple-literal on the same fixture. Same shape the peer
1397 // [`VersionError::semver_ctor_matches_tuple_literal_wrap_on_str_binding`]
1398 // pin carries on the sibling [`VersionError::Semver`] variant of
1399 // the same `(String, String)` two-slot tuple-newtype envelope.
1400 let value: &str = "not-a-req";
1401 let reason: &str = "unexpected character 'n' while parsing major version number";
1402 assert_eq!(
1403 VersionError::requirement(value, reason),
1404 VersionError::Requirement(value.to_string(), reason.to_string()),
1405 "generated requirement ctor over `&str` bindings must match \
1406 the pre-lift tuple-literal wrap on the same fixture",
1407 );
1408 }
1409
1410 #[test]
1411 fn requirement_ctor_matches_tuple_literal_wrap_on_string_binding() {
1412 // Fail-before-pass-after byte-equality pin on the paired owned-
1413 // `String` shape. Peer to the `&str` variant above; refuses any
1414 // future de-lift that inlines a divergent construction on the
1415 // owned-`String` path (a stray `.trim().to_string()` normalization
1416 // on either slot, a swap that routes the ctor through the sibling
1417 // [`VersionError::Semver`] variant on the paired parser surface,
1418 // an argument-ordering swap on the paired slots).
1419 let value: String = String::from("^bogus");
1420 let reason: String = String::from("unexpected character while parsing requirement");
1421 assert_eq!(
1422 VersionError::requirement(value.clone(), reason.clone()),
1423 VersionError::Requirement(value, reason),
1424 "generated requirement ctor over owned-`String` bindings must \
1425 match the pre-lift tuple-literal wrap on the same fixture",
1426 );
1427 }
1428
1429 #[test]
1430 fn parse_requirement_error_routes_through_requirement_ctor() {
1431 // Fail-before-pass-after routes-through pin: refuses any future
1432 // de-lift of [`parse_requirement`]'s
1433 // [`semver::VersionReq::parse`] `map_err` arm off the substrate
1434 // primitive. Sweeps three malformed authoring shapes (a bare
1435 // non-numeric, a stray operator with no version body, a
1436 // caret-prefixed non-numeric that the [`semver::VersionReq`]
1437 // grammar rejects at the operator-body slot) through the parser
1438 // and asserts the emitted [`VersionError`] equals the ctor-built
1439 // error verbatim under `PartialEq`, so any future swap of the
1440 // wire-up (an inline `Self::Requirement(...)` re-inlining, a
1441 // routing detour through the sibling [`VersionError::Semver`]
1442 // variant on the paired parser surface, an argument-ordering
1443 // swap on the paired slots) trips at caixa-core test time rather
1444 // than at a downstream diagnostic drift on a `feira lock` /
1445 // resolver admission callsite. The `"*"` wildcard short-circuit
1446 // is deliberately excluded from the sweep — it returns
1447 // [`semver::VersionReq::STAR`] before reaching the parser arm.
1448 for bad in ["not-a-req", "^", "^bogus"] {
1449 let err = parse_requirement(bad)
1450 .expect_err("malformed requirement fixture must fail parsing");
1451 let semver_reason = match semver::VersionReq::parse(bad) {
1452 Err(e) => e.to_string(),
1453 Ok(_) => unreachable!(
1454 "fixture `{bad}` is documented as a `VersionReq` \
1455 rejection but parsed cleanly — the pin's oracle \
1456 drifted from `semver`'s current shape",
1457 ),
1458 };
1459 assert_eq!(
1460 err,
1461 VersionError::requirement(bad, semver_reason),
1462 "parse_requirement must route its `map_err` arm through \
1463 the lifted VersionError::requirement ctor on the same \
1464 offending value and semver reason",
1465 );
1466 }
1467 }
1468
1469 #[test]
1470 fn default_publish_tag_prefix_pins_canonical_v_byte() {
1471 // Bridge-arm pin: [`DEFAULT_PUBLISH_TAG_PREFIX`] resolves to the
1472 // canonical Zig-style `"v"` byte today, the same prefix every
1473 // peer doc-comment on the typed `:versao` surfaces (the
1474 // top-level `:versao` `validate_versao` cascade at
1475 // caixa-core/src/manifest.rs:646, the four sibling per-axis
1476 // `:versao` requirement gates that name the publish-side
1477 // `v<versao>` tag inline in their bodies) cites as the
1478 // canonical convention. Pin the literal here (peer with the
1479 // [`crate::DEFAULT_SERVICO_PORT`] / [`crate::DEFAULT_NAMESPACE`]
1480 // / [`crate::DEFAULT_LIBRARY_NAME`] canonical-literal pins on
1481 // the sibling lifted-constant surfaces) so a future rebrand of
1482 // the constant surfaces here as a coordinated edit-point: both
1483 // sibling pinning tests on the two consumer crates
1484 // ([`caixa-feira`] `publish_prefix_default_pins_lifted_caixa_core_constant`,
1485 // [`caixa-flux`] `cluster_bundle_default_git_tag_uses_lifted_caixa_core_prefix`)
1486 // already pin the equality at the consumer-default axis; this
1487 // pin closes the third coordinate of the triangle by anchoring
1488 // the lifted constant's current byte to the canonical Zig-style
1489 // convention's documented shape.
1490 assert_eq!(DEFAULT_PUBLISH_TAG_PREFIX, "v");
1491 }
1492
1493 #[test]
1494 fn caixa_version_as_ref_str_routes_through_as_str_accessor() {
1495 // Fail-before-pass-after byte-parity pin on the lifted
1496 // `impl AsRef<str> for CaixaVersion` — asserts the standard-
1497 // library trait impl and the substrate-primitive
1498 // [`CaixaVersion::as_str`] `pub const fn` accessor resolve to
1499 // the same `&str` per instance, so any future silent detour
1500 // that routes the impl through a divergent projection (a
1501 // `Cow<'_, str>` intermediate, a stray `.to_lowercase()`
1502 // normalization, a swap onto a per-arm inline `&self.0.as_str()`
1503 // re-inlining, a swap onto a divergent [`String::trim`]
1504 // fold) trips at caixa-core test time under `PartialEq`
1505 // rather than at a downstream `impl AsRef<str>`-bound
1506 // consumer's silent split. Sweeps four authoring shapes (a
1507 // canonical release version, a pre-release build-metadata
1508 // version, the zero-version canonical unset baseline, and
1509 // the empty-string byte the caller-side default-construct
1510 // path composes) so every non-degenerate arm of the wrapped
1511 // `String` storage is covered. Peer of the sibling
1512 // [`caixa_version_as_str_accessor_is_const_fn`] const-eval
1513 // pin on the same [`CaixaVersion::as_str`] primitive — the
1514 // two pins together cover the const-eval axis (the pin above)
1515 // and the trait-projection axis (this pin) of the same
1516 // substrate-primitive scalar accessor.
1517 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
1518 let v: CaixaVersion = versao.into();
1519 assert_eq!(
1520 <CaixaVersion as AsRef<str>>::as_ref(&v),
1521 v.as_str(),
1522 "AsRef<str> impl must byte-equal CaixaVersion::as_str \
1523 on the same instance — divergence signals a silent \
1524 detour off the substrate-primitive accessor",
1525 );
1526 assert_eq!(
1527 <CaixaVersion as AsRef<str>>::as_ref(&v),
1528 versao,
1529 "AsRef<str> impl must byte-equal the pre-lift wrapped \
1530 String storage on round-trip through the From<&str> \
1531 constructor — divergence signals a normalization \
1532 detour on either the constructor or the accessor",
1533 );
1534 }
1535 }
1536
1537 #[test]
1538 fn caixa_version_as_ref_str_routes_through_display_via_shared_accessor() {
1539 // Fail-before-pass-after byte-parity pin on the three-path
1540 // convergence discipline the substrate primitive now carries
1541 // on the `&str`-projection axis: `<CaixaVersion as
1542 // AsRef<str>>::as_ref(&v)` (the newly lifted impl),
1543 // `format!("{v}")` (the pre-existing [`fmt::Display`] impl),
1544 // and `v.as_str()` (the substrate-primitive `pub const fn`
1545 // accessor both trait impls delegate through) must resolve to
1546 // the same byte-string on every instance. Refuses any future
1547 // divergence between the two trait impls (a stray
1548 // [`fmt::Display::fmt`] rewrite that inlines
1549 // `f.write_str(&self.0)` on the wrapped `String` directly,
1550 // bypassing the shared accessor; a hypothetical `AsRef<str>`
1551 // rewrite that inlines the same `&self.0` field-access) that
1552 // would silently split the two projection paths of the same
1553 // typed newtype. Mirrors the sibling three-path-convergence
1554 // discipline the peer [`RestartStrategy`] typed enum carries
1555 // on its `Display` / `as_str` / `Serialize` triple (aplicacao.rs
1556 // pin `restart_strategy_display_matches_serialized_wire_byte_string`).
1557 for versao in ["0.1.0", "1.2.3-alpha.1", ""] {
1558 let v: CaixaVersion = versao.into();
1559 let via_as_ref: &str = <CaixaVersion as AsRef<str>>::as_ref(&v);
1560 let via_display: String = format!("{v}");
1561 let via_accessor: &str = v.as_str();
1562 assert_eq!(via_as_ref, via_accessor);
1563 assert_eq!(via_display, via_accessor);
1564 assert_eq!(via_as_ref, via_display.as_str());
1565 }
1566 }
1567
1568 #[test]
1569 fn caixa_version_borrow_str_routes_through_as_str_accessor() {
1570 // Fail-before-pass-after byte-parity pin on the lifted
1571 // `impl std::borrow::Borrow<str> for CaixaVersion` — asserts the
1572 // standard-library trait impl and the substrate-primitive
1573 // [`CaixaVersion::as_str`] `pub const fn` accessor resolve to
1574 // the same `&str` per instance, so any future silent detour
1575 // that routes the impl through a divergent projection (a
1576 // `Cow<'_, str>` intermediate, a stray `.to_lowercase()`
1577 // normalization, a swap onto a per-arm inline `&self.0.as_str()`
1578 // re-inlining that bypasses the shared accessor) trips at
1579 // caixa-core test time under `PartialEq` rather than at a
1580 // downstream `Borrow<str>`-bound collection API's silent
1581 // hash-mismatch on the load-bearing HashMap-key axis. Peer of
1582 // the sibling
1583 // [`caixa_version_as_ref_str_routes_through_as_str_accessor`]
1584 // byte-parity pin on the paired [`AsRef<str>`] impl — both cover
1585 // the borrow-projection axis of the same substrate primitive.
1586 use std::borrow::Borrow;
1587 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
1588 let v: CaixaVersion = versao.into();
1589 assert_eq!(
1590 <CaixaVersion as Borrow<str>>::borrow(&v),
1591 v.as_str(),
1592 "Borrow<str> impl must byte-equal CaixaVersion::as_str \
1593 on the same instance — divergence signals a silent \
1594 detour off the substrate-primitive accessor",
1595 );
1596 assert_eq!(
1597 <CaixaVersion as Borrow<str>>::borrow(&v),
1598 versao,
1599 "Borrow<str> impl must byte-equal the pre-lift wrapped \
1600 String storage on round-trip through the From<&str> \
1601 constructor",
1602 );
1603 }
1604 }
1605
1606 #[test]
1607 fn caixa_version_borrow_str_and_as_ref_str_agree_on_every_shape() {
1608 // Fail-before-pass-after cross-axis partition pin on the two
1609 // trait impls on the same borrow-projection axis: the lifted
1610 // [`std::borrow::Borrow<str>`] impl (this commit) and the paired
1611 // [`AsRef<str>`] impl (a086 lift) must resolve to the same `&str`
1612 // per instance, both routing through the shared substrate-
1613 // primitive [`CaixaVersion::as_str`] accessor. Refuses any future
1614 // silent split between the two trait impls (a stray
1615 // [`AsRef::as_ref`] rewrite that inlines `&self.0.as_str()` on
1616 // the wrapped [`String`] directly, bypassing the shared
1617 // accessor; a hypothetical [`Borrow::borrow`] rewrite that
1618 // inlines the same `&self.0` field-access) that would silently
1619 // split the two projection paths of the same typed newtype and
1620 // break the [`std::borrow::Borrow`] safety contract's
1621 // "hash-agrees on the borrowed view" invariant the collection
1622 // APIs rely on. Mirrors the sibling three-path convergence
1623 // discipline the peer
1624 // [`caixa_version_as_ref_str_routes_through_display_via_shared_accessor`]
1625 // pin carries on the `AsRef<str>` / `Display` / `as_str` triple.
1626 use std::borrow::Borrow;
1627 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
1628 let v: CaixaVersion = versao.into();
1629 let via_borrow: &str = <CaixaVersion as Borrow<str>>::borrow(&v);
1630 let via_as_ref: &str = <CaixaVersion as AsRef<str>>::as_ref(&v);
1631 let via_accessor: &str = v.as_str();
1632 assert_eq!(via_borrow, via_accessor);
1633 assert_eq!(via_as_ref, via_accessor);
1634 assert_eq!(via_borrow, via_as_ref);
1635 }
1636 }
1637
1638 #[test]
1639 fn caixa_version_borrow_str_enables_hashmap_lookup_by_borrowed_key() {
1640 // Fail-before-pass-after contract-witness pin on the
1641 // [`std::borrow::Borrow<str>`] safety contract: a
1642 // [`std::collections::HashMap`] keyed by owned [`CaixaVersion`]
1643 // must resolve `.get::<str>("<versao>")` probes through the
1644 // borrowed `&str` view of a stored key to the same slot, and
1645 // (`String::hash` calls `str::hash` on bytes, and the
1646 // [`CaixaVersion`] derived [`Hash`] impl hashes the wrapped
1647 // [`String`] field) the borrowed and owned hash must agree on
1648 // every fixture. Refuses any future silent regression that would
1649 // break the hash-agrees invariant (a
1650 // [`Hash for CaixaVersion`] hand-written impl that diverges from
1651 // the derived shape, a [`Borrow<str>::borrow`] rewrite that
1652 // routes through a normalization detour, an `Eq` hand-written
1653 // impl that diverges from field-wise equality) —
1654 // [`HashMap::get<Q>`] would return [`None`] on a key that
1655 // structurally lives in the map, which is the exact silent
1656 // failure the [`std::borrow::Borrow`] documented safety contract
1657 // rules out. The load-bearing use-case this impl was added for:
1658 // per-`:versao` collection APIs must be probed by borrowed
1659 // `&str` without a per-probe [`CaixaVersion::from(&str)`]
1660 // allocation.
1661 use std::collections::HashMap;
1662 let mut map: HashMap<CaixaVersion, u32> = HashMap::new();
1663 for (i, versao) in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""].iter().enumerate() {
1664 let key: CaixaVersion = (*versao).into();
1665 map.insert(key, u32::try_from(i).unwrap());
1666 }
1667 for (i, versao) in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""].iter().enumerate() {
1668 let hit = map.get(*versao).unwrap_or_else(|| {
1669 panic!(
1670 "HashMap<CaixaVersion, _>::get(&str) must reach the \
1671 slot inserted under CaixaVersion::from({versao:?}) \
1672 through the Borrow<str> bound — a miss signals the \
1673 borrowed-vs-owned hash-agrees invariant broke",
1674 )
1675 });
1676 assert_eq!(*hit, u32::try_from(i).unwrap());
1677 }
1678 assert!(
1679 !map.contains_key("does-not-exist"),
1680 "HashMap<CaixaVersion, _>::contains_key(&str) on an absent \
1681 key must return false, not accidentally hash-collide onto \
1682 a stored slot — the miss path must respect the same \
1683 invariant as the hit path",
1684 );
1685 }
1686
1687 #[test]
1688 fn caixa_version_from_into_owned_string_returns_wrapped_body() {
1689 // Fail-before-pass-after byte-parity pin on the lifted
1690 // `impl From<CaixaVersion> for String` — asserts the owned-input
1691 // reverse-projection routes the wrapper's own heap allocation
1692 // through verbatim (no re-copy, no normalization detour) so
1693 // `String::from(v)` returns the same bytes `v.as_str()`
1694 // borrows. Refuses any future silent detour that would swap
1695 // the move on `v.0` for an allocating `.as_str().to_owned()` /
1696 // `.to_string()` cascade (the pre-lift compose shape), a stray
1697 // `.trim().to_owned()` normalization, or a routing through the
1698 // sibling [`fmt::Display`] emitter that would introduce a
1699 // formatter round-trip.
1700 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
1701 let v: CaixaVersion = versao.into();
1702 let expected = v.as_str().to_owned();
1703 let owned: String = String::from(v);
1704 assert_eq!(
1705 owned, expected,
1706 "String::from(v) must return the wrapper's own bytes verbatim",
1707 );
1708 assert_eq!(
1709 owned, versao,
1710 "String::from(v) must round-trip byte-equal through the From<&str> constructor",
1711 );
1712 }
1713 }
1714
1715 #[test]
1716 fn caixa_version_from_into_owned_string_and_as_str_agree_on_every_shape() {
1717 // Fail-before-pass-after cross-axis partition pin: the owned-
1718 // input [`From<CaixaVersion> for String`] reverse projection
1719 // and the borrowed [`AsRef<str>`] projection resolve to the
1720 // same bytes on every instance, and the paired forward
1721 // [`From<String> for CaixaVersion`] constructor closes the
1722 // `Self → String → Self` round-trip by construction. Refuses
1723 // any future silent split between the owned-move reverse axis
1724 // and the borrowed-clone AsRef axis (a stray normalization on
1725 // one path only) that would let `String::from(v)` and
1726 // `v.as_ref::<str>()` diverge on the same instance.
1727 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
1728 let v: CaixaVersion = versao.into();
1729 let via_as_ref: String = <CaixaVersion as AsRef<str>>::as_ref(&v).to_owned();
1730 let via_to_string: String = v.to_string();
1731 let via_from: String = String::from(v.clone());
1732 assert_eq!(via_from, via_as_ref);
1733 assert_eq!(via_from, via_to_string);
1734 let round_trip: CaixaVersion = via_from.clone().into();
1735 assert_eq!(round_trip, v);
1736 }
1737 }
1738
1739 #[test]
1740 fn caixa_version_from_borrowed_into_owned_string_routes_through_as_str_accessor() {
1741 // Fail-before-pass-after byte-parity pin on the lifted
1742 // `impl From<&CaixaVersion> for String` — asserts the
1743 // borrowed-input reverse projection allocates a fresh
1744 // [`String`] whose bytes byte-equal the substrate-primitive
1745 // [`CaixaVersion::as_str`] accessor on the same instance,
1746 // preserving the source [`CaixaVersion`] intact (no move-out).
1747 // Refuses any future silent detour that would route the impl
1748 // through a divergent projection (a stray normalization step,
1749 // a swap onto the sibling [`fmt::Display`]-routed
1750 // [`ToString::to_string`] surface, a re-inlining that
1751 // dereferences `&self.0` outside the shared accessor).
1752 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
1753 let v: CaixaVersion = versao.into();
1754 let via_borrowed: String = String::from(&v);
1755 assert_eq!(
1756 via_borrowed,
1757 v.as_str(),
1758 "String::from(&v) must byte-equal CaixaVersion::as_str",
1759 );
1760 // The borrowed-input impl must not move out of the source.
1761 assert_eq!(
1762 v.as_str(),
1763 versao,
1764 "source CaixaVersion must survive borrowed-input projection"
1765 );
1766 }
1767 }
1768
1769 #[test]
1770 fn caixa_version_from_owned_and_borrowed_into_string_agree_on_every_shape() {
1771 // Fail-before-pass-after cross-axis partition pin: the paired
1772 // owned-input [`From<CaixaVersion> for String`] and
1773 // borrowed-input [`From<&CaixaVersion> for String`] impls
1774 // resolve to the same bytes on every instance, closing the
1775 // "owned-input move vs. borrowed-input clone" bifurcation on
1776 // the same wrapped body. Refuses any future silent split
1777 // between the two corners (a normalization on one path only, a
1778 // divergent routing that would let `String::from(v.clone())`
1779 // and `String::from(&v)` disagree on the same body).
1780 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
1781 let v: CaixaVersion = versao.into();
1782 let via_borrowed: String = String::from(&v);
1783 let via_owned: String = String::from(v.clone());
1784 assert_eq!(via_owned, via_borrowed);
1785 assert_eq!(via_borrowed, versao);
1786 }
1787 }
1788
1789 #[test]
1790 fn caixa_version_from_into_owned_cow_str_returns_owned_wrapped_body() {
1791 // Fail-before-pass-after byte-parity + [`Cow::Owned`]-arm pin
1792 // on the lifted `impl From<CaixaVersion> for
1793 // std::borrow::Cow<'static, str>` — asserts the owned-input
1794 // reverse projection routes the wrapper's own heap allocation
1795 // through `Cow::Owned(v.0)` verbatim (no re-copy, no
1796 // normalization detour, no `Cow::Borrowed` misclassification
1797 // that would demand a `&'static str` the runtime wrapper cannot
1798 // carry), so the emitted [`Cow`] byte-equals the substrate-
1799 // primitive [`CaixaVersion::as_str`] accessor on the same
1800 // instance and round-trips byte-equal through the paired
1801 // forward [`From<String> for CaixaVersion`] constructor.
1802 // Refuses any future silent detour: a swap of the move on
1803 // `v.0` for an allocating `.as_str().to_owned()` cascade (the
1804 // pre-lift compose shape would double-allocate a fresh
1805 // intermediary [`String`] on the way to the same
1806 // [`Cow::Owned`] arm), a stray `.trim().to_owned()`
1807 // normalization, or a mis-routing through
1808 // [`Cow::Borrowed`] on a non-`'static` byte-string that would
1809 // not type-check.
1810 use std::borrow::Cow;
1811 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
1812 let v: CaixaVersion = versao.into();
1813 let expected = v.as_str().to_owned();
1814 let cow: Cow<'static, str> = Cow::from(v.clone());
1815 assert!(
1816 matches!(cow, Cow::Owned(_)),
1817 "From<CaixaVersion> for Cow<'static, str> must land on \
1818 the Cow::Owned arm — a runtime String wrapper cannot \
1819 promise the 'static lifetime the Cow::Borrowed arm \
1820 requires",
1821 );
1822 assert_eq!(
1823 cow.as_ref(),
1824 expected,
1825 "Cow::from(v) must return the wrapper's own bytes verbatim",
1826 );
1827 let round_trip: CaixaVersion = cow.into_owned().into();
1828 assert_eq!(
1829 round_trip, v,
1830 "Cow::from(v).into_owned() must round-trip byte-equal \
1831 through the From<String> constructor",
1832 );
1833 }
1834 }
1835
1836 #[test]
1837 fn caixa_version_from_into_owned_cow_str_and_string_agree_on_every_shape() {
1838 // Fail-before-pass-after cross-axis partition pin: the owned-
1839 // input [`From<CaixaVersion> for Cow<'static, str>`] reverse
1840 // projection and the paired owned-input
1841 // [`From<CaixaVersion> for String`] reverse projection resolve
1842 // to the same bytes on every instance, and both agree with the
1843 // borrowed [`AsRef<str>`] surface on the same wrapped body.
1844 // Refuses any future silent split between the two owned-input
1845 // reverse-projection axes (a stray normalization on one path
1846 // only, a divergent routing that would let
1847 // `Cow::from(v.clone())` and `String::from(v.clone())` disagree
1848 // on the same body) that would silently split the same-shape
1849 // owned-move discipline across the two reverse-projection
1850 // targets.
1851 use std::borrow::Cow;
1852 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
1853 let v: CaixaVersion = versao.into();
1854 let via_string: String = String::from(v.clone());
1855 let via_cow: Cow<'static, str> = Cow::from(v.clone());
1856 let via_as_ref: &str = <CaixaVersion as AsRef<str>>::as_ref(&v);
1857 assert_eq!(via_cow.as_ref(), via_string.as_str());
1858 assert_eq!(via_cow.as_ref(), via_as_ref);
1859 assert_eq!(via_cow.as_ref(), versao);
1860 }
1861 }
1862
1863 #[test]
1864 fn caixa_version_from_borrowed_into_owned_cow_str_routes_through_as_str_accessor() {
1865 // Fail-before-pass-after byte-parity + [`Cow::Owned`]-arm pin
1866 // on the lifted `impl From<&CaixaVersion> for
1867 // std::borrow::Cow<'static, str>` — asserts the borrowed-input
1868 // reverse projection allocates a fresh [`Cow::Owned`] whose
1869 // bytes byte-equal the substrate-primitive
1870 // [`CaixaVersion::as_str`] accessor on the same instance,
1871 // preserving the source [`CaixaVersion`] intact (no move-out).
1872 // Refuses any future silent detour that would route the impl
1873 // through a divergent projection (a stray normalization step,
1874 // a mis-routing onto [`Cow::Borrowed`] on a non-`'static`
1875 // byte-string that would not type-check, a re-inlining that
1876 // dereferences `&self.0` outside the shared accessor).
1877 use std::borrow::Cow;
1878 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
1879 let v: CaixaVersion = versao.into();
1880 let via_borrowed: Cow<'static, str> = Cow::from(&v);
1881 assert!(
1882 matches!(via_borrowed, Cow::Owned(_)),
1883 "From<&CaixaVersion> for Cow<'static, str> must land on \
1884 the Cow::Owned arm — a runtime String wrapper cannot \
1885 promise the 'static lifetime the Cow::Borrowed arm \
1886 requires",
1887 );
1888 assert_eq!(
1889 via_borrowed.as_ref(),
1890 v.as_str(),
1891 "Cow::from(&v) must byte-equal CaixaVersion::as_str",
1892 );
1893 // The borrowed-input impl must not move out of the source.
1894 assert_eq!(
1895 v.as_str(),
1896 versao,
1897 "source CaixaVersion must survive borrowed-input projection",
1898 );
1899 }
1900 }
1901
1902 #[test]
1903 fn caixa_version_from_owned_and_borrowed_into_cow_str_agree_on_every_shape() {
1904 // Fail-before-pass-after cross-axis partition pin: the paired
1905 // owned-input [`From<CaixaVersion> for Cow<'static, str>`] and
1906 // borrowed-input [`From<&CaixaVersion> for Cow<'static, str>`]
1907 // impls resolve to the same bytes on every instance, closing
1908 // the "owned-input move vs. borrowed-input clone" bifurcation
1909 // on the same wrapped body through the [`Cow<'static, str>`]
1910 // axis. Refuses any future silent split between the two
1911 // corners (a normalization on one path only, a divergent
1912 // routing that would let `Cow::from(v.clone())` and
1913 // `Cow::from(&v)` disagree on the same body). Both corners
1914 // must land on [`Cow::Owned`] — the runtime wrapper's storage
1915 // rules out the borrowed arm on both input shapes alike.
1916 use std::borrow::Cow;
1917 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
1918 let v: CaixaVersion = versao.into();
1919 let via_borrowed: Cow<'static, str> = Cow::from(&v);
1920 let via_owned: Cow<'static, str> = Cow::from(v.clone());
1921 assert!(matches!(via_borrowed, Cow::Owned(_)));
1922 assert!(matches!(via_owned, Cow::Owned(_)));
1923 assert_eq!(via_owned.as_ref(), via_borrowed.as_ref());
1924 assert_eq!(via_borrowed.as_ref(), versao);
1925 }
1926 }
1927
1928 #[test]
1929 fn caixa_version_from_into_owned_box_str_returns_wrapped_body() {
1930 // Fail-before-pass-after byte-parity pin on the lifted
1931 // `impl From<CaixaVersion> for Box<str>` — asserts the owned-
1932 // input reverse projection routes the wrapper's own heap
1933 // allocation through [`String::into_boxed_str`] verbatim (no
1934 // re-copy of the underlying bytes on the fixed-capacity path;
1935 // `String::into_boxed_str` reuses the same `Vec<u8>` buffer
1936 // when length matches capacity), so `Box::<str>::from(v)`
1937 // returns the same bytes `v.as_str()` borrows and round-trips
1938 // byte-equal through the paired forward
1939 // [`From<String> for CaixaVersion`] constructor closing the
1940 // two-way `Self → Box<str> → Self` cycle by construction.
1941 // Refuses any future silent detour that would swap
1942 // `v.0.into_boxed_str()` for an allocating
1943 // `.as_str().to_owned().into_boxed_str()` cascade (the pre-lift
1944 // compose shape would double-allocate a fresh intermediary
1945 // [`String`] on the way to the same [`Box<str>`] slot), a
1946 // stray `.trim().to_owned().into_boxed_str()` normalization,
1947 // or a routing through the sibling [`fmt::Display`] emitter
1948 // that would introduce a formatter round-trip.
1949 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
1950 let v: CaixaVersion = versao.into();
1951 let expected = v.as_str().to_owned();
1952 let boxed: Box<str> = Box::<str>::from(v.clone());
1953 assert_eq!(
1954 boxed.as_ref(),
1955 expected.as_str(),
1956 "Box::<str>::from(v) must return the wrapper's own bytes verbatim",
1957 );
1958 let round_trip: CaixaVersion = boxed.into_string().into();
1959 assert_eq!(
1960 round_trip, v,
1961 "Box::<str>::from(v).into_string() must round-trip byte-equal \
1962 through the From<String> constructor",
1963 );
1964 }
1965 }
1966
1967 #[test]
1968 fn caixa_version_from_into_owned_box_str_and_string_agree_on_every_shape() {
1969 // Fail-before-pass-after cross-axis partition pin: the owned-
1970 // input [`From<CaixaVersion> for Box<str>`] reverse projection
1971 // and the paired owned-input [`From<CaixaVersion> for String`]
1972 // and [`From<CaixaVersion> for Cow<'static, str>`] reverse
1973 // projections resolve to the same bytes on every instance, and
1974 // all three agree with the borrowed [`AsRef<str>`] surface on
1975 // the same wrapped body. Refuses any future silent split
1976 // between the three owned-input reverse-projection axes (a
1977 // stray normalization on one path only, a divergent routing
1978 // that would let `Box::<str>::from(v.clone())`,
1979 // `String::from(v.clone())`, and `Cow::from(v.clone())`
1980 // disagree on the same body) that would silently split the
1981 // same-shape owned-move discipline across the three
1982 // reverse-projection targets.
1983 use std::borrow::Cow;
1984 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
1985 let v: CaixaVersion = versao.into();
1986 let via_string: String = String::from(v.clone());
1987 let via_cow: Cow<'static, str> = Cow::from(v.clone());
1988 let via_box: Box<str> = Box::<str>::from(v.clone());
1989 let via_as_ref: &str = <CaixaVersion as AsRef<str>>::as_ref(&v);
1990 assert_eq!(via_box.as_ref(), via_string.as_str());
1991 assert_eq!(via_box.as_ref(), via_cow.as_ref());
1992 assert_eq!(via_box.as_ref(), via_as_ref);
1993 assert_eq!(via_box.as_ref(), versao);
1994 }
1995 }
1996
1997 #[test]
1998 fn caixa_version_from_borrowed_into_owned_box_str_routes_through_as_str_accessor() {
1999 // Fail-before-pass-after byte-parity pin on the lifted
2000 // `impl From<&CaixaVersion> for Box<str>` — asserts the
2001 // borrowed-input reverse projection allocates a fresh
2002 // [`Box<str>`] whose bytes byte-equal the substrate-primitive
2003 // [`CaixaVersion::as_str`] accessor on the same instance,
2004 // preserving the source [`CaixaVersion`] intact (no move-out).
2005 // Refuses any future silent detour that would route the impl
2006 // through a divergent projection (a stray normalization step,
2007 // a swap onto the sibling [`fmt::Display`]-routed
2008 // [`ToString::to_string`] surface followed by
2009 // `.into_boxed_str()`, a re-inlining that dereferences
2010 // `&self.0` outside the shared accessor).
2011 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
2012 let v: CaixaVersion = versao.into();
2013 let via_borrowed: Box<str> = Box::<str>::from(&v);
2014 assert_eq!(
2015 via_borrowed.as_ref(),
2016 v.as_str(),
2017 "Box::<str>::from(&v) must byte-equal CaixaVersion::as_str",
2018 );
2019 // The borrowed-input impl must not move out of the source.
2020 assert_eq!(
2021 v.as_str(),
2022 versao,
2023 "source CaixaVersion must survive borrowed-input projection",
2024 );
2025 }
2026 }
2027
2028 #[test]
2029 fn caixa_version_from_owned_and_borrowed_into_box_str_agree_on_every_shape() {
2030 // Fail-before-pass-after cross-corner partition pin: the paired
2031 // owned-input [`From<CaixaVersion> for Box<str>`] and
2032 // borrowed-input [`From<&CaixaVersion> for Box<str>`] impls
2033 // resolve to the same bytes on every instance, closing the
2034 // "owned-input move vs. borrowed-input clone" bifurcation on
2035 // the same wrapped body through the [`Box<str>`] axis. Refuses
2036 // any future silent split between the two corners (a
2037 // normalization on one path only, a divergent routing that
2038 // would let `Box::<str>::from(v.clone())` and
2039 // `Box::<str>::from(&v)` disagree on the same body).
2040 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
2041 let v: CaixaVersion = versao.into();
2042 let via_borrowed: Box<str> = Box::<str>::from(&v);
2043 let via_owned: Box<str> = Box::<str>::from(v.clone());
2044 assert_eq!(via_owned.as_ref(), via_borrowed.as_ref());
2045 assert_eq!(via_borrowed.as_ref(), versao);
2046 }
2047 }
2048
2049 #[test]
2050 fn caixa_version_from_into_owned_arc_str_returns_wrapped_body() {
2051 // Fail-before-pass-after byte-parity pin on the lifted
2052 // `impl From<CaixaVersion> for std::sync::Arc<str>` — asserts
2053 // the owned-input reverse projection routes the wrapper's own
2054 // [`String`] body through [`std::sync::Arc::<str>::from`]
2055 // verbatim (one heap allocation of the atomically-refcounted
2056 // slab, no intermediary [`String`] or [`Box<str>`] on the
2057 // owned-input path), so `Arc::<str>::from(v)` returns the same
2058 // bytes `v.as_str()` borrows and round-trips byte-equal through
2059 // the paired forward [`From<String> for CaixaVersion`]
2060 // constructor closing the two-way `Self → Arc<str> → Self`
2061 // cycle by construction. Refuses any future silent detour that
2062 // would swap `Arc::<str>::from(v.0)` for an allocating
2063 // `.as_str().to_owned().into()` cascade (the pre-lift compose
2064 // shape would double-allocate a fresh intermediary [`String`]
2065 // on the way to the same [`Arc<str>`] slot), a stray
2066 // `.trim().to_owned().into()` normalization, or a routing
2067 // through the sibling [`fmt::Display`] emitter that would
2068 // introduce a formatter round-trip.
2069 use std::sync::Arc;
2070 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
2071 let v: CaixaVersion = versao.into();
2072 let expected = v.as_str().to_owned();
2073 let arced: Arc<str> = Arc::<str>::from(v.clone());
2074 assert_eq!(
2075 arced.as_ref(),
2076 expected.as_str(),
2077 "Arc::<str>::from(v) must return the wrapper's own bytes verbatim",
2078 );
2079 let round_trip: CaixaVersion = arced.as_ref().to_owned().into();
2080 assert_eq!(
2081 round_trip, v,
2082 "Arc::<str>::from(v) must round-trip byte-equal through \
2083 the From<String> constructor",
2084 );
2085 }
2086 }
2087
2088 #[test]
2089 fn caixa_version_from_into_owned_arc_str_and_string_agree_on_every_shape() {
2090 // Fail-before-pass-after cross-axis partition pin: the owned-
2091 // input [`From<CaixaVersion> for std::sync::Arc<str>`] reverse
2092 // projection and the paired owned-input
2093 // [`From<CaixaVersion> for String`],
2094 // [`From<CaixaVersion> for Cow<'static, str>`], and
2095 // [`From<CaixaVersion> for Box<str>`] reverse projections
2096 // resolve to the same bytes on every instance, and all four
2097 // agree with the borrowed [`AsRef<str>`] surface on the same
2098 // wrapped body. Refuses any future silent split between the
2099 // four owned-input reverse-projection axes (a stray
2100 // normalization on one path only, a divergent routing that
2101 // would let `Arc::<str>::from(v.clone())`,
2102 // `Box::<str>::from(v.clone())`, `String::from(v.clone())`,
2103 // and `Cow::from(v.clone())` disagree on the same body) that
2104 // would silently split the same-shape owned-move discipline
2105 // across the four reverse-projection targets.
2106 use std::borrow::Cow;
2107 use std::sync::Arc;
2108 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
2109 let v: CaixaVersion = versao.into();
2110 let via_string: String = String::from(v.clone());
2111 let via_cow: Cow<'static, str> = Cow::from(v.clone());
2112 let via_box: Box<str> = Box::<str>::from(v.clone());
2113 let via_arc: Arc<str> = Arc::<str>::from(v.clone());
2114 let via_as_ref: &str = <CaixaVersion as AsRef<str>>::as_ref(&v);
2115 assert_eq!(via_arc.as_ref(), via_string.as_str());
2116 assert_eq!(via_arc.as_ref(), via_cow.as_ref());
2117 assert_eq!(via_arc.as_ref(), via_box.as_ref());
2118 assert_eq!(via_arc.as_ref(), via_as_ref);
2119 assert_eq!(via_arc.as_ref(), versao);
2120 }
2121 }
2122
2123 #[test]
2124 fn caixa_version_from_borrowed_into_owned_arc_str_routes_through_as_str_accessor() {
2125 // Fail-before-pass-after byte-parity pin on the lifted
2126 // `impl From<&CaixaVersion> for std::sync::Arc<str>` — asserts
2127 // the borrowed-input reverse projection allocates a fresh
2128 // [`std::sync::Arc<str>`] whose bytes byte-equal the
2129 // substrate-primitive [`CaixaVersion::as_str`] accessor on the
2130 // same instance, preserving the source [`CaixaVersion`] intact
2131 // (no move-out). Refuses any future silent detour that would
2132 // route the impl through a divergent projection (a stray
2133 // normalization step, a swap onto the sibling [`fmt::Display`]-
2134 // routed [`ToString::to_string`] surface followed by
2135 // `.into()`, a re-inlining that dereferences `&self.0` outside
2136 // the shared accessor).
2137 use std::sync::Arc;
2138 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
2139 let v: CaixaVersion = versao.into();
2140 let via_borrowed: Arc<str> = Arc::<str>::from(&v);
2141 assert_eq!(
2142 via_borrowed.as_ref(),
2143 v.as_str(),
2144 "Arc::<str>::from(&v) must byte-equal CaixaVersion::as_str",
2145 );
2146 // The borrowed-input impl must not move out of the source.
2147 assert_eq!(
2148 v.as_str(),
2149 versao,
2150 "source CaixaVersion must survive borrowed-input projection",
2151 );
2152 }
2153 }
2154
2155 #[test]
2156 fn caixa_version_from_owned_and_borrowed_into_arc_str_agree_on_every_shape() {
2157 // Fail-before-pass-after cross-corner partition pin: the paired
2158 // owned-input [`From<CaixaVersion> for std::sync::Arc<str>`]
2159 // and borrowed-input [`From<&CaixaVersion> for std::sync::Arc<str>`]
2160 // impls resolve to the same bytes on every instance, closing
2161 // the "owned-input move vs. borrowed-input clone" bifurcation
2162 // on the same wrapped body through the [`std::sync::Arc<str>`]
2163 // axis. Refuses any future silent split between the two
2164 // corners (a normalization on one path only, a divergent
2165 // routing that would let `Arc::<str>::from(v.clone())` and
2166 // `Arc::<str>::from(&v)` disagree on the same body).
2167 use std::sync::Arc;
2168 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
2169 let v: CaixaVersion = versao.into();
2170 let via_borrowed: Arc<str> = Arc::<str>::from(&v);
2171 let via_owned: Arc<str> = Arc::<str>::from(v.clone());
2172 assert_eq!(via_owned.as_ref(), via_borrowed.as_ref());
2173 assert_eq!(via_borrowed.as_ref(), versao);
2174 }
2175 }
2176
2177 #[test]
2178 fn caixa_version_from_into_owned_rc_str_returns_wrapped_body() {
2179 // Fail-before-pass-after byte-parity pin on the lifted
2180 // `impl From<CaixaVersion> for std::rc::Rc<str>` — asserts the
2181 // owned-input reverse projection routes the wrapper's own
2182 // [`String`] body through [`std::rc::Rc::<str>::from`] verbatim
2183 // (one heap allocation of the single-threaded-refcounted slab, no
2184 // intermediary [`String`] or [`Box<str>`] on the owned-input
2185 // path), so `Rc::<str>::from(v)` returns the same bytes
2186 // `v.as_str()` borrows and round-trips byte-equal through the
2187 // paired forward [`From<String> for CaixaVersion`] constructor
2188 // closing the two-way `Self → Rc<str> → Self` cycle by
2189 // construction. Refuses any future silent detour that would swap
2190 // `Rc::<str>::from(v.0)` for an allocating
2191 // `.as_str().to_owned().into()` cascade (the pre-lift compose
2192 // shape would double-allocate a fresh intermediary [`String`] on
2193 // the way to the same [`Rc<str>`] slot), a stray
2194 // `.trim().to_owned().into()` normalization, or a routing through
2195 // the sibling [`fmt::Display`] emitter that would introduce a
2196 // formatter round-trip.
2197 use std::rc::Rc;
2198 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
2199 let v: CaixaVersion = versao.into();
2200 let expected = v.as_str().to_owned();
2201 let rced: Rc<str> = Rc::<str>::from(v.clone());
2202 assert_eq!(
2203 rced.as_ref(),
2204 expected.as_str(),
2205 "Rc::<str>::from(v) must return the wrapper's own bytes verbatim",
2206 );
2207 let round_trip: CaixaVersion = rced.as_ref().to_owned().into();
2208 assert_eq!(
2209 round_trip, v,
2210 "Rc::<str>::from(v) must round-trip byte-equal through \
2211 the From<String> constructor",
2212 );
2213 }
2214 }
2215
2216 #[test]
2217 fn caixa_version_from_into_owned_rc_str_and_arc_str_agree_on_every_shape() {
2218 // Fail-before-pass-after cross-axis partition pin: the owned-
2219 // input [`From<CaixaVersion> for std::rc::Rc<str>`] reverse
2220 // projection and the paired owned-input
2221 // [`From<CaixaVersion> for String`],
2222 // [`From<CaixaVersion> for Cow<'static, str>`],
2223 // [`From<CaixaVersion> for Box<str>`], and
2224 // [`From<CaixaVersion> for std::sync::Arc<str>`] reverse
2225 // projections resolve to the same bytes on every instance, and
2226 // all five agree with the borrowed [`AsRef<str>`] surface on the
2227 // same wrapped body. Refuses any future silent split between the
2228 // five owned-input reverse-projection axes (a stray normalization
2229 // on one path only, a divergent routing that would let
2230 // `Rc::<str>::from(v.clone())`, `Arc::<str>::from(v.clone())`,
2231 // `Box::<str>::from(v.clone())`, `String::from(v.clone())`, and
2232 // `Cow::from(v.clone())` disagree on the same body) that would
2233 // silently split the same-shape owned-move discipline across the
2234 // five reverse-projection targets.
2235 use std::borrow::Cow;
2236 use std::rc::Rc;
2237 use std::sync::Arc;
2238 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
2239 let v: CaixaVersion = versao.into();
2240 let owned_string: String = String::from(v.clone());
2241 let owned_cow: Cow<'static, str> = Cow::from(v.clone());
2242 let owned_box: Box<str> = Box::<str>::from(v.clone());
2243 let atomic_handle: Arc<str> = Arc::<str>::from(v.clone());
2244 let single_handle: Rc<str> = Rc::<str>::from(v.clone());
2245 let borrowed_as_ref: &str = <CaixaVersion as AsRef<str>>::as_ref(&v);
2246 assert_eq!(single_handle.as_ref(), owned_string.as_str());
2247 assert_eq!(single_handle.as_ref(), owned_cow.as_ref());
2248 assert_eq!(single_handle.as_ref(), owned_box.as_ref());
2249 assert_eq!(single_handle.as_ref(), atomic_handle.as_ref());
2250 assert_eq!(single_handle.as_ref(), borrowed_as_ref);
2251 assert_eq!(single_handle.as_ref(), versao);
2252 }
2253 }
2254
2255 #[test]
2256 fn caixa_version_from_borrowed_into_owned_rc_str_routes_through_as_str_accessor() {
2257 // Fail-before-pass-after byte-parity pin on the lifted
2258 // `impl From<&CaixaVersion> for std::rc::Rc<str>` — asserts the
2259 // borrowed-input reverse projection allocates a fresh
2260 // [`std::rc::Rc<str>`] whose bytes byte-equal the substrate-
2261 // primitive [`CaixaVersion::as_str`] accessor on the same
2262 // instance, preserving the source [`CaixaVersion`] intact (no
2263 // move-out). Refuses any future silent detour that would route
2264 // the impl through a divergent projection (a stray normalization
2265 // step, a swap onto the sibling [`fmt::Display`]-routed
2266 // [`ToString::to_string`] surface followed by `.into()`, a
2267 // re-inlining that dereferences `&self.0` outside the shared
2268 // accessor).
2269 use std::rc::Rc;
2270 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
2271 let v: CaixaVersion = versao.into();
2272 let via_borrowed: Rc<str> = Rc::<str>::from(&v);
2273 assert_eq!(
2274 via_borrowed.as_ref(),
2275 v.as_str(),
2276 "Rc::<str>::from(&v) must byte-equal CaixaVersion::as_str",
2277 );
2278 // The borrowed-input impl must not move out of the source.
2279 assert_eq!(
2280 v.as_str(),
2281 versao,
2282 "source CaixaVersion must survive borrowed-input projection",
2283 );
2284 }
2285 }
2286
2287 #[test]
2288 fn caixa_version_from_owned_and_borrowed_into_rc_str_agree_on_every_shape() {
2289 // Fail-before-pass-after cross-corner partition pin: the paired
2290 // owned-input [`From<CaixaVersion> for std::rc::Rc<str>`] and
2291 // borrowed-input [`From<&CaixaVersion> for std::rc::Rc<str>`]
2292 // impls resolve to the same bytes on every instance, closing the
2293 // "owned-input move vs. borrowed-input clone" bifurcation on the
2294 // same wrapped body through the [`std::rc::Rc<str>`] axis.
2295 // Refuses any future silent split between the two corners (a
2296 // normalization on one path only, a divergent routing that would
2297 // let `Rc::<str>::from(v.clone())` and `Rc::<str>::from(&v)`
2298 // disagree on the same body).
2299 use std::rc::Rc;
2300 for versao in ["0.1.0", "1.2.3-alpha.1", "0.0.0", ""] {
2301 let v: CaixaVersion = versao.into();
2302 let via_borrowed: Rc<str> = Rc::<str>::from(&v);
2303 let via_owned: Rc<str> = Rc::<str>::from(v.clone());
2304 assert_eq!(via_owned.as_ref(), via_borrowed.as_ref());
2305 assert_eq!(via_borrowed.as_ref(), versao);
2306 }
2307 }
2308}