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