bilrost/encoding/
oneof.rs

1use crate::buf::ReverseBuf;
2use crate::encoding::{
3    Capped, DecodeContext, RestrictedDecodeContext, TagMeasurer, TagRevWriter, TagWriter, WireType,
4};
5use crate::{Canonicity, DecodeError};
6use alloc::boxed::Box;
7use bytes::{Buf, BufMut};
8
9/// Trait to be implemented by (or more commonly derived for) oneofs, which have knowledge of their
10/// variants' tags and encoding.
11///
12/// `Oneof` values can be represented in messages because they have an "empty"  state (typically a
13/// dedicated empty enum variant or Option::None). When `Oneof` is derived for an enum that does not
14/// have a unit variant, the trait that is actually derived is `NonEmptyOneof`, which has no empty
15/// states and must be wrapped in `Option` at some point to be used.
16///
17/// In addition to decoding into the variants of the oneof, implementations of the maybe-empty
18/// `Oneof` traits need to be able to return and attach useful details to the appropriate errors for
19/// collisions (when they decode a field but they already contain values) or when decoding a value
20/// for the oneof otherwise encounters an error. For this reason there are the following differences
21/// between `Oneof` and `NonEmptyOneof`:
22///
23/// * `Oneof::oneof_current_tag` returns `Option<u32>` instead of `u32`
24/// * `Oneof::oneof_decode_field` accepts a `value: &mut Self` argument, while `NonEmptyOneof` does
25///   not; the `Oneof` version of this function returns `Result<(), DecodeError>`, and the
26///   `NonEmptyOneof` version returns `Result<Self, DecodeError>` directly.
27/// * `Oneof::oneof_decode_field` is responsible for attaching error detail information when a
28///   decoding error occurs, while `NonEmptyOneof` does not need to do that.
29///
30/// There are implementations provided, like `impl<T> Oneof for Option<T> where T: NonEmptyOneof`
31/// for all relevant oneof decoder traits (see the `generic_oneof_grant_empty_state_impls` mod).
32/// These implementations take care of the above contract boundary as well.
33///
34/// Other than that: Both empty and non-empty oneofs can be `Box`ed, as there are also wrapper impls
35/// to cover that.
36pub trait Oneof {
37    const FIELD_TAGS: &'static [u32];
38
39    /// Returns a new empty oneof.
40    fn empty() -> Self;
41
42    /// Returns whether the oneof is in the empty variant.
43    fn is_empty(&self) -> bool;
44
45    /// Resets the oneof to the empty variant.
46    fn clear(&mut self);
47
48    /// Encodes the fields of the oneof into the given buffer.
49    fn oneof_encode<B: BufMut + ?Sized>(&self, buf: &mut B, tw: &mut TagWriter);
50
51    /// Prepends the fields of the oneof into the given buffer.
52    fn oneof_prepend<B: ReverseBuf + ?Sized>(&self, buf: &mut B, tw: &mut TagRevWriter);
53
54    /// Measures the number of bytes that would encode this oneof.
55    fn oneof_encoded_len(&self, tm: &mut impl TagMeasurer) -> usize;
56
57    /// Returns the current tag of the oneof, if any.
58    fn oneof_current_tag(&self) -> Option<u32>;
59
60    /// Returns the diagnostic name of the variant with the given tag. The first returned value is
61    /// the name of the oneof enum, and the second is the name of the field.
62    fn oneof_variant_name(tag: u32) -> (&'static str, &'static str);
63}
64
65/// Relaxed owned decoding trait for oneofs.
66pub trait OneofDecoder: Oneof {
67    /// Decodes from the given buffer.
68    fn oneof_decode_field<B: Buf + ?Sized>(
69        value: &mut Self,
70        tag: u32,
71        wire_type: WireType,
72        buf: Capped<B>,
73        ctx: DecodeContext,
74    ) -> Result<(), DecodeError>;
75}
76
77/// Distinguished owned decoding trait for oneofs.
78pub trait DistinguishedOneofDecoder: Oneof {
79    /// Decodes from the given buffer in distinguished mode.
80    fn oneof_decode_field_distinguished<B: Buf + ?Sized>(
81        value: &mut Self,
82        tag: u32,
83        wire_type: WireType,
84        buf: Capped<B>,
85        ctx: RestrictedDecodeContext,
86    ) -> Result<Canonicity, DecodeError>;
87}
88
89/// Relaxed borrowed decoding trait for oneofs.
90pub trait OneofBorrowDecoder<'a>: Oneof {
91    fn oneof_borrow_decode_field(
92        value: &mut Self,
93        tag: u32,
94        wire_type: WireType,
95        buf: Capped<&'a [u8]>,
96        ctx: DecodeContext,
97    ) -> Result<(), DecodeError>;
98}
99
100/// Distinguished borrowed decoding trait for oneofs.
101pub trait DistinguishedOneofBorrowDecoder<'a>: Oneof {
102    fn oneof_borrow_decode_field_distinguished(
103        value: &mut Self,
104        tag: u32,
105        wire_type: WireType,
106        buf: Capped<&'a [u8]>,
107        ctx: RestrictedDecodeContext,
108    ) -> Result<Canonicity, DecodeError>;
109}
110
111/// Underlying trait for a oneof that has no inherent "empty" variant, opting instead to be wrapped
112/// in an `Option`. This is the real trait that is derived for `enum` types that don't have a
113/// natural unit variant. Like the other `Oneof` traits, this is not intended for use by library
114/// users.
115pub trait NonEmptyOneof {
116    const FIELD_TAGS: &'static [u32];
117
118    /// Encodes the fields of the oneof into the given buffer.
119    fn oneof_encode<B: BufMut + ?Sized>(&self, buf: &mut B, tw: &mut TagWriter);
120
121    /// Prepends the fields of the oneof into the given buffer.
122    fn oneof_prepend<B: ReverseBuf + ?Sized>(&self, buf: &mut B, tw: &mut TagRevWriter);
123
124    /// Measures the number of bytes that would encode this oneof.
125    fn oneof_encoded_len(&self, tm: &mut impl TagMeasurer) -> usize;
126
127    /// Returns the current tag of the oneof.
128    fn oneof_current_tag(&self) -> u32;
129
130    /// Returns the diagnostic name of the variant with the given tag. The first returned value is
131    /// the name of the oneof enum, and the second is the name of the field.
132    fn oneof_variant_name(tag: u32) -> (&'static str, &'static str);
133}
134
135/// Relaxed owned decoding trait for non-empty oneofs.
136pub trait NonEmptyOneofDecoder: NonEmptyOneof + Sized {
137    /// Decodes from the given buffer.
138    fn oneof_decode_field<B: Buf + ?Sized>(
139        tag: u32,
140        wire_type: WireType,
141        buf: Capped<B>,
142        ctx: DecodeContext,
143    ) -> Result<Self, DecodeError>;
144}
145
146/// Distinguished owned decoding trait for non-empty oneofs.
147pub trait NonEmptyDistinguishedOneofDecoder: NonEmptyOneof + Sized {
148    /// Decodes from the given buffer.
149    fn oneof_decode_field_distinguished<B: Buf + ?Sized>(
150        tag: u32,
151        wire_type: WireType,
152        buf: Capped<B>,
153        ctx: RestrictedDecodeContext,
154    ) -> Result<(Self, Canonicity), DecodeError>;
155}
156
157/// Relaxed borrowed decoding trait for non-empty oneofs.
158pub trait NonEmptyOneofBorrowDecoder<'a>: NonEmptyOneof + Sized {
159    fn oneof_borrow_decode_field(
160        tag: u32,
161        wire_type: WireType,
162        buf: Capped<&'a [u8]>,
163        ctx: DecodeContext,
164    ) -> Result<Self, DecodeError>;
165}
166
167/// Distinguished borrowed decoding trait for non-empty oneofs.
168pub trait NonEmptyDistinguishedOneofBorrowDecoder<'a>: NonEmptyOneof + Sized {
169    fn oneof_borrow_decode_field_distinguished(
170        tag: u32,
171        wire_type: WireType,
172        buf: Capped<&'a [u8]>,
173        ctx: RestrictedDecodeContext,
174    ) -> Result<(Self, Canonicity), DecodeError>;
175}
176
177/// These are the impls that grant Oneof implementation status with a proper empty state to NonEmpty
178/// oneof implementers
179mod generic_oneof_grant_empty_state_impls {
180    use super::*;
181    use crate::DecodeErrorKind::{ConflictingFields, UnexpectedlyRepeated};
182
183    impl<T> Oneof for Option<T>
184    where
185        T: NonEmptyOneof,
186    {
187        const FIELD_TAGS: &'static [u32] = T::FIELD_TAGS;
188
189        fn empty() -> Self {
190            None
191        }
192
193        fn is_empty(&self) -> bool {
194            self.is_none()
195        }
196
197        fn clear(&mut self) {
198            *self = None;
199        }
200
201        #[inline]
202        fn oneof_encode<B: BufMut + ?Sized>(&self, buf: &mut B, tw: &mut TagWriter) {
203            if let Some(value) = self {
204                value.oneof_encode(buf, tw);
205            }
206        }
207
208        #[inline]
209        fn oneof_prepend<B: ReverseBuf + ?Sized>(&self, buf: &mut B, tw: &mut TagRevWriter) {
210            if let Some(value) = self {
211                value.oneof_prepend(buf, tw);
212            }
213        }
214
215        #[inline]
216        fn oneof_encoded_len(&self, tm: &mut impl TagMeasurer) -> usize {
217            if let Some(value) = self {
218                value.oneof_encoded_len(tm)
219            } else {
220                0
221            }
222        }
223
224        #[inline]
225        fn oneof_current_tag(&self) -> Option<u32> {
226            self.as_ref().map(NonEmptyOneof::oneof_current_tag)
227        }
228
229        #[inline]
230        fn oneof_variant_name(tag: u32) -> (&'static str, &'static str) {
231            T::oneof_variant_name(tag)
232        }
233    }
234
235    impl<T> OneofDecoder for Option<T>
236    where
237        T: NonEmptyOneofDecoder,
238    {
239        #[inline]
240        fn oneof_decode_field<B: Buf + ?Sized>(
241            value: &mut Self,
242            tag: u32,
243            wire_type: WireType,
244            buf: Capped<B>,
245            ctx: DecodeContext,
246        ) -> Result<(), DecodeError> {
247            if let Some(already) = value {
248                Err(DecodeError::new(if already.oneof_current_tag() == tag {
249                    UnexpectedlyRepeated
250                } else {
251                    ConflictingFields
252                }))
253            } else {
254                T::oneof_decode_field(tag, wire_type, buf, ctx)
255                    .map(|decoded| *value = Some(decoded))
256            }
257            .map_err(|mut err| {
258                let (msg, field) = T::oneof_variant_name(tag);
259                err.push(msg, field);
260                err
261            })
262        }
263    }
264
265    impl<T> DistinguishedOneofDecoder for Option<T>
266    where
267        T: NonEmptyDistinguishedOneofDecoder + NonEmptyOneof,
268        Self: Oneof,
269    {
270        #[inline]
271        fn oneof_decode_field_distinguished<B: Buf + ?Sized>(
272            value: &mut Self,
273            tag: u32,
274            wire_type: WireType,
275            buf: Capped<B>,
276            ctx: RestrictedDecodeContext,
277        ) -> Result<Canonicity, DecodeError> {
278            if let Some(already) = value {
279                Err(DecodeError::new(if already.oneof_current_tag() == tag {
280                    UnexpectedlyRepeated
281                } else {
282                    ConflictingFields
283                }))
284            } else {
285                T::oneof_decode_field_distinguished(tag, wire_type, buf, ctx.clone()).map(
286                    |(decoded, canon)| {
287                        *value = Some(decoded);
288                        canon
289                    },
290                )
291            }
292            .map_err(|mut err| {
293                let (msg, field) = T::oneof_variant_name(tag);
294                err.push(msg, field);
295                err
296            })
297        }
298    }
299
300    impl<'a, T> OneofBorrowDecoder<'a> for Option<T>
301    where
302        T: NonEmptyOneofBorrowDecoder<'a>,
303    {
304        #[inline]
305        fn oneof_borrow_decode_field(
306            value: &mut Self,
307            tag: u32,
308            wire_type: WireType,
309            buf: Capped<&'a [u8]>,
310            ctx: DecodeContext,
311        ) -> Result<(), DecodeError> {
312            if let Some(already) = value {
313                Err(DecodeError::new(if already.oneof_current_tag() == tag {
314                    UnexpectedlyRepeated
315                } else {
316                    ConflictingFields
317                }))
318            } else {
319                T::oneof_borrow_decode_field(tag, wire_type, buf, ctx)
320                    .map(|decoded| *value = Some(decoded))
321            }
322            .map_err(|mut err| {
323                let (msg, field) = T::oneof_variant_name(tag);
324                err.push(msg, field);
325                err
326            })
327        }
328    }
329
330    impl<'a, T> DistinguishedOneofBorrowDecoder<'a> for Option<T>
331    where
332        T: NonEmptyDistinguishedOneofBorrowDecoder<'a> + NonEmptyOneof,
333        Self: Oneof,
334    {
335        #[inline]
336        fn oneof_borrow_decode_field_distinguished(
337            value: &mut Self,
338            tag: u32,
339            wire_type: WireType,
340            buf: Capped<&'a [u8]>,
341            ctx: RestrictedDecodeContext,
342        ) -> Result<Canonicity, DecodeError> {
343            if let Some(already) = value {
344                Err(DecodeError::new(if already.oneof_current_tag() == tag {
345                    UnexpectedlyRepeated
346                } else {
347                    ConflictingFields
348                }))
349            } else {
350                T::oneof_borrow_decode_field_distinguished(tag, wire_type, buf, ctx.clone()).map(
351                    |(decoded, canon)| {
352                        *value = Some(decoded);
353                        canon
354                    },
355                )
356            }
357            .map_err(|mut err| {
358                let (msg, field) = T::oneof_variant_name(tag);
359                err.push(msg, field);
360                err
361            })
362        }
363    }
364}
365
366/// These are the impls that make the oneof trait transparent to Box
367mod generic_boxed_oneof_impls {
368    use super::*;
369
370    impl<T> Oneof for Box<T>
371    where
372        T: Oneof,
373    {
374        const FIELD_TAGS: &'static [u32] = <T as Oneof>::FIELD_TAGS;
375
376        #[inline]
377        fn empty() -> Self {
378            Box::new(T::empty())
379        }
380
381        #[inline]
382        fn is_empty(&self) -> bool {
383            self.as_ref().is_empty()
384        }
385
386        #[inline]
387        fn clear(&mut self) {
388            self.as_mut().clear()
389        }
390
391        #[inline]
392        fn oneof_encode<B: BufMut + ?Sized>(&self, buf: &mut B, tw: &mut TagWriter) {
393            Oneof::oneof_encode(&**self, buf, tw)
394        }
395
396        #[inline]
397        fn oneof_prepend<B: ReverseBuf + ?Sized>(&self, buf: &mut B, tw: &mut TagRevWriter) {
398            Oneof::oneof_prepend(&**self, buf, tw)
399        }
400
401        #[inline]
402        fn oneof_encoded_len(&self, tm: &mut impl TagMeasurer) -> usize {
403            Oneof::oneof_encoded_len(&**self, tm)
404        }
405
406        #[inline]
407        fn oneof_current_tag(&self) -> Option<u32> {
408            Oneof::oneof_current_tag(&**self)
409        }
410
411        #[inline]
412        fn oneof_variant_name(tag: u32) -> (&'static str, &'static str) {
413            T::oneof_variant_name(tag)
414        }
415    }
416
417    impl<T> OneofDecoder for Box<T>
418    where
419        T: OneofDecoder,
420    {
421        #[inline]
422        fn oneof_decode_field<B: Buf + ?Sized>(
423            value: &mut Self,
424            tag: u32,
425            wire_type: WireType,
426            buf: Capped<B>,
427            ctx: DecodeContext,
428        ) -> Result<(), DecodeError> {
429            OneofDecoder::oneof_decode_field(&mut **value, tag, wire_type, buf, ctx)
430        }
431    }
432
433    impl<T> DistinguishedOneofDecoder for Box<T>
434    where
435        T: DistinguishedOneofDecoder,
436    {
437        #[inline]
438        fn oneof_decode_field_distinguished<B: Buf + ?Sized>(
439            value: &mut Self,
440            tag: u32,
441            wire_type: WireType,
442            buf: Capped<B>,
443            ctx: RestrictedDecodeContext,
444        ) -> Result<Canonicity, DecodeError> {
445            DistinguishedOneofDecoder::oneof_decode_field_distinguished(
446                &mut **value,
447                tag,
448                wire_type,
449                buf,
450                ctx,
451            )
452        }
453    }
454
455    impl<'a, T> OneofBorrowDecoder<'a> for Box<T>
456    where
457        T: OneofBorrowDecoder<'a>,
458    {
459        #[inline]
460        fn oneof_borrow_decode_field(
461            value: &mut Self,
462            tag: u32,
463            wire_type: WireType,
464            buf: Capped<&'a [u8]>,
465            ctx: DecodeContext,
466        ) -> Result<(), DecodeError> {
467            OneofBorrowDecoder::oneof_borrow_decode_field(&mut **value, tag, wire_type, buf, ctx)
468        }
469    }
470
471    impl<'a, T> DistinguishedOneofBorrowDecoder<'a> for Box<T>
472    where
473        T: DistinguishedOneofBorrowDecoder<'a>,
474    {
475        #[inline]
476        fn oneof_borrow_decode_field_distinguished(
477            value: &mut Self,
478            tag: u32,
479            wire_type: WireType,
480            buf: Capped<&'a [u8]>,
481            ctx: RestrictedDecodeContext,
482        ) -> Result<Canonicity, DecodeError> {
483            DistinguishedOneofBorrowDecoder::oneof_borrow_decode_field_distinguished(
484                &mut **value,
485                tag,
486                wire_type,
487                buf,
488                ctx,
489            )
490        }
491    }
492
493    impl<T> NonEmptyOneof for Box<T>
494    where
495        T: NonEmptyOneof,
496    {
497        const FIELD_TAGS: &'static [u32] = <T as NonEmptyOneof>::FIELD_TAGS;
498
499        #[inline]
500        fn oneof_encode<B: BufMut + ?Sized>(&self, buf: &mut B, tw: &mut TagWriter) {
501            NonEmptyOneof::oneof_encode(&**self, buf, tw)
502        }
503
504        #[inline]
505        fn oneof_prepend<B: ReverseBuf + ?Sized>(&self, buf: &mut B, tw: &mut TagRevWriter) {
506            NonEmptyOneof::oneof_prepend(&**self, buf, tw)
507        }
508
509        #[inline]
510        fn oneof_encoded_len(&self, tm: &mut impl TagMeasurer) -> usize {
511            NonEmptyOneof::oneof_encoded_len(&**self, tm)
512        }
513
514        #[inline]
515        fn oneof_current_tag(&self) -> u32 {
516            NonEmptyOneof::oneof_current_tag(&**self)
517        }
518
519        #[inline]
520        fn oneof_variant_name(tag: u32) -> (&'static str, &'static str) {
521            T::oneof_variant_name(tag)
522        }
523    }
524
525    impl<T> NonEmptyOneofDecoder for Box<T>
526    where
527        T: NonEmptyOneofDecoder,
528    {
529        #[inline]
530        fn oneof_decode_field<B: Buf + ?Sized>(
531            tag: u32,
532            wire_type: WireType,
533            buf: Capped<B>,
534            ctx: DecodeContext,
535        ) -> Result<Self, DecodeError> {
536            T::oneof_decode_field(tag, wire_type, buf, ctx).map(Box::new)
537        }
538    }
539
540    impl<T> NonEmptyDistinguishedOneofDecoder for Box<T>
541    where
542        T: NonEmptyDistinguishedOneofDecoder,
543    {
544        #[inline]
545        fn oneof_decode_field_distinguished<B: Buf + ?Sized>(
546            tag: u32,
547            wire_type: WireType,
548            buf: Capped<B>,
549            ctx: RestrictedDecodeContext,
550        ) -> Result<(Self, Canonicity), DecodeError> {
551            NonEmptyDistinguishedOneofDecoder::oneof_decode_field_distinguished(
552                tag, wire_type, buf, ctx,
553            )
554            .map(|(val, canon)| (Box::new(val), canon))
555        }
556    }
557
558    impl<'a, T> NonEmptyOneofBorrowDecoder<'a> for Box<T>
559    where
560        T: NonEmptyOneofBorrowDecoder<'a>,
561    {
562        #[inline]
563        fn oneof_borrow_decode_field(
564            tag: u32,
565            wire_type: WireType,
566            buf: Capped<&'a [u8]>,
567            ctx: DecodeContext,
568        ) -> Result<Self, DecodeError> {
569            NonEmptyOneofBorrowDecoder::oneof_borrow_decode_field(tag, wire_type, buf, ctx)
570                .map(Box::new)
571        }
572    }
573
574    impl<'a, T> NonEmptyDistinguishedOneofBorrowDecoder<'a> for Box<T>
575    where
576        T: NonEmptyDistinguishedOneofBorrowDecoder<'a>,
577    {
578        #[inline]
579        fn oneof_borrow_decode_field_distinguished(
580            tag: u32,
581            wire_type: WireType,
582            buf: Capped<&'a [u8]>,
583            ctx: RestrictedDecodeContext,
584        ) -> Result<(Self, Canonicity), DecodeError> {
585            NonEmptyDistinguishedOneofBorrowDecoder::oneof_borrow_decode_field_distinguished(
586                tag, wire_type, buf, ctx,
587            )
588            .map(|(val, canon)| (Box::new(val), canon))
589        }
590    }
591}