1use core::fmt;
6use core::marker::PhantomData;
7use core::mem::MaybeUninit;
8
9use fidl_next_codec::{
10 munge, Decode, DecodeError, Decoder, Encodable, Encode, EncodeError, EncodeRef, Encoder,
11 RawWireUnion, Slot, TakeFrom, WireResult, ZeroPadding,
12};
13
14use crate::{FrameworkError, WireFrameworkError};
15
16#[derive(Debug)]
18pub enum FlexibleResult<T, E> {
19 Ok(T),
21 Err(E),
23 FrameworkErr(FrameworkError),
25}
26
27impl<T, E> FlexibleResult<T, E> {
28 pub fn as_ref(&self) -> FlexibleResult<&T, &E> {
30 match self {
31 Self::Ok(value) => FlexibleResult::Ok(value),
32 Self::Err(error) => FlexibleResult::Err(error),
33 Self::FrameworkErr(framework_error) => FlexibleResult::FrameworkErr(*framework_error),
34 }
35 }
36}
37
38#[repr(transparent)]
40pub struct WireFlexibleResult<T, E> {
41 raw: RawWireUnion,
42 _phantom: PhantomData<(T, E)>,
43}
44
45unsafe impl<T, E> ZeroPadding for WireFlexibleResult<T, E> {
46 #[inline]
47 fn zero_padding(out: &mut MaybeUninit<Self>) {
48 munge!(let Self { raw, _phantom: _ } = out);
49 RawWireUnion::zero_padding(raw);
50 }
51}
52
53const ORD_OK: u64 = 1;
54const ORD_ERR: u64 = 2;
55const ORD_FRAMEWORK_ERR: u64 = 3;
56
57impl<T, E> WireFlexibleResult<T, E> {
58 pub fn is_ok(&self) -> bool {
60 self.raw.ordinal() == ORD_OK
61 }
62
63 pub fn is_err(&self) -> bool {
65 self.raw.ordinal() == ORD_ERR
66 }
67
68 pub fn is_framework_err(&self) -> bool {
70 self.raw.ordinal() == ORD_FRAMEWORK_ERR
71 }
72
73 pub fn ok(&self) -> Option<&T> {
75 self.is_ok().then(|| unsafe { self.raw.get().deref_unchecked() })
76 }
77
78 pub fn err(&self) -> Option<&E> {
80 self.is_err().then(|| unsafe { self.raw.get().deref_unchecked() })
81 }
82
83 pub fn framework_err(&self) -> Option<FrameworkError> {
85 self.is_framework_err()
86 .then(|| unsafe { (*self.raw.get().deref_unchecked::<WireFrameworkError>()).into() })
87 }
88
89 pub fn unwrap(&self) -> &T {
93 self.ok().unwrap()
94 }
95
96 pub fn unwrap_err(&self) -> &E {
100 self.err().unwrap()
101 }
102
103 pub fn unwrap_framework_err(&self) -> FrameworkError {
107 self.framework_err().unwrap()
108 }
109
110 pub fn as_ref(&self) -> FlexibleResult<&T, &E> {
112 match self.raw.ordinal() {
113 ORD_OK => unsafe { FlexibleResult::Ok(self.raw.get().deref_unchecked()) },
114 ORD_ERR => unsafe { FlexibleResult::Err(self.raw.get().deref_unchecked()) },
115 ORD_FRAMEWORK_ERR => unsafe {
116 FlexibleResult::FrameworkErr(
117 (*self.raw.get().deref_unchecked::<WireFrameworkError>()).into(),
118 )
119 },
120 _ => unsafe { ::core::hint::unreachable_unchecked() },
121 }
122 }
123
124 pub fn as_response(&self) -> Result<&WireResult<T, E>, FrameworkError> {
126 match self.raw.ordinal() {
127 ORD_OK | ORD_ERR => unsafe { Ok(&*(self as *const Self as *const WireResult<T, E>)) },
128 ORD_FRAMEWORK_ERR => unsafe {
129 Err((*self.raw.get().deref_unchecked::<WireFrameworkError>()).into())
130 },
131 _ => unsafe { ::core::hint::unreachable_unchecked() },
132 }
133 }
134
135 pub fn as_result(&self) -> Result<Result<&T, &E>, FrameworkError> {
137 match self.raw.ordinal() {
138 ORD_OK => unsafe { Ok(Ok(self.raw.get().deref_unchecked())) },
139 ORD_ERR => unsafe { Ok(Err(self.raw.get().deref_unchecked())) },
140 ORD_FRAMEWORK_ERR => unsafe {
141 Err((*self.raw.get().deref_unchecked::<WireFrameworkError>()).into())
142 },
143 _ => unsafe { ::core::hint::unreachable_unchecked() },
144 }
145 }
146}
147
148impl<T, E> fmt::Debug for WireFlexibleResult<T, E>
149where
150 T: fmt::Debug,
151 E: fmt::Debug,
152{
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 self.as_ref().fmt(f)
155 }
156}
157
158unsafe impl<D, T, E> Decode<D> for WireFlexibleResult<T, E>
159where
160 D: Decoder + ?Sized,
161 T: Decode<D>,
162 E: Decode<D>,
163{
164 fn decode(slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
165 munge!(let Self { mut raw, _phantom: _ } = slot);
166
167 match RawWireUnion::encoded_ordinal(raw.as_mut()) {
168 ORD_OK => RawWireUnion::decode_as::<D, T>(raw, decoder)?,
169 ORD_ERR => RawWireUnion::decode_as::<D, E>(raw, decoder)?,
170 ORD_FRAMEWORK_ERR => RawWireUnion::decode_as::<D, WireFrameworkError>(raw, decoder)?,
171 ord => return Err(DecodeError::InvalidUnionOrdinal(ord as usize)),
172 }
173
174 Ok(())
175 }
176}
177
178impl<T, E> Encodable for FlexibleResult<T, E>
179where
180 T: Encodable,
181 E: Encodable,
182{
183 type Encoded = WireFlexibleResult<T::Encoded, E::Encoded>;
184}
185
186unsafe impl<Enc, T, E> Encode<Enc> for FlexibleResult<T, E>
187where
188 Enc: Encoder + ?Sized,
189 T: Encode<Enc>,
190 E: Encode<Enc>,
191{
192 fn encode(
193 self,
194 encoder: &mut Enc,
195 out: &mut MaybeUninit<Self::Encoded>,
196 ) -> Result<(), EncodeError> {
197 munge!(let WireFlexibleResult { raw, _phantom: _ } = out);
198
199 match self {
200 Self::Ok(value) => RawWireUnion::encode_as::<Enc, T>(value, ORD_OK, encoder, raw)?,
201 Self::Err(error) => RawWireUnion::encode_as::<Enc, E>(error, ORD_ERR, encoder, raw)?,
202 Self::FrameworkErr(error) => RawWireUnion::encode_as::<Enc, FrameworkError>(
203 error,
204 ORD_FRAMEWORK_ERR,
205 encoder,
206 raw,
207 )?,
208 }
209
210 Ok(())
211 }
212}
213
214unsafe impl<Enc, T, E> EncodeRef<Enc> for FlexibleResult<T, E>
215where
216 Enc: Encoder + ?Sized,
217 T: EncodeRef<Enc>,
218 E: EncodeRef<Enc>,
219{
220 fn encode_ref(
221 &self,
222 encoder: &mut Enc,
223 out: &mut MaybeUninit<Self::Encoded>,
224 ) -> Result<(), EncodeError> {
225 self.as_ref().encode(encoder, out)
226 }
227}
228
229impl<T, WT, E, WE> TakeFrom<WireFlexibleResult<WT, WE>> for FlexibleResult<T, E>
230where
231 T: TakeFrom<WT>,
232 E: TakeFrom<WE>,
233{
234 fn take_from(from: &WireFlexibleResult<WT, WE>) -> Self {
235 match from.as_ref() {
236 FlexibleResult::Ok(value) => Self::Ok(T::take_from(value)),
237 FlexibleResult::Err(error) => Self::Err(E::take_from(error)),
238 FlexibleResult::FrameworkErr(framework_error) => Self::FrameworkErr(framework_error),
239 }
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use fidl_next_codec::{chunks, WireI32};
246
247 use super::{FlexibleResult, WireFlexibleResult};
248 use crate::testing::{assert_decoded, assert_encoded};
249 use crate::FrameworkError;
250
251 #[test]
252 fn encode_flexible_result() {
253 assert_encoded(
254 FlexibleResult::<(), i32>::Ok(()),
255 &chunks![
256 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
257 0x01, 0x00,
258 ],
259 );
260 assert_encoded(
261 FlexibleResult::<(), i32>::Err(0x12345678),
262 &chunks![
263 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12, 0x00, 0x00,
264 0x01, 0x00,
265 ],
266 );
267 assert_encoded(
268 FlexibleResult::<(), i32>::FrameworkErr(FrameworkError::UnknownMethod),
269 &chunks![
270 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
271 0x01, 0x00,
272 ],
273 );
274 }
275
276 #[test]
277 fn decode_flexible_result() {
278 assert_decoded::<WireFlexibleResult<(), WireI32>>(
279 &mut chunks![
280 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 0x01, 0x00,
282 ],
283 |x| assert!(matches!(x.as_ref(), FlexibleResult::Ok(()))),
284 );
285 assert_decoded::<WireFlexibleResult<(), WireI32>>(
286 &mut chunks![
287 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12, 0x00, 0x00,
288 0x01, 0x00,
289 ],
290 |x| assert!(matches!(x.as_ref(), FlexibleResult::Err(WireI32(0x12345678)))),
291 );
292 assert_decoded::<WireFlexibleResult<(), WireI32>>(
293 &mut chunks![
294 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
295 0x01, 0x00,
296 ],
297 |x| {
298 assert!(matches!(
299 x.as_ref(),
300 FlexibleResult::FrameworkErr(FrameworkError::UnknownMethod)
301 ))
302 },
303 );
304 }
305}