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;
7
8use crate::{
9    munge, Decode, DecodeError, Decoder, Encodable, Encode, EncodeError, Encoder, RawWireUnion,
10    Slot, TakeFrom, ZeroPadding,
11};
12
13/// A FIDL result union.
14#[repr(transparent)]
15pub struct WireResult<T, E> {
16    raw: RawWireUnion,
17    _phantom: PhantomData<(T, E)>,
18}
19
20unsafe impl<T, E> ZeroPadding for WireResult<T, E> {
21    #[inline]
22    unsafe fn zero_padding(ptr: *mut Self) {
23        unsafe {
24            RawWireUnion::zero_padding(ptr.cast());
25        }
26    }
27}
28
29const ORD_OK: u64 = 1;
30const ORD_ERR: u64 = 2;
31
32impl<T, E> WireResult<T, E> {
33    /// Returns whether the result is `Ok`.
34    pub fn is_ok(&self) -> bool {
35        self.raw.ordinal() == ORD_OK
36    }
37
38    /// Returns whether the result is `Err`.
39    pub fn is_err(&self) -> bool {
40        self.raw.ordinal() == ORD_ERR
41    }
42
43    /// Returns the `Ok` value of the result, if any.
44    pub fn ok(&self) -> Option<&T> {
45        self.is_ok().then(|| unsafe { self.raw.get().deref_unchecked() })
46    }
47
48    /// Returns the `Err` value of the result, if any.
49    pub fn err(&self) -> Option<&E> {
50        self.is_err().then(|| unsafe { self.raw.get().deref_unchecked() })
51    }
52
53    /// Returns the contained `Ok` value.
54    ///
55    /// Panics if the result was not `Ok`.
56    pub fn unwrap(&self) -> &T {
57        self.ok().unwrap()
58    }
59
60    /// Returns the contained `Err` value.
61    ///
62    /// Panics if the result was not `Err`.
63    pub fn unwrap_err(&self) -> &E {
64        self.err().unwrap()
65    }
66
67    /// Returns a `Result` of a reference to the value or error.
68    pub fn as_ref(&self) -> Result<&T, &E> {
69        match self.raw.ordinal() {
70            ORD_OK => unsafe { Ok(self.raw.get().deref_unchecked()) },
71            ORD_ERR => unsafe { Err(self.raw.get().deref_unchecked()) },
72            _ => unsafe { ::core::hint::unreachable_unchecked() },
73        }
74    }
75}
76
77impl<T, E> fmt::Debug for WireResult<T, E>
78where
79    T: fmt::Debug,
80    E: fmt::Debug,
81{
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        self.as_ref().fmt(f)
84    }
85}
86
87unsafe impl<D, T, E> Decode<D> for WireResult<T, E>
88where
89    D: Decoder + ?Sized,
90    T: Decode<D>,
91    E: Decode<D>,
92{
93    fn decode(slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
94        munge!(let Self { mut raw, _phantom: _ } = slot);
95
96        match RawWireUnion::encoded_ordinal(raw.as_mut()) {
97            ORD_OK => RawWireUnion::decode_as::<D, T>(raw, decoder)?,
98            ORD_ERR => RawWireUnion::decode_as::<D, E>(raw, decoder)?,
99            ord => return Err(DecodeError::InvalidUnionOrdinal(ord as usize)),
100        }
101
102        Ok(())
103    }
104}
105
106impl<T, E> Encodable for Result<T, E>
107where
108    T: Encodable,
109    E: Encodable,
110{
111    type Encoded = WireResult<T::Encoded, E::Encoded>;
112}
113
114impl<Enc, T, E> Encode<Enc> for Result<T, E>
115where
116    Enc: Encoder + ?Sized,
117    T: Encode<Enc>,
118    E: Encode<Enc>,
119{
120    fn encode(
121        &mut self,
122        encoder: &mut Enc,
123        slot: Slot<'_, Self::Encoded>,
124    ) -> Result<(), EncodeError> {
125        munge!(let WireResult { raw, _phantom: _ } = slot);
126
127        match self {
128            Ok(value) => RawWireUnion::encode_as::<Enc, T>(value, ORD_OK, encoder, raw)?,
129            Err(error) => RawWireUnion::encode_as::<Enc, E>(error, ORD_ERR, encoder, raw)?,
130        }
131
132        Ok(())
133    }
134}
135
136impl<T, E, WT, WE> TakeFrom<WireResult<WT, WE>> for Result<T, E>
137where
138    T: TakeFrom<WT>,
139    E: TakeFrom<WE>,
140{
141    fn take_from(from: &WireResult<WT, WE>) -> Self {
142        match from.as_ref() {
143            Ok(value) => Ok(T::take_from(value)),
144            Err(error) => Err(E::take_from(error)),
145        }
146    }
147}