armour/
lib.rs

1#![warn(clippy::unwrap_used)]
2#![cfg_attr(not(feature = "std"), no_std)]
3#[cfg_attr(not(feature = "std"), macro_use)]
4#[cfg(not(feature = "std"))]
5extern crate alloc;
6
7#[macro_use]
8extern crate tracing;
9#[macro_use]
10extern crate metrics;
11
12pub use armour_derive::*;
13pub use async_broadcast::RecvError;
14pub use cid::{Cid, KeyScheme, KeyType, key_size};
15#[cfg(feature = "sled")]
16pub use database::{db::Database, raw_tree::RawTree, tree::CollectionTree};
17pub use dyn_types::{Typ, get_type::GetType, value::Value};
18pub use error::{DbError, DbResult};
19#[cfg(feature = "fjall")]
20pub use fjall::{self, Slice};
21pub use indexes::index::{CompositionIndex, HashIndexExtractor};
22pub use rapira;
23pub use record::{Migration, Record};
24#[cfg(feature = "sled")]
25pub use sled::{self, InlineArray};
26#[cfg(feature = "fjall")]
27pub use transactional::{db::TxDb, raw::TxRawTree, tree::TxTree};
28pub use types::{entry::Entry, fuid::Fuid, id64::Id64, record_status::RecordStatus};
29#[cfg(all(feature = "sled", feature = "id32"))]
30pub use types::{ident::ID, low_id::LowId, uid::Uid};
31
32#[cfg(feature = "bytemuck")]
33pub use crate::database::byte_as_slice::BytesAsValSlice;
34
35pub mod cid;
36#[cfg(feature = "sled")]
37pub mod database;
38pub mod dyn_types;
39pub mod error;
40pub mod indexes;
41#[cfg(feature = "fjall")]
42pub mod logdb;
43pub mod record;
44pub mod replication;
45#[cfg(feature = "fjall")]
46pub mod transactional;
47pub mod types;
48pub mod utils;
49
50pub mod migrations {
51    pub use crate::record::{MigrationRes, MigrationType};
52}
53
54pub type KV<K, V> = (K, V);
55
56/// key should be Base64Url decoded 56 bytes long (~ 75 chars)
57///
58/// `const_hasher!(module_name, "ENV_KEY_NAME");`
59///
60/// env key concatenated with "APP_ID_KEY_" will be used to get the key
61#[macro_export]
62macro_rules! const_hasher {
63    ($m_name: ident, $key_name: literal) => {
64        pub mod $m_name {
65            use $crate::types::enc::{Cipher, IdHasher};
66
67            #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)]
68            pub struct Hasher;
69
70            impl IdHasher for Hasher {
71                const HASHER: Cipher = Cipher::new(env!(concat!("APP_ID_KEY_", $key_name)));
72            }
73        }
74    };
75}
76
77/// key should be Base64Url decoded 56 bytes long (~ 75 chars)
78///
79/// `hasher!(module_name, "hash_key");`
80#[macro_export]
81macro_rules! hasher {
82    ($m_name: ident, $key: literal) => {
83        pub mod $m_name {
84            use $crate::types::enc::{Cipher, IdHasher};
85
86            #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)]
87            pub struct Hasher;
88
89            impl IdHasher for Hasher {
90                const HASHER: Cipher = Cipher::new($key);
91            }
92        }
93    };
94}
95
96/// rapira_record!(User, UserID, sled::InlineArray, "users")
97#[macro_export]
98macro_rules! rapira_record {
99    ($ty: ty, $id_ty: ty, $value_ty: ty, $name: literal) => {
100        impl $crate::Record for $ty {
101            type SelfId = $id_ty;
102            type Value = $value_ty;
103            const NAME: &'static str = $name;
104            fn deser(bytes: &Self::Value) -> Self {
105                rapira::deserialize(bytes.as_ref()).unwrap()
106            }
107            fn ser(&self) -> $value_ty {
108                rapira::serialize(self).into()
109            }
110        }
111    };
112}
113
114/// zerocopy_record!(User, UserID, sled::InlineArray, "users")
115#[macro_export]
116macro_rules! zerocopy_record {
117    ($ty: ty, $id_ty: ty, $value_ty: ty, $name: literal) => {
118        const SIZE: usize = std::mem::size_of::<$ty>();
119        impl $crate::Record for $ty {
120            type SelfId = $id_ty;
121            type Value = $value_ty;
122            const NAME: &'static str = $name;
123            fn deser(bytes: &Self::Value) -> Self {
124                let bytes: &[u8] = bytes.as_ref();
125                let bytes: [u8; SIZE] = bytes.try_into().unwrap();
126                zerocopy::transmute!(bytes)
127            }
128            fn ser(&self) -> $value_ty {
129                let bytes: &[u8; SIZE] = zerocopy::transmute_ref!(self);
130                bytes.into()
131            }
132        }
133    };
134}
135
136/// bytemuck_record!(User, UserID, sled::InlineArray, "users")
137#[macro_export]
138macro_rules! bytemuck_slice_record {
139    ($ty: ty, $id_ty: ty, $value_ty: ty, $name: literal) => {
140        impl $crate::Record for $ty {
141            type SelfId = $id_ty;
142            type Value = $value_ty;
143            const NAME: &'static str = $name;
144            fn deser(bytes: &Self::Value) -> Self {
145                if bytes.is_empty() {
146                    return Default::default();
147                }
148                let vec = bytes.as_ref().to_vec();
149                let vec: Vec<ProfileId> = bytemuck::cast_vec(vec);
150                Self(vec)
151            }
152            fn ser(&self) -> $value_ty {
153                let bytes: &[u8] = bytemuck::cast_slice(self);
154                bytes.to_vec().into()
155            }
156        }
157    };
158}
159
160/// `zerocopy_cid!(Key, [KeyType::U64...], Type::GROUP_BITS, field_name)`
161#[macro_export]
162macro_rules! zerocopy_cid {
163    ($ty: ty, [$($key_type:expr),*], $group_bits:expr, $field:ident) => {
164        impl $crate::Cid for $ty {
165            type B = [u8; size_of::<Self>()];
166            const TY: $crate::KeyScheme = $crate::KeyScheme::Typed(&[$($key_type),*]);
167            const GROUP_BITS: u32 = $group_bits;
168            fn encode(&self) -> Self::B {
169                zerocopy::transmute!(*self)
170            }
171            fn decode(bytes: &Self::B) -> armour::types::Result<Self> {
172                Ok(zerocopy::transmute!(*bytes))
173            }
174            fn group_id(&self) -> u32 {
175                self.$field.group_id()
176            }
177        }
178    };
179}
180
181#[cfg(test)]
182mod tests {
183    use rapira::Rapira;
184
185    use super::*;
186    use crate::types::id64::Id64;
187
188    #[derive(Clone, Rapira)]
189    struct User {
190        name: String,
191    }
192
193    impl GetType for User {
194        const TYPE: Typ = Typ::Custom("unimplemented", &[]);
195    }
196
197    const_hasher!(test_key, "TEST");
198    type UserID = Id64<test_key::Hasher>;
199    rapira_record!(User, UserID, Vec<u8>, "users");
200
201    #[test]
202    fn test_rapira_record() {
203        let _user = User {
204            name: "John Doe".to_string(),
205        };
206    }
207}