Skip to main content

entelix_persistence/
schema_version.rs

1//! Persisted-payload schema version stamps.
2//!
3//! Every JSON blob written through this crate carries a
4//! [`SessionSchemaVersion`] tag. On read, payloads with versions
5//! outside the build's accepted range surface as
6//! [`crate::PersistenceError::SchemaVersionMismatch`]. Silent
7//! degradation is forbidden — a future-version payload is rejected
8//! hard so a downgrade never corrupts state by writing back a
9//! lower-version blob.
10
11use serde::{Deserialize, Serialize};
12
13use crate::error::{PersistenceError, PersistenceResult};
14
15/// Highest schema version this build can read and write.
16pub const CURRENT_VERSION: u32 = 1;
17
18/// Lowest schema version this build still understands. When
19/// migrations land, bump this only after the migration ladder writes
20/// every prior payload to the new shape.
21pub const MIN_SUPPORTED_VERSION: u32 = 1;
22
23/// Schema version tag for persisted payloads.
24#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
25#[serde(transparent)]
26pub struct SessionSchemaVersion(pub u32);
27
28impl SessionSchemaVersion {
29    /// The version this build emits.
30    pub const CURRENT: Self = Self(CURRENT_VERSION);
31
32    /// Validate that `payload` is in `[MIN_SUPPORTED_VERSION,
33    /// CURRENT_VERSION]`. Errors are loud — never silently downgrade.
34    pub fn validate(self) -> PersistenceResult<()> {
35        if self.0 < MIN_SUPPORTED_VERSION || self.0 > CURRENT_VERSION {
36            return Err(PersistenceError::SchemaVersionMismatch {
37                payload: self.0,
38                min: MIN_SUPPORTED_VERSION,
39                current: CURRENT_VERSION,
40            });
41        }
42        Ok(())
43    }
44
45    /// Raw integer.
46    pub const fn raw(self) -> u32 {
47        self.0
48    }
49}
50
51impl Default for SessionSchemaVersion {
52    fn default() -> Self {
53        Self::CURRENT
54    }
55}