1use core::fmt;
6use core::marker::PhantomData;
7use core::mem::{ManuallyDrop, MaybeUninit};
8
9use fidl_next_codec::{
10 Chunk, Constrained, Decode, DecodeError, Decoder, Encode, EncodeError, Encoder, FromWire,
11 FromWireRef, IntoNatural, RawWireUnion, Slot, Unconstrained, Wire, WireResult, munge,
12};
13
14use crate::{FrameworkError, WireFrameworkError};
15
16#[derive(Clone, 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 is_ok(&self) -> bool {
30 matches!(self, Self::Ok(_))
31 }
32
33 pub fn is_err(&self) -> bool {
35 matches!(self, Self::Err(_))
36 }
37
38 pub fn is_framework_err(&self) -> bool {
40 matches!(self, Self::FrameworkErr(_))
41 }
42
43 pub fn ok(self) -> Option<T> {
45 if let Self::Ok(value) = self { Some(value) } else { None }
46 }
47
48 pub fn err(self) -> Option<E> {
50 if let Self::Err(error) = self { Some(error) } else { None }
51 }
52
53 pub fn framework_err(self) -> Option<FrameworkError> {
55 if let Self::FrameworkErr(error) = self { Some(error) } else { None }
56 }
57
58 pub fn unwrap(self) -> T {
62 self.ok().unwrap()
63 }
64
65 pub fn unwrap_err(self) -> E {
69 self.err().unwrap()
70 }
71
72 pub fn unwrap_framework_err(self) -> FrameworkError {
76 self.framework_err().unwrap()
77 }
78
79 pub fn as_ref(&self) -> FlexibleResult<&T, &E> {
81 match self {
82 Self::Ok(value) => FlexibleResult::Ok(value),
83 Self::Err(error) => FlexibleResult::Err(error),
84 Self::FrameworkErr(framework_error) => FlexibleResult::FrameworkErr(*framework_error),
85 }
86 }
87}
88
89#[repr(transparent)]
91pub struct WireFlexibleResult<'de, T, E> {
92 raw: RawWireUnion,
93 _phantom: PhantomData<(&'de mut [Chunk], T, E)>,
94}
95
96impl<T, E> Drop for WireFlexibleResult<'_, T, E> {
97 fn drop(&mut self) {
98 match self.raw.ordinal() {
99 ORD_OK => {
100 let _ = unsafe { self.raw.get().read_unchecked::<T>() };
101 }
102 ORD_ERR => {
103 let _ = unsafe { self.raw.get().read_unchecked::<E>() };
104 }
105 ORD_FRAMEWORK_ERR => {
106 let _ = unsafe { self.raw.get().read_unchecked::<WireFrameworkError>() };
107 }
108 _ => unsafe { ::core::hint::unreachable_unchecked() },
109 }
110 }
111}
112
113unsafe impl<T: Wire, E: Wire> Wire for WireFlexibleResult<'static, T, E> {
114 type Owned<'de> = WireFlexibleResult<'de, T::Owned<'de>, E::Owned<'de>>;
115
116 #[inline]
117 fn zero_padding(out: &mut MaybeUninit<Self>) {
118 munge!(let Self { raw, _phantom: _ } = out);
119 RawWireUnion::zero_padding(raw);
120 }
121}
122impl<T, E> Unconstrained for WireFlexibleResult<'_, T, E>
123where
124 T: Constrained<Constraint = ()>,
125 E: Constrained<Constraint = ()>,
126{
127}
128
129const ORD_OK: u64 = 1;
130const ORD_ERR: u64 = 2;
131const ORD_FRAMEWORK_ERR: u64 = 3;
132
133impl<'de, T, E> WireFlexibleResult<'de, T, E> {
134 pub fn is_ok(&self) -> bool {
136 self.raw.ordinal() == ORD_OK
137 }
138
139 pub fn is_err(&self) -> bool {
141 self.raw.ordinal() == ORD_ERR
142 }
143
144 pub fn is_framework_err(&self) -> bool {
146 self.raw.ordinal() == ORD_FRAMEWORK_ERR
147 }
148
149 pub fn ok(&self) -> Option<&T> {
151 self.is_ok().then(|| unsafe { self.raw.get().deref_unchecked() })
152 }
153
154 pub fn err(&self) -> Option<&E> {
156 self.is_err().then(|| unsafe { self.raw.get().deref_unchecked() })
157 }
158
159 pub fn framework_err(&self) -> Option<FrameworkError> {
161 self.is_framework_err()
162 .then(|| unsafe { (*self.raw.get().deref_unchecked::<WireFrameworkError>()).into() })
163 }
164
165 pub fn unwrap(&self) -> &T {
169 self.ok().unwrap()
170 }
171
172 pub fn unwrap_err(&self) -> &E {
176 self.err().unwrap()
177 }
178
179 pub fn unwrap_framework_err(&self) -> FrameworkError {
183 self.framework_err().unwrap()
184 }
185
186 pub fn as_ref(&self) -> FlexibleResult<&T, &E> {
188 match self.raw.ordinal() {
189 ORD_OK => unsafe { FlexibleResult::Ok(self.raw.get().deref_unchecked()) },
190 ORD_ERR => unsafe { FlexibleResult::Err(self.raw.get().deref_unchecked()) },
191 ORD_FRAMEWORK_ERR => unsafe {
192 FlexibleResult::FrameworkErr(
193 (*self.raw.get().deref_unchecked::<WireFrameworkError>()).into(),
194 )
195 },
196 _ => unsafe { ::core::hint::unreachable_unchecked() },
197 }
198 }
199
200 pub fn as_response(&self) -> Result<&WireResult<'_, T, E>, FrameworkError> {
202 match self.raw.ordinal() {
203 ORD_OK | ORD_ERR => unsafe {
204 Ok(&*(self as *const Self as *const WireResult<'_, T, E>))
205 },
206 ORD_FRAMEWORK_ERR => unsafe {
207 Err((*self.raw.get().deref_unchecked::<WireFrameworkError>()).into())
208 },
209 _ => unsafe { ::core::hint::unreachable_unchecked() },
210 }
211 }
212
213 pub fn as_result(&self) -> Result<Result<&T, &E>, FrameworkError> {
215 match self.raw.ordinal() {
216 ORD_OK => unsafe { Ok(Ok(self.raw.get().deref_unchecked())) },
217 ORD_ERR => unsafe { Ok(Err(self.raw.get().deref_unchecked())) },
218 ORD_FRAMEWORK_ERR => unsafe {
219 Err((*self.raw.get().deref_unchecked::<WireFrameworkError>()).into())
220 },
221 _ => unsafe { ::core::hint::unreachable_unchecked() },
222 }
223 }
224
225 pub fn to_flexible_result(self) -> FlexibleResult<T, E> {
227 let this = ManuallyDrop::new(self);
228 match this.raw.ordinal() {
229 ORD_OK => unsafe { FlexibleResult::Ok(this.raw.get().read_unchecked()) },
230 ORD_ERR => unsafe { FlexibleResult::Err(this.raw.get().read_unchecked()) },
231 ORD_FRAMEWORK_ERR => unsafe {
232 FlexibleResult::FrameworkErr(
233 this.raw.get().read_unchecked::<WireFrameworkError>().into(),
234 )
235 },
236 _ => unsafe { ::core::hint::unreachable_unchecked() },
237 }
238 }
239}
240
241impl<T: Clone, E: Clone> Clone for WireFlexibleResult<'_, T, E> {
242 fn clone(&self) -> Self {
243 Self {
244 raw: match self.raw.ordinal() {
245 ORD_OK => unsafe { self.raw.clone_inline_unchecked::<T>() },
246 ORD_ERR => unsafe { self.raw.clone_inline_unchecked::<E>() },
247 ORD_FRAMEWORK_ERR => unsafe {
248 self.raw.clone_inline_unchecked::<WireFrameworkError>()
249 },
250 _ => unsafe { ::core::hint::unreachable_unchecked() },
251 },
252 _phantom: PhantomData,
253 }
254 }
255}
256
257impl<T, E> fmt::Debug for WireFlexibleResult<'_, T, E>
258where
259 T: fmt::Debug,
260 E: fmt::Debug,
261{
262 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
263 self.as_ref().fmt(f)
264 }
265}
266
267unsafe impl<D, T, E> Decode<D> for WireFlexibleResult<'static, T, E>
268where
269 D: Decoder + ?Sized,
270 T: Decode<D> + Constrained<Constraint = ()>,
271 E: Decode<D> + Constrained<Constraint = ()>,
272{
273 fn decode(slot: Slot<'_, Self>, decoder: &mut D, _: ()) -> Result<(), DecodeError> {
274 munge!(let Self { mut raw, _phantom: _ } = slot);
275
276 match RawWireUnion::encoded_ordinal(raw.as_mut()) {
277 ORD_OK => RawWireUnion::decode_as::<D, T>(raw, decoder, ())?,
278 ORD_ERR => RawWireUnion::decode_as::<D, E>(raw, decoder, ())?,
279 ORD_FRAMEWORK_ERR => {
280 RawWireUnion::decode_as::<D, WireFrameworkError>(raw, decoder, ())?
281 }
282 ord => return Err(DecodeError::InvalidUnionOrdinal(ord as usize)),
283 }
284
285 Ok(())
286 }
287}
288
289unsafe impl<Enc, WT, T, WE, E> Encode<WireFlexibleResult<'static, WT, WE>, Enc>
290 for FlexibleResult<T, E>
291where
292 Enc: Encoder + ?Sized,
293 WT: Constrained<Constraint = ()> + Wire,
294 T: Encode<WT, Enc>,
295 WE: Constrained<Constraint = ()> + Wire,
296 E: Encode<WE, Enc>,
297{
298 fn encode(
299 self,
300 encoder: &mut Enc,
301 out: &mut MaybeUninit<WireFlexibleResult<'static, WT, WE>>,
302 _: (),
303 ) -> Result<(), EncodeError> {
304 munge!(let WireFlexibleResult { raw, _phantom: _ } = out);
305
306 match self {
307 Self::Ok(value) => RawWireUnion::encode_as::<Enc, WT>(value, ORD_OK, encoder, raw, ())?,
308 Self::Err(error) => {
309 RawWireUnion::encode_as::<Enc, WE>(error, ORD_ERR, encoder, raw, ())?
310 }
311 Self::FrameworkErr(error) => RawWireUnion::encode_as::<Enc, WireFrameworkError>(
312 error,
313 ORD_FRAMEWORK_ERR,
314 encoder,
315 raw,
316 (),
317 )?,
318 }
319
320 Ok(())
321 }
322}
323
324unsafe impl<'a, Enc, WT, T, WE, E> Encode<WireFlexibleResult<'static, WT, WE>, Enc>
325 for &'a FlexibleResult<T, E>
326where
327 Enc: Encoder + ?Sized,
328 WT: Constrained<Constraint = ()> + Wire,
329 &'a T: Encode<WT, Enc>,
330 WE: Constrained<Constraint = ()> + Wire,
331 &'a E: Encode<WE, Enc>,
332{
333 fn encode(
334 self,
335 encoder: &mut Enc,
336 out: &mut MaybeUninit<WireFlexibleResult<'static, WT, WE>>,
337 _: (),
338 ) -> Result<(), EncodeError> {
339 self.as_ref().encode(encoder, out, ())
340 }
341}
342
343impl<T, WT, E, WE> FromWire<WireFlexibleResult<'_, WT, WE>> for FlexibleResult<T, E>
344where
345 T: FromWire<WT>,
346 E: FromWire<WE>,
347{
348 fn from_wire(wire: WireFlexibleResult<'_, WT, WE>) -> Self {
349 match wire.to_flexible_result() {
350 FlexibleResult::Ok(value) => Self::Ok(T::from_wire(value)),
351 FlexibleResult::Err(error) => Self::Err(E::from_wire(error)),
352 FlexibleResult::FrameworkErr(framework_error) => Self::FrameworkErr(framework_error),
353 }
354 }
355}
356
357impl<T: IntoNatural, E: IntoNatural> IntoNatural for WireFlexibleResult<'_, T, E> {
358 type Natural = FlexibleResult<T::Natural, E::Natural>;
359}
360
361impl<T, WT, E, WE> FromWireRef<WireFlexibleResult<'_, WT, WE>> for FlexibleResult<T, E>
362where
363 T: FromWireRef<WT>,
364 E: FromWireRef<WE>,
365{
366 fn from_wire_ref(wire: &WireFlexibleResult<'_, WT, WE>) -> Self {
367 match wire.as_ref() {
368 FlexibleResult::Ok(value) => Self::Ok(T::from_wire_ref(value)),
369 FlexibleResult::Err(error) => Self::Err(E::from_wire_ref(error)),
370 FlexibleResult::FrameworkErr(framework_error) => Self::FrameworkErr(framework_error),
371 }
372 }
373}
374
375#[cfg(test)]
376mod tests {
377 use fidl_next_codec::{WireI32, chunks};
378
379 use super::{FlexibleResult, WireFlexibleResult};
380 use crate::FrameworkError;
381 use crate::testing::{assert_decoded, assert_encoded};
382
383 #[test]
384 fn encode_flexible_result() {
385 assert_encoded(
386 FlexibleResult::<(), i32>::Ok(()),
387 &chunks![
388 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
389 0x01, 0x00,
390 ],
391 );
392 assert_encoded(
393 FlexibleResult::<(), i32>::Err(0x12345678),
394 &chunks![
395 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12, 0x00, 0x00,
396 0x01, 0x00,
397 ],
398 );
399 assert_encoded(
400 FlexibleResult::<(), i32>::FrameworkErr(FrameworkError::UnknownMethod),
401 &chunks![
402 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
403 0x01, 0x00,
404 ],
405 );
406 }
407
408 #[test]
409 fn decode_flexible_result() {
410 assert_decoded::<WireFlexibleResult<'_, (), WireI32>>(
411 &mut chunks![
412 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
413 0x01, 0x00,
414 ],
415 |x| assert!(matches!(x.as_ref(), FlexibleResult::Ok(()))),
416 );
417 assert_decoded::<WireFlexibleResult<'_, (), WireI32>>(
418 &mut chunks![
419 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12, 0x00, 0x00,
420 0x01, 0x00,
421 ],
422 |x| assert!(matches!(x.as_ref(), FlexibleResult::Err(WireI32(0x12345678)))),
423 );
424 assert_decoded::<WireFlexibleResult<'_, (), WireI32>>(
425 &mut chunks![
426 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
427 0x01, 0x00,
428 ],
429 |x| {
430 assert!(matches!(
431 x.as_ref(),
432 FlexibleResult::FrameworkErr(FrameworkError::UnknownMethod)
433 ))
434 },
435 );
436 }
437}