Skip to main content

fidl_next_codec/wire/
union.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use core::mem::MaybeUninit;
6
7use munge::munge;
8
9use crate::decoder::InternalHandleDecoder;
10use crate::encoder::InternalHandleEncoder;
11use crate::{
12    Constrained, Decode, DecodeError, Decoder, Encode, EncodeError, Encoder, Slot, ValidationError,
13    Wire, wire,
14};
15
16/// A raw FIDL union
17#[repr(C)]
18pub struct Union {
19    ordinal: wire::Uint64,
20    envelope: wire::Envelope,
21}
22
23impl Constrained for Union {
24    type Constraint = ();
25
26    fn validate(_: Slot<'_, Self>, _: Self::Constraint) -> Result<(), ValidationError> {
27        Ok(())
28    }
29}
30
31unsafe impl Wire for Union {
32    type Narrowed<'de> = Self;
33
34    #[inline]
35    fn zero_padding(_: &mut MaybeUninit<Self>) {
36        // Wire unions have no padding
37    }
38}
39
40impl Union {
41    /// Encodes that a union is absent in a slot.
42    #[inline]
43    pub fn encode_absent(out: &mut MaybeUninit<Self>) {
44        munge!(let Self { ordinal, envelope } = out);
45
46        ordinal.write(wire::Uint64(0));
47        wire::Envelope::encode_zero(envelope);
48    }
49
50    /// Encodes a `'static` value and ordinal in a slot.
51    #[inline]
52    pub fn encode_as_static<E: InternalHandleEncoder + ?Sized, W: Wire>(
53        value: impl Encode<W, E>,
54        ord: u64,
55        encoder: &mut E,
56        out: &mut MaybeUninit<Self>,
57        constraint: W::Constraint,
58    ) -> Result<(), EncodeError> {
59        munge!(let Self { ordinal, envelope } = out);
60
61        ordinal.write(wire::Uint64(ord));
62        wire::Envelope::encode_value_static(value, encoder, envelope, constraint)
63    }
64
65    /// Encodes a value and ordinal in a slot.
66    #[inline]
67    pub fn encode_as<E: Encoder + ?Sized, W: Wire>(
68        value: impl Encode<W, E>,
69        ord: u64,
70        encoder: &mut E,
71        out: &mut MaybeUninit<Self>,
72        constraint: W::Constraint,
73    ) -> Result<(), EncodeError> {
74        munge!(let Self { ordinal, envelope } = out);
75
76        ordinal.write(wire::Uint64(ord));
77        wire::Envelope::encode_value(value, encoder, envelope, constraint)
78    }
79
80    /// Returns the ordinal of the encoded value.
81    #[inline]
82    pub fn encoded_ordinal(slot: Slot<'_, Self>) -> u64 {
83        munge!(let Self { ordinal, envelope: _ } = slot);
84        **ordinal
85    }
86
87    /// Decodes an absent union from a slot.
88    #[inline]
89    pub fn decode_absent(slot: Slot<'_, Self>) -> Result<(), DecodeError> {
90        munge!(let Self { ordinal: _, envelope } = slot);
91        if !wire::Envelope::is_encoded_zero(envelope) {
92            return Err(DecodeError::InvalidUnionEnvelope);
93        }
94        Ok(())
95    }
96
97    /// Decodes an unknown `'static` value from a union.
98    ///
99    /// The handles owned by the unknown value are discarded.
100    #[inline]
101    pub fn decode_unknown_static<D: InternalHandleDecoder + ?Sized>(
102        slot: Slot<'_, Self>,
103        decoder: &mut D,
104    ) -> Result<(), DecodeError> {
105        munge!(let Self { ordinal: _, envelope } = slot);
106        wire::Envelope::decode_unknown_static(envelope, decoder)
107    }
108
109    /// Decodes an unknown value from a union.
110    ///
111    /// The handles owned by the unknown value are discarded.
112    #[inline]
113    pub fn decode_unknown<'de, D: Decoder<'de> + ?Sized>(
114        slot: Slot<'_, Self>,
115        decoder: &mut D,
116    ) -> Result<(), DecodeError> {
117        munge!(let Self { ordinal: _, envelope } = slot);
118        wire::Envelope::decode_unknown(envelope, decoder)
119    }
120
121    /// Decodes the typed `'static` value in a union.
122    #[inline]
123    pub fn decode_as_static<D: InternalHandleDecoder + ?Sized, T: Decode<D>>(
124        slot: Slot<'_, Self>,
125        decoder: &mut D,
126        constraint: T::Constraint,
127    ) -> Result<(), DecodeError> {
128        munge!(let Self { ordinal: _, envelope } = slot);
129        wire::Envelope::decode_as_static::<D, T>(envelope, decoder, constraint)
130    }
131
132    /// Decodes the typed value in a union.
133    #[inline]
134    pub fn decode_as<'de, D: Decoder<'de> + ?Sized, T: Decode<D>>(
135        slot: Slot<'_, Self>,
136        decoder: &mut D,
137        constraint: T::Constraint,
138    ) -> Result<(), DecodeError> {
139        munge!(let Self { ordinal: _, envelope } = slot);
140        wire::Envelope::decode_as::<D, T>(envelope, decoder, constraint)
141    }
142
143    /// The absent optional union.
144    #[inline]
145    pub fn absent() -> Self {
146        Self { ordinal: wire::Uint64(0), envelope: wire::Envelope::zero() }
147    }
148
149    /// Returns whether the union contains a value.
150    #[inline]
151    pub fn is_some(&self) -> bool {
152        *self.ordinal != 0
153    }
154
155    /// Returns whether the union is empty.
156    #[inline]
157    pub fn is_none(&self) -> bool {
158        !self.is_some()
159    }
160
161    /// Returns the ordinal of the union.
162    #[inline]
163    pub fn ordinal(&self) -> u64 {
164        *self.ordinal
165    }
166
167    /// Gets a reference to the envelope underlying the union.
168    #[inline]
169    pub fn get(&self) -> &wire::Envelope {
170        &self.envelope
171    }
172
173    /// Clones the union, assuming that it contains an inline `T`.
174    ///
175    /// # Safety
176    ///
177    /// The union must have been successfully decoded inline as a `T`.
178    #[inline]
179    pub unsafe fn clone_inline_unchecked<T: Clone>(&self) -> Self {
180        Self {
181            ordinal: self.ordinal,
182            envelope: unsafe { self.envelope.clone_inline_unchecked::<T>() },
183        }
184    }
185}