//! Persistence interface for complete validated candidate snapshots. use core::num::NonZeroU64; /// Storage-owned monotonically increasing committed snapshot generation. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct Generation(NonZeroU64); impl Generation { /// Creates a generation supplied only by a persistence backend. pub const fn new(value: u64) -> Self { match NonZeroU64::new(value) { Some(value) => Self(value), None => panic!("configuration generation must be nonzero"), } } /// Parses an on-disk or wire generation, rejecting the factory sentinel. pub const fn try_new(value: u64) -> Option { match NonZeroU64::new(value) { Some(value) => Some(Self(value)), None => None, } } /// Returns the committed generation value. pub const fn get(self) -> u64 { self.0.get() } } /// Durable storage of complete configuration snapshots. /// /// Flight implementations use a two-slot journal: a record contains a header, /// bounded CBOR payload, integrity check, and a commit marker written last. /// A backend must retain its previous valid record until the replacement is /// fully verified. Host file stores may implement the same interface without /// claiming flash power-loss semantics. pub trait ProfileStore { /// Backend-specific I/O or integrity failure. type Error; /// Loads the newest valid committed candidate, if one exists. fn load(&mut self) -> Result, Self::Error>; /// Persists one complete already-validated candidate atomically. fn persist(&mut self, candidate: &C) -> Result; }