Skip to main content

tycho_storage/kv/
models.rs

1use std::marker::PhantomData;
2
3use weedb::{ColumnFamily, MigrationError, Semver, VersionProvider, WeeDbRaw};
4
5use super::NamedTables;
6
7#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
8#[repr(transparent)]
9pub struct InstanceId(pub [u8; 16]);
10
11impl InstanceId {
12    #[inline]
13    pub fn from_slice(slice: &[u8]) -> Self {
14        Self(slice.try_into().expect("slice with incorrect length"))
15    }
16}
17
18impl rand::distr::Distribution<InstanceId> for rand::distr::StandardUniform {
19    #[inline]
20    fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> InstanceId {
21        InstanceId(rng.random())
22    }
23}
24
25impl AsRef<[u8]> for InstanceId {
26    #[inline(always)]
27    fn as_ref(&self) -> &[u8] {
28        self.0.as_ref()
29    }
30}
31
32pub struct StateVersionProvider<C> {
33    db_name: &'static str,
34    cf: PhantomData<C>,
35}
36
37impl<C> StateVersionProvider<C> {
38    pub const DB_NAME_KEY: &'static [u8] = b"__db_name";
39    pub const DB_VERSION_KEY: &'static [u8] = b"__db_version";
40
41    pub fn new<T: NamedTables>() -> Self
42    where
43        C: ColumnFamily,
44    {
45        Self {
46            db_name: T::NAME,
47            cf: PhantomData,
48        }
49    }
50}
51
52impl<C: ColumnFamily> VersionProvider for StateVersionProvider<C> {
53    fn get_version(&self, db: &WeeDbRaw) -> Result<Option<Semver>, MigrationError> {
54        let state = db.instantiate_table::<C>();
55
56        if let Some(db_name) = state.get(Self::DB_NAME_KEY)?
57            && db_name.as_ref() != self.db_name.as_bytes()
58        {
59            return Err(MigrationError::Custom(
60                format!(
61                    "expected db name: {}, got: {}",
62                    self.db_name,
63                    String::from_utf8_lossy(db_name.as_ref())
64                )
65                .into(),
66            ));
67        }
68
69        let value = state.get(Self::DB_VERSION_KEY)?;
70        match value {
71            Some(version) => {
72                let slice = version.as_ref();
73                slice
74                    .try_into()
75                    .map_err(|_e| MigrationError::InvalidDbVersion)
76                    .map(Some)
77            }
78            None => Ok(None),
79        }
80    }
81
82    fn set_version(&self, db: &WeeDbRaw, version: Semver) -> Result<(), MigrationError> {
83        let state = db.instantiate_table::<C>();
84        state.insert(Self::DB_NAME_KEY, self.db_name.as_bytes())?;
85        state.insert(Self::DB_VERSION_KEY, version)?;
86        Ok(())
87    }
88}