armour 0.30.27

DDL and serialization for key-value storage
Documentation
#![warn(clippy::unwrap_used)]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg_attr(not(feature = "std"), macro_use)]
#[cfg(not(feature = "std"))]
extern crate alloc;

#[macro_use]
extern crate tracing;
#[macro_use]
extern crate metrics;

pub use armour_core;
pub use armour_derive::*;
pub use async_broadcast::RecvError;
pub use cid::{Cid, KeyScheme, KeyType};
pub use dyn_types::{Typ, get_type::GetType, value::Value};
pub use error::{DbError, DbResult};
#[cfg(feature = "fjall")]
pub use fjall::{self, Slice};
pub use indexes::index::{CompositionIndex, HashIndexExtractor};
#[cfg(feature = "fjall")]
pub use logdb::{IterTree, db::Db, read::ReadTree, tree::TypedTree};
pub use rapira;
pub use record::{Migration, Record};
#[cfg(feature = "fjall")]
pub use transactional::{db::TxDb, raw::TxRawTree, read::TxReadTree, tree::TxTree};
pub use types::{entry::Entry, fuid::Fuid, id64::Id64, record_status::RecordStatus};

pub mod cid;
pub mod dyn_types;
pub mod error;
pub mod indexes;
#[cfg(feature = "fjall")]
pub mod logdb;
#[cfg(feature = "fjall")]
mod migration;
pub mod record;
pub mod replication;
#[cfg(feature = "fjall")]
pub mod snapshot;
#[cfg(feature = "fjall")]
pub mod transactional;
pub mod types;
pub mod utils;

#[cfg(feature = "rpc")]
pub mod rpc;

pub mod migrations {
    pub use crate::record::{MigrationRes, MigrationType};
}

pub type KV<K, V> = (K, V);

pub use armour_core::const_hasher;
pub use armour_core::hasher;

/// rapira_record!(User, UserID, sled::InlineArray, "users")
#[macro_export]
macro_rules! rapira_record {
    ($ty: ty, $id_ty: ty, $value_ty: ty, $name: literal) => {
        impl $crate::Record for $ty {
            type SelfId = $id_ty;
            type Value = $value_ty;
            const NAME: &'static str = $name;
            const SIZE: Option<usize> = <Self as rapira::Rapira>::STATIC_SIZE;
            fn deser(bytes: &Self::Value) -> Self {
                rapira::deserialize(bytes.as_ref()).unwrap()
            }
            fn ser(&self) -> $value_ty {
                rapira::serialize(self).into()
            }
        }
    };
}

/// zerocopy_record!(User, UserID, sled::InlineArray, "users")
#[macro_export]
macro_rules! zerocopy_record {
    ($ty: ty, $id_ty: ty, $value_ty: ty, $name: literal) => {
        impl $ty {
            const INNER_SIZE: usize = std::mem::size_of::<$ty>();
        }
        impl $crate::Record for $ty {
            type SelfId = $id_ty;
            type Value = $value_ty;
            const NAME: &'static str = $name;
            const SIZE: Option<usize> = Some(Self::INNER_SIZE);
            fn deser(bytes: &Self::Value) -> Self {
                let bytes: &[u8] = bytes.as_ref();
                let bytes: [u8; Self::INNER_SIZE] = bytes.try_into().unwrap();
                zerocopy::transmute!(bytes)
            }
            fn ser(&self) -> $value_ty {
                let bytes: &[u8; Self::INNER_SIZE] = zerocopy::transmute_ref!(self);
                bytes.into()
            }
        }
    };
}

/// bytemuck_record!(User, UserID, sled::InlineArray, "users")
#[macro_export]
macro_rules! bytemuck_slice_record {
    ($ty: ty, $id_ty: ty, $value_ty: ty, $name: literal) => {
        impl $crate::Record for $ty {
            type SelfId = $id_ty;
            type Value = $value_ty;
            const NAME: &'static str = $name;
            fn deser(bytes: &Self::Value) -> Self {
                if bytes.is_empty() {
                    return Default::default();
                }
                let vec = bytes.as_ref().to_vec();
                let vec: Vec<ProfileId> = bytemuck::cast_vec(vec);
                Self(vec)
            }
            fn ser(&self) -> $value_ty {
                let bytes: &[u8] = bytemuck::cast_slice(self);
                bytes.to_vec().into()
            }
        }
    };
}

/// `zerocopy_cid!(Key, [KeyType::U64...], Type::GROUP_BITS, field_name)`
#[macro_export]
macro_rules! zerocopy_cid {
    ($ty: ty, [$($key_type:expr),*], $group_bits:expr, $field:ident) => {
        impl $crate::Cid for $ty {
            type B = [u8; size_of::<Self>()];
            const TY: $crate::KeyScheme = $crate::KeyScheme::Typed(&[$($key_type),*]);
            const GROUP_BITS: u32 = $group_bits;
            fn encode(&self) -> Self::B {
                zerocopy::transmute!(*self)
            }
            fn decode(bytes: &Self::B) -> armour::types::Result<Self> {
                Ok(zerocopy::transmute!(*bytes))
            }
            fn group_id(&self) -> u32 {
                self.$field.group_id()
            }
        }
    };
}

#[cfg(test)]
mod tests {
    use rapira::Rapira;

    use super::*;
    use crate::types::id64::Id64;

    #[derive(Clone, Rapira)]
    struct User {
        name: String,
    }

    impl GetType for User {
        const TYPE: Typ = Typ::Custom("unimplemented", &[]);
    }

    const_hasher!(test_key, "TEST");
    type UserID = Id64<test_key::Hasher>;
    rapira_record!(User, UserID, Vec<u8>, "users");

    #[test]
    fn test_rapira_record() {
        let _user = User {
            name: "John Doe".to_string(),
        };
    }
}