redb/
legacy_tuple_types.rs

1use crate::types::{Key, TypeName, Value};
2use std::borrow::Borrow;
3use std::cmp::Ordering;
4use std::mem::size_of;
5
6#[repr(transparent)]
7#[derive(Debug)]
8/// Legacy wrapper for tuple types created with redb version 2.x
9///
10/// See the CHANGELOG.md file for more details
11pub struct Legacy<T>(T);
12
13fn serialize_tuple_elements_variable(slices: &[&[u8]]) -> Vec<u8> {
14    let total_len: usize = slices.iter().map(|x| x.len()).sum();
15    let mut output = Vec::with_capacity((slices.len() - 1) * size_of::<u32>() + total_len);
16    for len in slices.iter().map(|x| x.len()).take(slices.len() - 1) {
17        output.extend_from_slice(&(u32::try_from(len).unwrap()).to_le_bytes());
18    }
19
20    for slice in slices {
21        output.extend_from_slice(slice);
22    }
23
24    output
25}
26
27fn serialize_tuple_elements_fixed(slices: &[&[u8]]) -> Vec<u8> {
28    let total_len: usize = slices.iter().map(|x| x.len()).sum();
29    let mut output = Vec::with_capacity(total_len);
30    for slice in slices {
31        output.extend_from_slice(slice);
32    }
33    output
34}
35
36fn parse_lens<const N: usize>(data: &[u8]) -> [usize; N] {
37    let mut result = [0; N];
38    for i in 0..N {
39        result[i] = u32::from_le_bytes(data[4 * i..4 * (i + 1)].try_into().unwrap()) as usize;
40    }
41    result
42}
43
44fn not_equal<T: Key>(data1: &[u8], data2: &[u8]) -> Option<Ordering> {
45    match T::compare(data1, data2) {
46        Ordering::Less => Some(Ordering::Less),
47        Ordering::Equal => None,
48        Ordering::Greater => Some(Ordering::Greater),
49    }
50}
51
52macro_rules! fixed_width_impl {
53    ( $( $t:ty ),+ ) => {
54        {
55            let mut sum = 0;
56            $(
57                sum += <$t>::fixed_width()?;
58            )+
59            Some(sum)
60        }
61    };
62}
63
64macro_rules! as_bytes_impl {
65    ( $value:expr, $( $t:ty, $i:tt ),+ ) => {{
66        if Self::fixed_width().is_some() {
67            serialize_tuple_elements_fixed(&[
68                $(
69                    <$t>::as_bytes($value.$i.borrow()).as_ref(),
70                )+
71            ])
72        } else {
73            serialize_tuple_elements_variable(&[
74                $(
75                    <$t>::as_bytes($value.$i.borrow()).as_ref(),
76                )+
77            ])
78        }
79    }};
80}
81
82macro_rules! type_name_impl {
83    ( $head:ty $(,$tail:ty)+ ) => {
84        {
85            let mut result = String::new();
86            result.push('(');
87            result.push_str(&<$head>::type_name().name());
88            $(
89                result.push(',');
90                result.push_str(&<$tail>::type_name().name());
91            )+
92            result.push(')');
93
94            TypeName::internal(&result)
95        }
96    };
97}
98
99macro_rules! from_bytes_variable_impl {
100    ( $data:expr $(,$t:ty, $v:ident, $i:literal )+ | $t_last:ty, $v_last:ident, $i_last:literal ) => {
101        #[allow(clippy::manual_bits)]
102        {
103            let lens: [usize; $i_last] = parse_lens($data);
104            let mut offset = $i_last * size_of::<u32>();
105            $(
106                let len = lens[$i];
107                let $v = <$t>::from_bytes(&$data[offset..(offset + len)]);
108                offset += len;
109            )+
110            let $v_last = <$t_last>::from_bytes(&$data[offset..]);
111            ($(
112                $v,
113            )+
114                $v_last
115            )
116        }
117    };
118}
119
120macro_rules! from_bytes_fixed_impl {
121    ( $data:expr $(,$t:ty, $v:ident )+ ) => {
122        {
123            let mut offset = 0;
124            $(
125                let len = <$t>::fixed_width().unwrap();
126                let $v = <$t>::from_bytes(&$data[offset..(offset + len)]);
127                #[allow(unused_assignments)]
128                {
129                    offset += len;
130                }
131            )+
132
133            ($(
134                $v,
135            )+)
136        }
137    };
138}
139
140macro_rules! compare_variable_impl {
141    ( $data0:expr, $data1:expr $(,$t:ty, $i:literal )+ | $t_last:ty, $i_last:literal ) => {
142        #[allow(clippy::manual_bits)]
143        {
144            let lens0: [usize; $i_last] = parse_lens($data0);
145            let lens1: [usize; $i_last] = parse_lens($data1);
146            let mut offset0 = $i_last * size_of::<u32>();
147            let mut offset1 = $i_last * size_of::<u32>();
148            $(
149                let index = $i;
150                let len0 = lens0[index];
151                let len1 = lens1[index];
152                if let Some(order) = not_equal::<$t>(
153                    &$data0[offset0..(offset0 + len0)],
154                    &$data1[offset1..(offset1 + len1)],
155                ) {
156                    return order;
157                }
158                offset0 += len0;
159                offset1 += len1;
160            )+
161
162            <$t_last>::compare(&$data0[offset0..], &$data1[offset1..])
163        }
164    };
165}
166
167macro_rules! compare_fixed_impl {
168    ( $data0:expr, $data1:expr, $($t:ty),+ ) => {
169        {
170            let mut offset0 = 0;
171            let mut offset1 = 0;
172            $(
173                let len = <$t>::fixed_width().unwrap();
174                if let Some(order) = not_equal::<$t>(
175                    &$data0[offset0..(offset0 + len)],
176                    &$data1[offset1..(offset1 + len)],
177                ) {
178                    return order;
179                }
180                #[allow(unused_assignments)]
181                {
182                    offset0 += len;
183                    offset1 += len;
184                }
185            )+
186
187            Ordering::Equal
188        }
189    };
190}
191
192macro_rules! tuple_impl {
193    ( $($t:ident, $v:ident, $i:tt ),+ | $t_last:ident, $v_last:ident, $i_last:tt ) => {
194        impl<$($t: Value,)+ $t_last: Value> Value for Legacy<($($t,)+ $t_last)> {
195            type SelfType<'a> = (
196                $(<$t>::SelfType<'a>,)+
197                <$t_last>::SelfType<'a>,
198            )
199            where
200                Self: 'a;
201            type AsBytes<'a> = Vec<u8>
202            where
203                Self: 'a;
204
205            fn fixed_width() -> Option<usize> {
206                fixed_width_impl!($($t,)+ $t_last)
207            }
208
209            fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
210            where
211                Self: 'a,
212            {
213                if Self::fixed_width().is_some() {
214                    from_bytes_fixed_impl!(data $(,$t,$v)+, $t_last, $v_last)
215                } else {
216                    from_bytes_variable_impl!(data $(,$t,$v,$i)+ | $t_last, $v_last, $i_last)
217                }
218            }
219
220            fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Vec<u8>
221            where
222                Self: 'a,
223                Self: 'b,
224            {
225                as_bytes_impl!(value, $($t,$i,)+ $t_last, $i_last)
226            }
227
228            fn type_name() -> TypeName {
229                type_name_impl!($($t,)+ $t_last)
230            }
231        }
232
233        impl<$($t: Key,)+ $t_last: Key> Key for Legacy<($($t,)+ $t_last)> {
234            fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
235                if Self::fixed_width().is_some() {
236                    compare_fixed_impl!(data1, data2, $($t,)+ $t_last)
237                } else {
238                    compare_variable_impl!(data1, data2 $(,$t,$i)+ | $t_last, $i_last)
239                }
240            }
241        }
242    };
243}
244
245impl<T: Value> Value for Legacy<(T,)> {
246    type SelfType<'a>
247        = (T::SelfType<'a>,)
248    where
249        Self: 'a;
250    type AsBytes<'a>
251        = T::AsBytes<'a>
252    where
253        Self: 'a;
254
255    fn fixed_width() -> Option<usize> {
256        T::fixed_width()
257    }
258
259    fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
260    where
261        Self: 'a,
262    {
263        (T::from_bytes(data),)
264    }
265
266    fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
267    where
268        Self: 'a,
269        Self: 'b,
270    {
271        T::as_bytes(&value.0)
272    }
273
274    fn type_name() -> TypeName {
275        TypeName::internal(&format!("({},)", T::type_name().name()))
276    }
277}
278
279impl<T: Key> Key for Legacy<(T,)> {
280    fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
281        T::compare(data1, data2)
282    }
283}
284
285tuple_impl! {
286    T0, t0, 0
287    | T1, t1, 1
288}
289
290tuple_impl! {
291    T0, t0, 0,
292    T1, t1, 1
293    | T2, t2, 2
294}
295
296tuple_impl! {
297    T0, t0, 0,
298    T1, t1, 1,
299    T2, t2, 2
300    | T3, t3, 3
301}
302
303tuple_impl! {
304    T0, t0, 0,
305    T1, t1, 1,
306    T2, t2, 2,
307    T3, t3, 3
308    | T4, t4, 4
309}
310
311tuple_impl! {
312    T0, t0, 0,
313    T1, t1, 1,
314    T2, t2, 2,
315    T3, t3, 3,
316    T4, t4, 4
317    | T5, t5, 5
318}
319
320tuple_impl! {
321    T0, t0, 0,
322    T1, t1, 1,
323    T2, t2, 2,
324    T3, t3, 3,
325    T4, t4, 4,
326    T5, t5, 5
327    | T6, t6, 6
328}
329
330tuple_impl! {
331    T0, t0, 0,
332    T1, t1, 1,
333    T2, t2, 2,
334    T3, t3, 3,
335    T4, t4, 4,
336    T5, t5, 5,
337    T6, t6, 6
338    | T7, t7, 7
339}
340
341tuple_impl! {
342    T0, t0, 0,
343    T1, t1, 1,
344    T2, t2, 2,
345    T3, t3, 3,
346    T4, t4, 4,
347    T5, t5, 5,
348    T6, t6, 6,
349    T7, t7, 7
350    | T8, t8, 8
351}
352
353tuple_impl! {
354    T0, t0, 0,
355    T1, t1, 1,
356    T2, t2, 2,
357    T3, t3, 3,
358    T4, t4, 4,
359    T5, t5, 5,
360    T6, t6, 6,
361    T7, t7, 7,
362    T8, t8, 8
363    | T9, t9, 9
364}
365
366tuple_impl! {
367    T0, t0, 0,
368    T1, t1, 1,
369    T2, t2, 2,
370    T3, t3, 3,
371    T4, t4, 4,
372    T5, t5, 5,
373    T6, t6, 6,
374    T7, t7, 7,
375    T8, t8, 8,
376    T9, t9, 9
377    | T10, t10, 10
378}
379
380tuple_impl! {
381    T0, t0, 0,
382    T1, t1, 1,
383    T2, t2, 2,
384    T3, t3, 3,
385    T4, t4, 4,
386    T5, t5, 5,
387    T6, t6, 6,
388    T7, t7, 7,
389    T8, t8, 8,
390    T9, t9, 9,
391    T10, t10, 10
392    | T11, t11, 11
393}
394
395#[cfg(test)]
396mod test {
397    use crate::legacy_tuple_types::Legacy;
398    use crate::types::Value;
399
400    #[test]
401    fn width() {
402        assert!(<Legacy<(&str, u8)>>::fixed_width().is_none());
403        assert!(<Legacy<(u16, u8, &str, u128)>>::fixed_width().is_none());
404        assert_eq!(<Legacy<(u16,)>>::fixed_width().unwrap(), 2);
405        assert_eq!(<Legacy<(u16, u8)>>::fixed_width().unwrap(), 3);
406        assert_eq!(<Legacy<(u16, u8, u128)>>::fixed_width().unwrap(), 19);
407        assert_eq!(<Legacy<(u16, u8, i8, u128)>>::fixed_width().unwrap(), 20);
408    }
409}