tree_buf/internal/types/
tuple.rs

1#![allow(non_snake_case)]
2
3use crate::prelude::*;
4
5// https://www.reddit.com/r/rust/comments/339yj3/tuple_indexing_in_a_macro/
6macro_rules! expr {
7    ($x:expr) => {
8        $x
9    };
10} // HACK
11macro_rules! tuple_index {
12    ($tuple:expr, $idx:tt) => {
13        expr!($tuple.$idx)
14    };
15}
16
17macro_rules! parallel_new_rhs {
18    ($opts:ident, ) => {
19      ()
20    };
21    ($opts:ident, $ts:ident) => {
22        $ts::new($ts, $opts)
23    };
24    ($opts:ident, $ts:ident, $($remainder:ident),+) => {
25        parallel(move || $ts::new($ts, $opts), move || parallel_new_rhs!($opts, $($remainder),*), $opts)
26    }
27}
28
29macro_rules! parallel_decode_rhs {
30    ($opts: ident) => {
31      ()
32    };
33    ($opts: ident, $ts:ident) => {
34        $ts::decode($ts, $opts)
35    };
36    ($opts: ident, $ts:ident, $($remainder:ident),+) => {
37        parallel(move || $ts::decode($ts, $opts), move || parallel_decode_rhs!($opts, $($remainder),*), $opts)
38    }
39}
40
41macro_rules! parallel_lhs {
42    () => {
43      ()
44    };
45    ($ts:ident) => {
46        $ts
47    };
48    ($ts:ident, $($remainder:ident),+) => {
49        ($ts, parallel_lhs!($($remainder),*))
50    }
51}
52
53macro_rules! parallel_new {
54    ($opts:ident, $($ts:ident),*) => {
55        let parallel_lhs!($($ts),*) = parallel_new_rhs!($opts, $($ts),*);
56    };
57}
58
59macro_rules! parallel_decode {
60    ($opts:ident, $($ts:ident),*) => {
61        let parallel_lhs!($($ts),*) = parallel_decode_rhs!($opts, $($ts),*);
62    };
63}
64
65macro_rules! impl_tuple {
66    ($count:expr, $trid:expr, $taid:expr, $($ts:ident, $ti:tt,)+) => {
67        #[cfg(feature = "encode")]
68        impl <$($ts: Encodable),+> Encodable for ($($ts),+) {
69            type EncoderArray=($($ts::EncoderArray),+);
70            fn encode_root<O: EncodeOptions>(&self, stream: &mut EncoderStream<'_, O>) -> RootTypeId {
71                profile_method!(encode_root);
72                $(
73                    stream.encode_with_id(|stream| tuple_index!(self, $ti).encode_root(stream));
74                )+
75                $trid
76            }
77        }
78
79        #[cfg(feature = "encode")]
80        impl<$($ts: Encodable),+> EncoderArray<($($ts),+)> for ($($ts::EncoderArray),+) {
81            fn buffer_one<'a, 'b: 'a>(&'a mut self, value: &'b ($($ts),+)) {
82                $(
83                    tuple_index!(self, $ti).buffer_one(&tuple_index!(value, $ti));
84                )+
85            }
86            fn flush<O: EncodeOptions>(self, stream: &mut EncoderStream<'_, O>) -> ArrayTypeId {
87                profile_method!(flush);
88                let ($($ts,)+) = self;
89                $(
90                    stream.encode_with_id(|stream|
91                        $ts.flush(stream)
92                    );
93                )+
94                $taid
95            }
96        }
97
98        #[cfg(feature = "decode")]
99        impl <$($ts: Decodable + Send),+> Decodable for ($($ts),+)
100        // Overly verbose because of `?` requiring `From` See also ec4fa3ba-def5-44eb-9065-e80b59530af6
101        where $(DecodeError : From<<$ts::DecoderArray as DecoderArray>::Error>),+ {
102            type DecoderArray=($($ts::DecoderArray),+);
103            fn decode(sticks: DynRootBranch<'_>, options: &impl DecodeOptions) -> DecodeResult<Self> {
104                profile_method!(decode);
105                match sticks {
106                    DynRootBranch::Tuple { mut fields } => {
107                        // See also abb368f2-6c99-4c44-8f9f-4b00868adaaf
108                        if fields.len() != $count {
109                            return Err(DecodeError::SchemaMismatch)
110                        }
111                        let mut fields = fields.drain(..);
112
113                        // Move the fields out of the vec
114                        $(
115                            // This unwrap is ok because we verified the len already. See also abb368f2-6c99-4c44-8f9f-4b00868adaaf
116                            let $ts = fields.next().unwrap();
117                        )+
118
119                        parallel_decode!(options, $($ts),*);
120
121                        Ok(($($ts?),*))
122                    },
123                    _ => Err(DecodeError::SchemaMismatch),
124                }
125            }
126        }
127
128        #[cfg(feature = "decode")]
129        impl <$($ts: DecoderArray),+> DecoderArray for ($($ts),+)
130        // Overly verbose because of `?` requiring `From` See also ec4fa3ba-def5-44eb-9065-e80b59530af6
131        where $(DecodeError : From<$ts::Error>),+ {
132            type Decode=($($ts::Decode),+);
133            // TODO: It would be nice to know somehow whether or not
134            // all the fields are infallible types. Perhaps specialization
135            // can achieve this.
136            type Error=DecodeError;
137            fn new(sticks: DynArrayBranch<'_>, options: &impl DecodeOptions) -> DecodeResult<Self> {
138                profile_method!(new);
139
140                match sticks {
141                    DynArrayBranch::Tuple { mut fields } => {
142                        // See also abb368f2-6c99-4c44-8f9f-4b00868adaaf
143                        if fields.len() != $count {
144                            return Err(DecodeError::SchemaMismatch)
145                        }
146                        let mut fields = fields.drain(..);
147
148                        // Move the fields out of the vec
149                        $(
150                            // This unwrap is ok because we verified the len already. See also abb368f2-6c99-4c44-8f9f-4b00868adaaf
151                            let $ts = fields.next().unwrap();
152                        )+
153
154                        parallel_new!(options, $($ts),*);
155
156                        Ok(($($ts?),*))
157                    },
158                    _ => Err(DecodeError::SchemaMismatch)
159                }
160            }
161            fn decode_next(&mut self) -> Result<Self::Decode, Self::Error> {
162                Ok(($(
163                    tuple_index!(self, $ti).decode_next()?,
164                )+))
165            }
166        }
167
168        impl<T, $($ts: Compressor<T>,)+> CompressorSet<T> for ($($ts,)+) {
169            fn len(&self) -> usize {
170                $count
171            }
172            fn fast_size_for<O: EncodeOptions>(&self, compressor: usize, data: &[T], options: &O) -> Result<usize, ()> {
173                match compressor {
174                    $($ti => tuple_index!(self, $ti).fast_size_for(data, options),)+
175                    _ => unreachable!("No compressor at that index"),
176                }
177            }
178            fn compress<O: EncodeOptions>(&self, compressor: usize, data: &[T], stream: &mut EncoderStream<'_, O>) -> Result<ArrayTypeId, ()> {
179                match compressor {
180                    $($ti => tuple_index!(self, $ti).compress(data, stream),)+
181                    _ => unreachable!("No compressor at that index"),
182                }
183            }
184        }
185    };
186}
187
188impl<T, T0: Compressor<T>> CompressorSet<T> for (T0,) {
189    fn len(&self) -> usize {
190        1
191    }
192    fn fast_size_for<O: EncodeOptions>(&self, compressor: usize, data: &[T], options: &O) -> Result<usize, ()> {
193        match compressor {
194            0 => self.0.fast_size_for(data, options),
195            _ => unreachable!("No compressor at that index"),
196        }
197    }
198    fn compress<O: EncodeOptions>(&self, compressor: usize, data: &[T], stream: &mut EncoderStream<'_, O>) -> Result<ArrayTypeId, ()> {
199        match compressor {
200            0 => self.0.compress(data, stream),
201            _ => unreachable!("No compressor at that index"),
202        }
203    }
204}
205
206// TODO: Consider 0 and 1 sized tuples.
207// These should probably be no serialization at all,
208// and pass-through serialization respectively and just
209// not use the tuple construct. The tuple construct isn't invalid
210// though, which opens considerations for matching either for a schema
211// which may not be trivial - like a recursive descent parser.
212impl_tuple!(2, RootTypeId::Tuple2, ArrayTypeId::Tuple2, T0, 0, T1, 1,);
213impl_tuple!(3, RootTypeId::Tuple3, ArrayTypeId::Tuple3, T0, 0, T1, 1, T2, 2,);
214impl_tuple!(4, RootTypeId::Tuple4, ArrayTypeId::Tuple4, T0, 0, T1, 1, T2, 2, T3, 3,);
215impl_tuple!(5, RootTypeId::Tuple5, ArrayTypeId::Tuple5, T0, 0, T1, 1, T2, 2, T3, 3, T4, 4,);
216impl_tuple!(6, RootTypeId::Tuple6, ArrayTypeId::Tuple6, T0, 0, T1, 1, T2, 2, T3, 3, T4, 4, T5, 5,);
217
218// TODO: Support tuple structs in the macro