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