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