weiss_core/db/
serialization.rs

1use std::fs;
2use std::path::Path;
3
4use anyhow::{Context, Result};
5
6use super::store::CardDb;
7
8const WSDB_MAGIC: &[u8; 4] = b"WSDB";
9/// Current wsdb schema version.
10pub const WSDB_SCHEMA_VERSION: u32 = 2;
11
12impl CardDb {
13    /// Load a WSDB v2 file from disk.
14    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
15        let bytes = fs::read(&path)
16            .with_context(|| format!("Failed to read card db {:?}", path.as_ref()))?;
17        Self::from_wsdb_bytes(&bytes)
18    }
19
20    /// Parse a WSDB v2 file from bytes.
21    pub fn from_wsdb_bytes(bytes: &[u8]) -> Result<Self> {
22        if bytes.len() < 8 {
23            anyhow::bail!("Card db file too small");
24        }
25        if &bytes[0..4] != WSDB_MAGIC {
26            anyhow::bail!("Card db magic mismatch; expected WSDB header");
27        }
28        let version = u32::from_le_bytes(
29            bytes[4..8]
30                .try_into()
31                .map_err(|_| anyhow::anyhow!("Card db header missing version bytes"))?,
32        );
33        if version != WSDB_SCHEMA_VERSION {
34            anyhow::bail!(
35                "Unsupported card db schema version {version}, expected {WSDB_SCHEMA_VERSION}. \
36                 This build only loads WSDB v2 files; regenerate the card DB with the current \
37                 parser-v2 rule-pack pipeline."
38            );
39        }
40        let payload = &bytes[8..];
41        Self::from_postcard_payload(payload)
42    }
43
44    /// Parse the postcard payload (without WSDB header) into a `CardDb`.
45    pub fn from_postcard_payload(payload: &[u8]) -> Result<Self> {
46        let mut db: CardDb =
47            postcard::from_bytes(payload).context("Failed to decode card db payload")?;
48        db.build_index()?;
49        Ok(db)
50    }
51
52    /// Return the current WSDB schema version supported by this build.
53    pub fn schema_version() -> u32 {
54        WSDB_SCHEMA_VERSION
55    }
56
57    /// Serialize this database to a WSDB v2 byte buffer (including header).
58    pub fn to_bytes_with_header(&self) -> Result<Vec<u8>> {
59        let payload = postcard::to_stdvec(self)?;
60        let mut out = Vec::with_capacity(8 + payload.len());
61        out.extend_from_slice(WSDB_MAGIC);
62        out.extend_from_slice(&WSDB_SCHEMA_VERSION.to_le_bytes());
63        out.extend_from_slice(&payload);
64        Ok(out)
65    }
66}