fidl_next_codec/wire/
result.rs

1// Copyright 2025 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::fmt;
6use core::marker::PhantomData;
7use core::mem::{ManuallyDrop, MaybeUninit};
8
9use crate::{
10    munge, Chunk, Decode, DecodeError, Decoder, Encodable, Encode, EncodeError, EncodeRef, Encoder,
11    FromWire, FromWireRef, RawWireUnion, Slot, Wire,
12};
13
14/// A FIDL result union.
15#[repr(transparent)]
16pub struct WireResult<'de, T, E> {
17    raw: RawWireUnion,
18    _phantom: PhantomData<(&'de mut [Chunk], T, E)>,
19}
20
21impl<T, E> Drop for WireResult<'_, T, E> {
22    fn drop(&mut self) {
23        match self.raw.ordinal() {
24            ORD_OK => {
25                let _ = unsafe { self.raw.get().read_unchecked::<T>() };
26            }
27            ORD_ERR => {
28                let _ = unsafe { self.raw.get().read_unchecked::<E>() };
29            }
30            _ => unsafe { ::core::hint::unreachable_unchecked() },
31        }
32    }
33}
34
35unsafe impl<T: Wire, E: Wire> Wire for WireResult<'static, T, E> {
36    type Decoded<'de> = WireResult<'de, T::Decoded<'de>, E::Decoded<'de>>;
37
38    #[inline]
39    fn zero_padding(out: &mut MaybeUninit<Self>) {
40        munge!(let Self { raw, _phantom: _ } = out);
41        RawWireUnion::zero_padding(raw);
42    }
43}
44
45const ORD_OK: u64 = 1;
46const ORD_ERR: u64 = 2;
47
48impl<T, E> WireResult<'_, T, E> {
49    /// Returns whether the result is `Ok`.
50    pub fn is_ok(&self) -> bool {
51        self.raw.ordinal() == ORD_OK
52    }
53
54    /// Returns whether the result is `Err`.
55    pub fn is_err(&self) -> bool {
56        self.raw.ordinal() == ORD_ERR
57    }
58
59    /// Returns the `Ok` value of the result, if any.
60    pub fn ok(&self) -> Option<&T> {
61        self.is_ok().then(|| unsafe { self.raw.get().deref_unchecked() })
62    }
63
64    /// Returns the `Err` value of the result, if any.
65    pub fn err(&self) -> Option<&E> {
66        self.is_err().then(|| unsafe { self.raw.get().deref_unchecked() })
67    }
68
69    /// Returns the contained `Ok` value.
70    ///
71    /// Panics if the result was not `Ok`.
72    pub fn unwrap(&self) -> &T {
73        self.ok().unwrap()
74    }
75
76    /// Returns the contained `Err` value.
77    ///
78    /// Panics if the result was not `Err`.
79    pub fn unwrap_err(&self) -> &E {
80        self.err().unwrap()
81    }
82
83    /// Returns a `Result` of a reference to the value or error.
84    pub fn as_ref(&self) -> Result<&T, &E> {
85        match self.raw.ordinal() {
86            ORD_OK => unsafe { Ok(self.raw.get().deref_unchecked()) },
87            ORD_ERR => unsafe { Err(self.raw.get().deref_unchecked()) },
88            _ => unsafe { ::core::hint::unreachable_unchecked() },
89        }
90    }
91
92    /// Returns a `Result` of the owned value or error.
93    pub fn into_result(self) -> Result<T, E> {
94        let this = ManuallyDrop::new(self);
95        match this.raw.ordinal() {
96            ORD_OK => unsafe { Ok(this.raw.get().read_unchecked()) },
97            ORD_ERR => unsafe { Err(this.raw.get().read_unchecked()) },
98            _ => unsafe { ::core::hint::unreachable_unchecked() },
99        }
100    }
101}
102
103impl<T: Clone, E: Clone> Clone for WireResult<'_, T, E> {
104    fn clone(&self) -> Self {
105        Self {
106            raw: match self.raw.ordinal() {
107                ORD_OK => unsafe { self.raw.clone_inline_unchecked::<T>() },
108                ORD_ERR => unsafe { self.raw.clone_inline_unchecked::<E>() },
109                _ => unsafe { ::core::hint::unreachable_unchecked() },
110            },
111            _phantom: PhantomData,
112        }
113    }
114}
115
116impl<T, E> fmt::Debug for WireResult<'_, T, E>
117where
118    T: fmt::Debug,
119    E: fmt::Debug,
120{
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122        self.as_ref().fmt(f)
123    }
124}
125
126unsafe impl<D, T, E> Decode<D> for WireResult<'static, T, E>
127where
128    D: Decoder + ?Sized,
129    T: Decode<D>,
130    E: Decode<D>,
131{
132    fn decode(slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
133        munge!(let Self { mut raw, _phantom: _ } = slot);
134
135        match RawWireUnion::encoded_ordinal(raw.as_mut()) {
136            ORD_OK => RawWireUnion::decode_as::<D, T>(raw, decoder)?,
137            ORD_ERR => RawWireUnion::decode_as::<D, E>(raw, decoder)?,
138            ord => return Err(DecodeError::InvalidUnionOrdinal(ord as usize)),
139        }
140
141        Ok(())
142    }
143}
144
145impl<T, E> Encodable for Result<T, E>
146where
147    T: Encodable,
148    E: Encodable,
149{
150    type Encoded = WireResult<'static, T::Encoded, E::Encoded>;
151}
152
153unsafe impl<Enc, T, E> Encode<Enc> for Result<T, E>
154where
155    Enc: Encoder + ?Sized,
156    T: Encode<Enc>,
157    E: Encode<Enc>,
158{
159    fn encode(
160        self,
161        encoder: &mut Enc,
162        out: &mut MaybeUninit<Self::Encoded>,
163    ) -> Result<(), EncodeError> {
164        munge!(let WireResult { raw, _phantom: _ } = out);
165
166        match self {
167            Ok(value) => RawWireUnion::encode_as::<Enc, T>(value, ORD_OK, encoder, raw)?,
168            Err(error) => RawWireUnion::encode_as::<Enc, E>(error, ORD_ERR, encoder, raw)?,
169        }
170
171        Ok(())
172    }
173}
174
175unsafe impl<Enc, T, E> EncodeRef<Enc> for Result<T, E>
176where
177    Enc: Encoder + ?Sized,
178    T: EncodeRef<Enc>,
179    E: EncodeRef<Enc>,
180{
181    fn encode_ref(
182        &self,
183        encoder: &mut Enc,
184        out: &mut MaybeUninit<Self::Encoded>,
185    ) -> Result<(), EncodeError> {
186        self.as_ref().encode(encoder, out)
187    }
188}
189
190impl<T, E, WT, WE> FromWire<WireResult<'_, WT, WE>> for Result<T, E>
191where
192    T: FromWire<WT>,
193    E: FromWire<WE>,
194{
195    #[inline]
196    fn from_wire(wire: WireResult<'_, WT, WE>) -> Self {
197        match wire.into_result() {
198            Ok(value) => Ok(T::from_wire(value)),
199            Err(error) => Err(E::from_wire(error)),
200        }
201    }
202}
203
204impl<T, E, WT, WE> FromWireRef<WireResult<'_, WT, WE>> for Result<T, E>
205where
206    T: FromWireRef<WT>,
207    E: FromWireRef<WE>,
208{
209    #[inline]
210    fn from_wire_ref(wire: &WireResult<'_, WT, WE>) -> Self {
211        match wire.as_ref() {
212            Ok(value) => Ok(T::from_wire_ref(value)),
213            Err(error) => Err(E::from_wire_ref(error)),
214        }
215    }
216}