cuprate_database/
storable.rs

1//! (De)serialization for table keys & values.
2
3//---------------------------------------------------------------------------------------------------- Import
4use std::{
5    borrow::{Borrow, Cow},
6    fmt::Debug,
7};
8
9use bytemuck::Pod;
10use bytes::Bytes;
11
12//---------------------------------------------------------------------------------------------------- Storable
13/// A type that can be stored in the database.
14///
15/// All keys and values in the database must be able
16/// to be (de)serialized into/from raw bytes (`[u8]`).
17///
18/// This trait represents types that can be **perfectly**
19/// casted/represented as raw bytes.
20///
21/// ## `bytemuck`
22/// Any type that implements:
23/// - [`bytemuck::Pod`]
24/// - [`Debug`]
25///
26/// will automatically implement [`Storable`].
27///
28/// See [`StorableVec`] & [`StorableBytes`] for storing slices of `T: Storable`.
29///
30/// ```rust
31/// # use cuprate_database::*;
32/// # use std::borrow::*;
33/// let number: u64 = 0;
34///
35/// // Into bytes.
36/// let into = Storable::as_bytes(&number);
37/// assert_eq!(into, &[0; 8]);
38///
39/// // From bytes.
40/// let from: u64 = Storable::from_bytes(&into);
41/// assert_eq!(from, number);
42/// ```
43///
44/// ## Invariants
45/// No function in this trait is expected to panic.
46///
47/// The byte conversions must execute flawlessly.
48///
49/// ## Endianness
50/// This trait doesn't currently care about endianness.
51///
52/// Bytes are (de)serialized as-is, and `bytemuck`
53/// types are architecture-dependant.
54///
55/// Most likely, the bytes are little-endian, however
56/// that cannot be relied upon when using this trait.
57pub trait Storable: Debug {
58    /// Is this type fixed width in byte length?
59    ///
60    /// I.e., when converting `Self` to bytes, is it
61    /// represented with a fixed length array of bytes?
62    ///
63    /// # `Some`
64    /// This should be `Some(usize)` on types like:
65    /// - `u8`
66    /// - `u64`
67    /// - `i32`
68    ///
69    /// where the byte length is known.
70    ///
71    /// # `None`
72    /// This should be `None` on any variable-length type like:
73    /// - `str`
74    /// - `[u8]`
75    /// - `Vec<u8>`
76    ///
77    /// # Examples
78    /// ```rust
79    /// # use cuprate_database::*;
80    /// assert_eq!(<()>::BYTE_LENGTH, Some(0));
81    /// assert_eq!(u8::BYTE_LENGTH, Some(1));
82    /// assert_eq!(u16::BYTE_LENGTH, Some(2));
83    /// assert_eq!(u32::BYTE_LENGTH, Some(4));
84    /// assert_eq!(u64::BYTE_LENGTH, Some(8));
85    /// assert_eq!(i8::BYTE_LENGTH, Some(1));
86    /// assert_eq!(i16::BYTE_LENGTH, Some(2));
87    /// assert_eq!(i32::BYTE_LENGTH, Some(4));
88    /// assert_eq!(i64::BYTE_LENGTH, Some(8));
89    /// assert_eq!(StorableVec::<u8>::BYTE_LENGTH, None);
90    /// assert_eq!(StorableVec::<u64>::BYTE_LENGTH, None);
91    /// ```
92    const BYTE_LENGTH: Option<usize>;
93
94    /// Return `self` in byte form.
95    fn as_bytes(&self) -> &[u8];
96
97    /// Create an owned [`Self`] from bytes.
98    ///
99    /// # Blanket implementation
100    /// The blanket implementation that covers all types used
101    /// by `cuprate_database` will simply bitwise copy `bytes`
102    /// into `Self`.
103    ///
104    /// The bytes do not have be correctly aligned.
105    fn from_bytes(bytes: &[u8]) -> Self;
106}
107
108impl<T> Storable for T
109where
110    Self: Pod + Debug,
111{
112    const BYTE_LENGTH: Option<usize> = Some(size_of::<T>());
113
114    #[inline]
115    fn as_bytes(&self) -> &[u8] {
116        bytemuck::bytes_of(self)
117    }
118
119    #[inline]
120    fn from_bytes(bytes: &[u8]) -> T {
121        bytemuck::pod_read_unaligned(bytes)
122    }
123}
124
125//---------------------------------------------------------------------------------------------------- StorableVec
126/// A [`Storable`] vector of `T: Storable`.
127///
128/// This is a wrapper around `Vec<T> where T: Storable`.
129///
130/// Slice types are owned both:
131/// - when returned from the database
132/// - in [`crate::DatabaseRw::put()`]
133///
134/// This is needed as `impl Storable for Vec<T>` runs into impl conflicts.
135///
136/// # Example
137/// ```rust
138/// # use cuprate_database::*;
139/// //---------------------------------------------------- u8
140/// let vec: StorableVec<u8> = StorableVec(vec![0,1]);
141///
142/// // Into bytes.
143/// let into = Storable::as_bytes(&vec);
144/// assert_eq!(into, &[0,1]);
145///
146/// // From bytes.
147/// let from: StorableVec<u8> = Storable::from_bytes(&into);
148/// assert_eq!(from, vec);
149///
150/// //---------------------------------------------------- u64
151/// let vec: StorableVec<u64> = StorableVec(vec![0,1]);
152///
153/// // Into bytes.
154/// let into = Storable::as_bytes(&vec);
155/// assert_eq!(into, &[0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0]);
156///
157/// // From bytes.
158/// let from: StorableVec<u64> = Storable::from_bytes(&into);
159/// assert_eq!(from, vec);
160/// ```
161#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck::TransparentWrapper)]
162#[repr(transparent)]
163pub struct StorableVec<T>(pub Vec<T>);
164
165impl<T> Storable for StorableVec<T>
166where
167    T: Pod + Debug,
168{
169    const BYTE_LENGTH: Option<usize> = None;
170
171    /// Casts the inner `Vec<T>` directly as bytes.
172    #[inline]
173    fn as_bytes(&self) -> &[u8] {
174        bytemuck::must_cast_slice(&self.0)
175    }
176
177    /// This always allocates a new `Vec<T>`,
178    /// casting `bytes` into a vector of type `T`.
179    #[inline]
180    fn from_bytes(bytes: &[u8]) -> Self {
181        Self(bytemuck::pod_collect_to_vec(bytes))
182    }
183}
184
185impl<T> std::ops::Deref for StorableVec<T> {
186    type Target = [T];
187    #[inline]
188    fn deref(&self) -> &[T] {
189        &self.0
190    }
191}
192
193impl<T> Borrow<[T]> for StorableVec<T> {
194    #[inline]
195    fn borrow(&self) -> &[T] {
196        &self.0
197    }
198}
199
200//---------------------------------------------------------------------------------------------------- StorableVec
201/// A [`Storable`] string.
202///
203/// This is a wrapper around a `Cow<'static, str>`
204/// that can be stored in the database.
205///
206/// # Invariant
207/// [`StorableStr::from_bytes`] will panic
208/// if the bytes are not UTF-8. This should normally
209/// not be possible in database operations, although technically
210/// you can call this function yourself and input bad data.
211///
212/// # Example
213/// ```rust
214/// # use cuprate_database::*;
215/// # use std::borrow::Cow;
216/// let string: StorableStr = StorableStr(Cow::Borrowed("a"));
217///
218/// // Into bytes.
219/// let into = Storable::as_bytes(&string);
220/// assert_eq!(into, &[97]);
221///
222/// // From bytes.
223/// let from: StorableStr = Storable::from_bytes(&into);
224/// assert_eq!(from, string);
225/// ```
226#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck::TransparentWrapper)]
227#[repr(transparent)]
228pub struct StorableStr(pub Cow<'static, str>);
229
230impl Storable for StorableStr {
231    const BYTE_LENGTH: Option<usize> = None;
232
233    /// [`String::as_bytes`].
234    #[inline]
235    fn as_bytes(&self) -> &[u8] {
236        self.0.as_bytes()
237    }
238
239    #[inline]
240    fn from_bytes(bytes: &[u8]) -> Self {
241        Self(Cow::Owned(std::str::from_utf8(bytes).unwrap().to_string()))
242    }
243}
244
245impl std::ops::Deref for StorableStr {
246    type Target = Cow<'static, str>;
247    #[inline]
248    fn deref(&self) -> &Cow<'static, str> {
249        &self.0
250    }
251}
252
253impl Borrow<Cow<'static, str>> for StorableStr {
254    #[inline]
255    fn borrow(&self) -> &Cow<'static, str> {
256        &self.0
257    }
258}
259
260//---------------------------------------------------------------------------------------------------- StorableBytes
261/// A [`Storable`] version of [`Bytes`].
262///
263/// ```rust
264/// # use cuprate_database::*;
265/// # use bytes::Bytes;
266/// let bytes: StorableBytes = StorableBytes(Bytes::from_static(&[0,1]));
267///
268/// // Into bytes.
269/// let into = Storable::as_bytes(&bytes);
270/// assert_eq!(into, &[0,1]);
271///
272/// // From bytes.
273/// let from: StorableBytes = Storable::from_bytes(&into);
274/// assert_eq!(from, bytes);
275/// ```
276#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
277#[repr(transparent)]
278pub struct StorableBytes(pub Bytes);
279
280impl Storable for StorableBytes {
281    const BYTE_LENGTH: Option<usize> = None;
282
283    #[inline]
284    fn as_bytes(&self) -> &[u8] {
285        &self.0
286    }
287
288    /// This always allocates a new `Bytes`.
289    #[inline]
290    fn from_bytes(bytes: &[u8]) -> Self {
291        Self(Bytes::copy_from_slice(bytes))
292    }
293}
294
295impl std::ops::Deref for StorableBytes {
296    type Target = [u8];
297    #[inline]
298    fn deref(&self) -> &[u8] {
299        &self.0
300    }
301}
302
303impl Borrow<[u8]> for StorableBytes {
304    #[inline]
305    fn borrow(&self) -> &[u8] {
306        &self.0
307    }
308}
309
310//---------------------------------------------------------------------------------------------------- Tests
311#[cfg(test)]
312mod test {
313    use super::*;
314
315    /// Serialize, deserialize, and compare that
316    /// the intermediate/end results are correct.
317    fn test_storable<const LEN: usize, T>(
318        // The primitive number function that
319        // converts the number into little endian bytes,
320        // e.g `u8::to_le_bytes`.
321        to_le_bytes: fn(T) -> [u8; LEN],
322        // A `Vec` of the numbers to test.
323        t: Vec<T>,
324    ) where
325        T: Storable + Debug + Copy + PartialEq,
326    {
327        for t in t {
328            let expected_bytes = to_le_bytes(t);
329
330            println!("testing: {t:?}, expected_bytes: {expected_bytes:?}");
331
332            // (De)serialize.
333            let se: &[u8] = Storable::as_bytes(&t);
334            let de = <T as Storable>::from_bytes(se);
335
336            println!("serialized: {se:?}, deserialized: {de:?}\n");
337
338            // Assert we wrote correct amount of bytes.
339            if T::BYTE_LENGTH.is_some() {
340                assert_eq!(se.len(), expected_bytes.len());
341            }
342            // Assert the data is the same.
343            assert_eq!(de, t);
344        }
345    }
346
347    /// Create all the float tests.
348    macro_rules! test_float {
349        ($(
350            $float:ident // The float type.
351        ),* $(,)?) => {
352            $(
353                #[test]
354                fn $float() {
355                    test_storable(
356                        $float::to_le_bytes,
357                        vec![
358                            -1.0,
359                            0.0,
360                            1.0,
361                            $float::MIN,
362                            $float::MAX,
363                            $float::INFINITY,
364                            $float::NEG_INFINITY,
365                        ],
366                    );
367                }
368            )*
369        };
370    }
371
372    test_float! {
373        f32,
374        f64,
375    }
376
377    /// Create all the (un)signed number tests.
378    /// u8 -> u128, i8 -> i128.
379    macro_rules! test_unsigned {
380        ($(
381            $number:ident // The integer type.
382        ),* $(,)?) => {
383            $(
384                #[test]
385                fn $number() {
386                    test_storable($number::to_le_bytes, vec![$number::MIN, 0, 1, $number::MAX]);
387                }
388            )*
389        };
390    }
391
392    test_unsigned! {
393        u8,
394        u16,
395        u32,
396        u64,
397        u128,
398        usize,
399        i8,
400        i16,
401        i32,
402        i64,
403        i128,
404        isize,
405    }
406}