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