redb_32bit/
types.rs

1use std::cmp::Ordering;
2use std::convert::TryInto;
3use std::fmt::Debug;
4
5#[derive(Eq, PartialEq, Clone, Debug)]
6enum TypeClassification {
7    Internal,
8    UserDefined,
9}
10
11impl TypeClassification {
12    fn to_byte(&self) -> u8 {
13        match self {
14            TypeClassification::Internal => 1,
15            TypeClassification::UserDefined => 2,
16        }
17    }
18
19    fn from_byte(value: u8) -> Self {
20        match value {
21            1 => TypeClassification::Internal,
22            2 => TypeClassification::UserDefined,
23            _ => unreachable!(),
24        }
25    }
26}
27
28#[derive(Eq, PartialEq, Debug, Clone)]
29pub struct TypeName {
30    classification: TypeClassification,
31    name: String,
32}
33
34impl TypeName {
35    /// It is recommended that `name` be prefixed with the crate name to minimize the chance of
36    /// it coliding with another user defined type
37    pub fn new(name: &str) -> Self {
38        Self {
39            classification: TypeClassification::UserDefined,
40            name: name.to_string(),
41        }
42    }
43
44    pub(crate) fn internal(name: &str) -> Self {
45        Self {
46            classification: TypeClassification::Internal,
47            name: name.to_string(),
48        }
49    }
50
51    pub(crate) fn to_bytes(&self) -> Vec<u8> {
52        let mut result = Vec::with_capacity(self.name.as_bytes().len() + 1);
53        result.push(self.classification.to_byte());
54        result.extend_from_slice(self.name.as_bytes());
55        result
56    }
57
58    pub(crate) fn from_bytes(bytes: &[u8]) -> Self {
59        let classification = TypeClassification::from_byte(bytes[0]);
60        let name = std::str::from_utf8(&bytes[1..]).unwrap().to_string();
61
62        Self {
63            classification,
64            name,
65        }
66    }
67
68    pub(crate) fn name(&self) -> &str {
69        &self.name
70    }
71}
72
73pub trait RedbValue: Debug {
74    /// SelfType<'a> must be the same type as Self with all lifetimes replaced with 'a
75    type SelfType<'a>: Debug + 'a
76    where
77        Self: 'a;
78
79    type AsBytes<'a>: AsRef<[u8]> + 'a
80    where
81        Self: 'a;
82
83    /// Width of a fixed type, or None for variable width
84    fn fixed_width() -> Option<usize>;
85
86    /// Deserializes data
87    /// Implementations may return a view over data, or an owned type
88    fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
89    where
90        Self: 'a;
91
92    /// Serialize the value to a slice
93    fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
94    where
95        Self: 'a,
96        Self: 'b;
97
98    /// Globally unique identifier for this type
99    fn type_name() -> TypeName;
100}
101
102/// Implementing this trait indicates that the type can be mutated in-place as a &mut [u8].
103/// This enables the .insert_reserve() method on Table
104pub trait MutInPlaceValue: RedbValue {
105    /// The base type such that &mut [u8] can be safely transmuted to &mut BaseRefType
106    type BaseRefType: Debug + ?Sized;
107
108    // Initialize `data` to a valid value. This method will be called (at some point, not necessarily immediately)
109    // before from_bytes_mut() is called on a slice.
110    fn initialize(data: &mut [u8]);
111
112    fn from_bytes_mut(data: &mut [u8]) -> &mut Self::BaseRefType;
113}
114
115impl MutInPlaceValue for &[u8] {
116    type BaseRefType = [u8];
117
118    fn initialize(_data: &mut [u8]) {
119        // no-op. All values are valid.
120    }
121
122    fn from_bytes_mut(data: &mut [u8]) -> &mut Self::BaseRefType {
123        data
124    }
125}
126
127pub trait RedbKey: RedbValue {
128    /// Compare data1 with data2
129    fn compare(data1: &[u8], data2: &[u8]) -> Ordering;
130}
131
132impl RedbValue for () {
133    type SelfType<'a> = ()
134    where
135        Self: 'a;
136    type AsBytes<'a> = &'a [u8]
137    where
138        Self: 'a;
139
140    fn fixed_width() -> Option<usize> {
141        Some(0)
142    }
143
144    #[allow(clippy::unused_unit)]
145    fn from_bytes<'a>(_data: &'a [u8]) -> ()
146    where
147        Self: 'a,
148    {
149        ()
150    }
151
152    fn as_bytes<'a, 'b: 'a>(_: &'a Self::SelfType<'b>) -> &'a [u8]
153    where
154        Self: 'a,
155        Self: 'b,
156    {
157        &[]
158    }
159
160    fn type_name() -> TypeName {
161        TypeName::internal("()")
162    }
163}
164
165impl RedbKey for () {
166    fn compare(_data1: &[u8], _data2: &[u8]) -> Ordering {
167        Ordering::Equal
168    }
169}
170
171impl RedbValue for bool {
172    type SelfType<'a> = bool
173        where
174            Self: 'a;
175    type AsBytes<'a> = &'a [u8]
176        where
177            Self: 'a;
178
179    fn fixed_width() -> Option<usize> {
180        Some(1)
181    }
182
183    fn from_bytes<'a>(data: &'a [u8]) -> bool
184    where
185        Self: 'a,
186    {
187        match data[0] {
188            0 => false,
189            1 => true,
190            _ => unreachable!(),
191        }
192    }
193
194    fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> &'a [u8]
195    where
196        Self: 'a,
197        Self: 'b,
198    {
199        match value {
200            true => &[1],
201            false => &[0],
202        }
203    }
204
205    fn type_name() -> TypeName {
206        TypeName::internal("bool")
207    }
208}
209
210impl RedbKey for bool {
211    fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
212        let value1 = Self::from_bytes(data1);
213        let value2 = Self::from_bytes(data2);
214        value1.cmp(&value2)
215    }
216}
217
218impl<T: RedbValue> RedbValue for Option<T> {
219    type SelfType<'a> = Option<T::SelfType<'a>>
220    where
221        Self: 'a;
222    type AsBytes<'a> = Vec<u8>
223    where
224        Self: 'a;
225
226    fn fixed_width() -> Option<usize> {
227        T::fixed_width().map(|x| x + 1)
228    }
229
230    fn from_bytes<'a>(data: &'a [u8]) -> Option<T::SelfType<'a>>
231    where
232        Self: 'a,
233    {
234        match data[0] {
235            0 => None,
236            1 => Some(T::from_bytes(&data[1..])),
237            _ => unreachable!(),
238        }
239    }
240
241    fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Vec<u8>
242    where
243        Self: 'a,
244        Self: 'b,
245    {
246        let mut result = vec![0];
247        if let Some(x) = value {
248            result[0] = 1;
249            result.extend_from_slice(T::as_bytes(x).as_ref());
250        } else if let Some(fixed_width) = T::fixed_width() {
251            result.extend_from_slice(&vec![0; fixed_width]);
252        }
253        result
254    }
255
256    fn type_name() -> TypeName {
257        TypeName::internal(&format!("Option<{}>", T::type_name().name()))
258    }
259}
260
261impl<T: RedbKey> RedbKey for Option<T> {
262    #[allow(clippy::collapsible_else_if)]
263    fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
264        if data1[0] == 0 {
265            if data2[0] == 0 {
266                Ordering::Equal
267            } else {
268                Ordering::Less
269            }
270        } else {
271            if data2[0] == 0 {
272                Ordering::Greater
273            } else {
274                T::compare(&data1[1..], &data2[1..])
275            }
276        }
277    }
278}
279
280impl RedbValue for &[u8] {
281    type SelfType<'a> = &'a [u8]
282    where
283        Self: 'a;
284    type AsBytes<'a> = &'a [u8]
285    where
286        Self: 'a;
287
288    fn fixed_width() -> Option<usize> {
289        None
290    }
291
292    fn from_bytes<'a>(data: &'a [u8]) -> &'a [u8]
293    where
294        Self: 'a,
295    {
296        data
297    }
298
299    fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> &'a [u8]
300    where
301        Self: 'a,
302        Self: 'b,
303    {
304        value
305    }
306
307    fn type_name() -> TypeName {
308        TypeName::internal("&[u8]")
309    }
310}
311
312impl RedbKey for &[u8] {
313    fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
314        data1.cmp(data2)
315    }
316}
317
318impl<const N: usize> RedbValue for &[u8; N] {
319    type SelfType<'a> = &'a [u8; N]
320    where
321        Self: 'a;
322    type AsBytes<'a> = &'a [u8; N]
323    where
324        Self: 'a;
325
326    fn fixed_width() -> Option<usize> {
327        Some(N)
328    }
329
330    fn from_bytes<'a>(data: &'a [u8]) -> &'a [u8; N]
331    where
332        Self: 'a,
333    {
334        data.try_into().unwrap()
335    }
336
337    fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> &'a [u8; N]
338    where
339        Self: 'a,
340        Self: 'b,
341    {
342        value
343    }
344
345    fn type_name() -> TypeName {
346        TypeName::internal(&format!("[u8;{N}]"))
347    }
348}
349
350impl<const N: usize> RedbKey for &[u8; N] {
351    fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
352        data1.cmp(data2)
353    }
354}
355
356impl RedbValue for &str {
357    type SelfType<'a> = &'a str
358    where
359        Self: 'a;
360    type AsBytes<'a> = &'a str
361    where
362        Self: 'a;
363
364    fn fixed_width() -> Option<usize> {
365        None
366    }
367
368    fn from_bytes<'a>(data: &'a [u8]) -> &'a str
369    where
370        Self: 'a,
371    {
372        std::str::from_utf8(data).unwrap()
373    }
374
375    fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> &'a str
376    where
377        Self: 'a,
378        Self: 'b,
379    {
380        value
381    }
382
383    fn type_name() -> TypeName {
384        TypeName::internal("&str")
385    }
386}
387
388impl RedbKey for &str {
389    fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
390        let str1 = Self::from_bytes(data1);
391        let str2 = Self::from_bytes(data2);
392        str1.cmp(str2)
393    }
394}
395
396impl RedbValue for char {
397    type SelfType<'a> = char;
398    type AsBytes<'a> = [u8; 3] where Self: 'a;
399
400    fn fixed_width() -> Option<usize> {
401        Some(3)
402    }
403
404    fn from_bytes<'a>(data: &'a [u8]) -> char
405    where
406        Self: 'a,
407    {
408        char::from_u32(u32::from_le_bytes([data[0], data[1], data[2], 0])).unwrap()
409    }
410
411    fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> [u8; 3]
412    where
413        Self: 'a,
414        Self: 'b,
415    {
416        let bytes = u32::from(*value).to_le_bytes();
417        [bytes[0], bytes[1], bytes[2]]
418    }
419
420    fn type_name() -> TypeName {
421        TypeName::internal(stringify!(char))
422    }
423}
424
425impl RedbKey for char {
426    fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
427        Self::from_bytes(data1).cmp(&Self::from_bytes(data2))
428    }
429}
430
431macro_rules! le_value {
432    ($t:ty) => {
433        impl RedbValue for $t {
434            type SelfType<'a> = $t;
435            type AsBytes<'a> = [u8; std::mem::size_of::<$t>()] where Self: 'a;
436
437            fn fixed_width() -> Option<usize> {
438                Some(std::mem::size_of::<$t>())
439            }
440
441            fn from_bytes<'a>(data: &'a [u8]) -> $t
442            where
443                Self: 'a,
444            {
445                <$t>::from_le_bytes(data.try_into().unwrap())
446            }
447
448            fn as_bytes<'a, 'b: 'a>(
449                value: &'a Self::SelfType<'b>,
450            ) -> [u8; std::mem::size_of::<$t>()]
451            where
452                Self: 'a,
453                Self: 'b,
454            {
455                value.to_le_bytes()
456            }
457
458            fn type_name() -> TypeName {
459                TypeName::internal(stringify!($t))
460            }
461        }
462    };
463}
464
465macro_rules! le_impl {
466    ($t:ty) => {
467        le_value!($t);
468
469        impl RedbKey for $t {
470            fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
471                Self::from_bytes(data1).cmp(&Self::from_bytes(data2))
472            }
473        }
474    };
475}
476
477le_impl!(u8);
478le_impl!(u16);
479le_impl!(u32);
480le_impl!(u64);
481le_impl!(u128);
482le_impl!(i8);
483le_impl!(i16);
484le_impl!(i32);
485le_impl!(i64);
486le_impl!(i128);
487le_value!(f32);
488le_value!(f64);