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)]
8pub 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}