1#![allow(clippy::single_match, clippy::block_in_if_condition_stmt)]
2use crate::field::{FieldDecode, FieldEncode, RequiredFieldDecode, RequiredFieldEncode};
3use crate::wire::Tag;
4use bytecodec::{ByteCount, Decode, Encode, Eos, ErrorKind, Result, SizedEncode};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
8#[allow(missing_docs)]
9pub enum Branch2<A, B> {
10 A(A),
11 B(B),
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
16#[allow(missing_docs)]
17pub enum Branch3<A, B, C> {
18 A(A),
19 B(B),
20 C(C),
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
25#[allow(missing_docs)]
26pub enum Branch4<A, B, C, D> {
27 A(A),
28 B(B),
29 C(C),
30 D(D),
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
35#[allow(missing_docs)]
36pub enum Branch5<A, B, C, D, E> {
37 A(A),
38 B(B),
39 C(C),
40 D(D),
41 E(E),
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
46#[allow(missing_docs)]
47pub enum Branch6<A, B, C, D, E, F> {
48 A(A),
49 B(B),
50 C(C),
51 D(D),
52 E(E),
53 F(F),
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
58#[allow(missing_docs)]
59pub enum Branch7<A, B, C, D, E, F, G> {
60 A(A),
61 B(B),
62 C(C),
63 D(D),
64 E(E),
65 F(F),
66 G(G),
67}
68
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
71#[allow(missing_docs)]
72pub enum Branch8<A, B, C, D, E, F, G, H> {
73 A(A),
74 B(B),
75 C(C),
76 D(D),
77 E(E),
78 F(F),
79 G(G),
80 H(H),
81}
82
83#[derive(Debug, Default)]
85pub struct Oneof<F> {
86 fields: F,
87 index: usize,
88}
89impl<F> Oneof<F> {
90 pub fn new(fields: F) -> Self {
92 Oneof { fields, index: 0 }
93 }
94}
95
96macro_rules! impl_field_decode {
97 ($oneof:ident, [$($f:ident),*], [$($i:tt),*]) => {
98 impl<$($f),*> Decode for Oneof<($($f),*,)>
99 where
100 $($f: RequiredFieldDecode),*
101 {
102 type Item = $oneof<$($f::Item),*>;
103
104 fn decode(&mut self, buf: &[u8], eos: Eos) -> Result<usize> {
105 if self.index == 0 {
106 return Ok(0)
107 }
108 match self.index - 1 {
109 $($i => track!(self.fields.$i.decode(buf, eos))),*,
110 _ => unreachable!()
111 }
112 }
113
114 fn finish_decoding(&mut self) -> Result<Self::Item> {
115 let i = self.index;
116 self.index = 0;
117 track_assert_ne!(i, 0, ErrorKind::InvalidInput, "No `Oneof` field");
118 match i - 1 {
119 $($i => track!(self.fields.$i.finish_decoding()).map($oneof::$f)),*,
120 _ => unreachable!()
121 }
122 }
123
124 fn is_idle(&self) -> bool {
125 if self.index == 0 {
126 return false;
127 }
128 match self.index - 1 {
129 $($i => self.fields.$i.is_idle()),*,
130 _ => unreachable!(),
131 }
132 }
133
134 fn requiring_bytes(&self) -> ByteCount {
135 if self.index == 0 {
136 return ByteCount::Unknown;
137 }
138 match self.index - 1 {
139 $($i => self.fields.$i.requiring_bytes()),*,
140 _ => unreachable!()
141 }
142 }
143 }
144 impl<$($f),*> FieldDecode for Oneof<($($f),*,)>
145 where
146 $($f: RequiredFieldDecode),*
147 {
148 fn start_decoding(&mut self, tag: Tag) -> Result<bool> {
149 if self.index != 0 {
150 match self.index - 1 {
151 $($i => track!(self.fields.$i.finish_decoding()).map(|_| ())?),*,
152 _ => {},
153 }
154 self.index = 0;
155 }
156
157 $(if track!(self.fields.$i.start_decoding(tag); tag)? {
158 self.index = $i + 1;
159 return Ok(true);
160 })*
161 Ok(false)
162 }
163 }
164 impl<$($f),*> RequiredFieldDecode for Oneof<($($f),*,)>
165 where
166 $($f: RequiredFieldDecode),*
167 {
168 fn is_present(&self) -> bool {
169 self.index != 0
170 }
171 }
172 }
173}
174
175macro_rules! impl_field_encode {
176 ($oneof:ident,[$($f:ident),*],[$($i:tt),*]) => {
177 impl<$($f),*> Encode for Oneof<($($f),*,)>
178 where
179 $($f: RequiredFieldEncode),*
180 {
181 type Item = $oneof<$($f::Item),*>;
182
183 fn encode(&mut self, buf: &mut [u8], eos: Eos) -> Result<usize> {
184 if self.index == 0 {
185 return Ok(0);
186 }
187 match self.index - 1 {
188 $($i => track!(self.fields.$i.encode(buf, eos))),*,
189 _ => unreachable!()
190 }
191 }
192
193 fn start_encoding(&mut self, item: Self::Item) -> Result<()> {
194 track_assert!(self.is_idle(), ErrorKind::EncoderFull);
195 match item {
196 $($oneof::$f(v) => {
197 self.index = $i + 1;
198 track!(self.fields.$i.start_encoding(v))
199 }),*
200 }
201 }
202
203 fn is_idle(&self) -> bool {
204 if self.index == 0 {
205 return true;
206 }
207 match self.index - 1 {
208 $($i => self.fields.$i.is_idle()),*,
209 _ => unreachable!()
210 }
211 }
212
213 fn requiring_bytes(&self) -> ByteCount {
214 if self.index == 0 {
215 return ByteCount::Finite(0);
216 }
217 match self.index - 1 {
218 $($i => self.fields.$i.requiring_bytes()),*,
219 _ => unreachable!()
220 }
221 }
222 }
223 impl<$($f),*> FieldEncode for Oneof<($($f),*,)>
224 where
225 $($f: RequiredFieldEncode),*
226 {
227 }
228 impl<$($f),*> RequiredFieldEncode for Oneof<($($f),*,)>
229 where
230 $($f: RequiredFieldEncode),*
231 {
232 }
233 impl<$($f),*> SizedEncode for Oneof<($($f),*,)>
234 where
235 $($f: RequiredFieldEncode + SizedEncode),*
236 {
237 fn exact_requiring_bytes(&self) -> u64 {
238 if self.index == 0 {
239 return 0;
240 }
241 match self.index - 1 {
242 $($i => self.fields.$i.exact_requiring_bytes()),*,
243 _ => unreachable!(),
244 }
245 }
246 }
247 };
248}
249
250impl_field_decode!(Branch2, [A, B], [0, 1]);
251impl_field_decode!(Branch3, [A, B, C], [0, 1, 2]);
252impl_field_decode!(Branch4, [A, B, C, D], [0, 1, 2, 3]);
253impl_field_decode!(Branch5, [A, B, C, D, E], [0, 1, 2, 3, 4]);
254impl_field_decode!(Branch6, [A, B, C, D, E, F], [0, 1, 2, 3, 4, 5]);
255impl_field_decode!(Branch7, [A, B, C, D, E, F, G], [0, 1, 2, 3, 4, 5, 6]);
256impl_field_decode!(Branch8, [A, B, C, D, E, F, G, H], [0, 1, 2, 3, 4, 5, 6, 7]);
257
258impl_field_encode!(Branch2, [A, B], [0, 1]);
259impl_field_encode!(Branch3, [A, B, C], [0, 1, 2]);
260impl_field_encode!(Branch4, [A, B, C, D], [0, 1, 2, 3]);
261impl_field_encode!(Branch5, [A, B, C, D, E], [0, 1, 2, 3, 4]);
262impl_field_encode!(Branch6, [A, B, C, D, E, F], [0, 1, 2, 3, 4, 5]);
263impl_field_encode!(Branch7, [A, B, C, D, E, F, G], [0, 1, 2, 3, 4, 5, 6]);
264impl_field_encode!(Branch8, [A, B, C, D, E, F, G, H], [0, 1, 2, 3, 4, 5, 6, 7]);