1use core::fmt;
6use core::marker::PhantomData;
7use core::mem::{ManuallyDrop, MaybeUninit};
8
9use fidl_next_codec::{
10 munge, Chunk, Decode, DecodeError, Decoder, Encodable, Encode, EncodeError, EncodeRef, Encoder,
11 FromWire, FromWireRef, RawWireUnion, Slot, Wire, WireResult,
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 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<'de, T, E> {
41 raw: RawWireUnion,
42 _phantom: PhantomData<(&'de mut [Chunk], T, E)>,
43}
44
45impl<T, E> Drop for WireFlexibleResult<'_, T, E> {
46 fn drop(&mut self) {
47 match self.raw.ordinal() {
48 ORD_OK => {
49 let _ = unsafe { self.raw.get().read_unchecked::<T>() };
50 }
51 ORD_ERR => {
52 let _ = unsafe { self.raw.get().read_unchecked::<E>() };
53 }
54 ORD_FRAMEWORK_ERR => {
55 let _ = unsafe { self.raw.get().read_unchecked::<WireFrameworkError>() };
56 }
57 _ => unsafe { ::core::hint::unreachable_unchecked() },
58 }
59 }
60}
61
62unsafe impl<T: Wire, E: Wire> Wire for WireFlexibleResult<'static, T, E> {
63 type Decoded<'de> = WireFlexibleResult<'de, T::Decoded<'de>, E::Decoded<'de>>;
64
65 #[inline]
66 fn zero_padding(out: &mut MaybeUninit<Self>) {
67 munge!(let Self { raw, _phantom: _ } = out);
68 RawWireUnion::zero_padding(raw);
69 }
70}
71
72const ORD_OK: u64 = 1;
73const ORD_ERR: u64 = 2;
74const ORD_FRAMEWORK_ERR: u64 = 3;
75
76impl<'de, T, E> WireFlexibleResult<'de, T, E> {
77 pub fn is_ok(&self) -> bool {
79 self.raw.ordinal() == ORD_OK
80 }
81
82 pub fn is_err(&self) -> bool {
84 self.raw.ordinal() == ORD_ERR
85 }
86
87 pub fn is_framework_err(&self) -> bool {
89 self.raw.ordinal() == ORD_FRAMEWORK_ERR
90 }
91
92 pub fn ok(&self) -> Option<&T> {
94 self.is_ok().then(|| unsafe { self.raw.get().deref_unchecked() })
95 }
96
97 pub fn err(&self) -> Option<&E> {
99 self.is_err().then(|| unsafe { self.raw.get().deref_unchecked() })
100 }
101
102 pub fn framework_err(&self) -> Option<FrameworkError> {
104 self.is_framework_err()
105 .then(|| unsafe { (*self.raw.get().deref_unchecked::<WireFrameworkError>()).into() })
106 }
107
108 pub fn unwrap(&self) -> &T {
112 self.ok().unwrap()
113 }
114
115 pub fn unwrap_err(&self) -> &E {
119 self.err().unwrap()
120 }
121
122 pub fn unwrap_framework_err(&self) -> FrameworkError {
126 self.framework_err().unwrap()
127 }
128
129 pub fn as_ref(&self) -> FlexibleResult<&T, &E> {
131 match self.raw.ordinal() {
132 ORD_OK => unsafe { FlexibleResult::Ok(self.raw.get().deref_unchecked()) },
133 ORD_ERR => unsafe { FlexibleResult::Err(self.raw.get().deref_unchecked()) },
134 ORD_FRAMEWORK_ERR => unsafe {
135 FlexibleResult::FrameworkErr(
136 (*self.raw.get().deref_unchecked::<WireFrameworkError>()).into(),
137 )
138 },
139 _ => unsafe { ::core::hint::unreachable_unchecked() },
140 }
141 }
142
143 pub fn as_response(&self) -> Result<&WireResult<'_, T, E>, FrameworkError> {
145 match self.raw.ordinal() {
146 ORD_OK | ORD_ERR => unsafe {
147 Ok(&*(self as *const Self as *const WireResult<'_, T, E>))
148 },
149 ORD_FRAMEWORK_ERR => unsafe {
150 Err((*self.raw.get().deref_unchecked::<WireFrameworkError>()).into())
151 },
152 _ => unsafe { ::core::hint::unreachable_unchecked() },
153 }
154 }
155
156 pub fn as_result(&self) -> Result<Result<&T, &E>, FrameworkError> {
158 match self.raw.ordinal() {
159 ORD_OK => unsafe { Ok(Ok(self.raw.get().deref_unchecked())) },
160 ORD_ERR => unsafe { Ok(Err(self.raw.get().deref_unchecked())) },
161 ORD_FRAMEWORK_ERR => unsafe {
162 Err((*self.raw.get().deref_unchecked::<WireFrameworkError>()).into())
163 },
164 _ => unsafe { ::core::hint::unreachable_unchecked() },
165 }
166 }
167
168 pub fn to_flexible_result(self) -> FlexibleResult<T, E> {
170 let this = ManuallyDrop::new(self);
171 match this.raw.ordinal() {
172 ORD_OK => unsafe { FlexibleResult::Ok(this.raw.get().read_unchecked()) },
173 ORD_ERR => unsafe { FlexibleResult::Err(this.raw.get().read_unchecked()) },
174 ORD_FRAMEWORK_ERR => unsafe {
175 FlexibleResult::FrameworkErr(
176 this.raw.get().read_unchecked::<WireFrameworkError>().into(),
177 )
178 },
179 _ => unsafe { ::core::hint::unreachable_unchecked() },
180 }
181 }
182}
183
184impl<T: Clone, E: Clone> Clone for WireFlexibleResult<'_, T, E> {
185 fn clone(&self) -> Self {
186 Self {
187 raw: match self.raw.ordinal() {
188 ORD_OK => unsafe { self.raw.clone_inline_unchecked::<T>() },
189 ORD_ERR => unsafe { self.raw.clone_inline_unchecked::<E>() },
190 ORD_FRAMEWORK_ERR => unsafe {
191 self.raw.clone_inline_unchecked::<WireFrameworkError>()
192 },
193 _ => unsafe { ::core::hint::unreachable_unchecked() },
194 },
195 _phantom: PhantomData,
196 }
197 }
198}
199
200impl<T, E> fmt::Debug for WireFlexibleResult<'_, T, E>
201where
202 T: fmt::Debug,
203 E: fmt::Debug,
204{
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 self.as_ref().fmt(f)
207 }
208}
209
210unsafe impl<D, T, E> Decode<D> for WireFlexibleResult<'static, T, E>
211where
212 D: Decoder + ?Sized,
213 T: Decode<D>,
214 E: Decode<D>,
215{
216 fn decode(slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
217 munge!(let Self { mut raw, _phantom: _ } = slot);
218
219 match RawWireUnion::encoded_ordinal(raw.as_mut()) {
220 ORD_OK => RawWireUnion::decode_as::<D, T>(raw, decoder)?,
221 ORD_ERR => RawWireUnion::decode_as::<D, E>(raw, decoder)?,
222 ORD_FRAMEWORK_ERR => RawWireUnion::decode_as::<D, WireFrameworkError>(raw, decoder)?,
223 ord => return Err(DecodeError::InvalidUnionOrdinal(ord as usize)),
224 }
225
226 Ok(())
227 }
228}
229
230impl<T, E> Encodable for FlexibleResult<T, E>
231where
232 T: Encodable,
233 E: Encodable,
234{
235 type Encoded = WireFlexibleResult<'static, T::Encoded, E::Encoded>;
236}
237
238unsafe impl<Enc, T, E> Encode<Enc> for FlexibleResult<T, E>
239where
240 Enc: Encoder + ?Sized,
241 T: Encode<Enc>,
242 E: Encode<Enc>,
243{
244 fn encode(
245 self,
246 encoder: &mut Enc,
247 out: &mut MaybeUninit<Self::Encoded>,
248 ) -> Result<(), EncodeError> {
249 munge!(let WireFlexibleResult { raw, _phantom: _ } = out);
250
251 match self {
252 Self::Ok(value) => RawWireUnion::encode_as::<Enc, T>(value, ORD_OK, encoder, raw)?,
253 Self::Err(error) => RawWireUnion::encode_as::<Enc, E>(error, ORD_ERR, encoder, raw)?,
254 Self::FrameworkErr(error) => RawWireUnion::encode_as::<Enc, FrameworkError>(
255 error,
256 ORD_FRAMEWORK_ERR,
257 encoder,
258 raw,
259 )?,
260 }
261
262 Ok(())
263 }
264}
265
266unsafe impl<Enc, T, E> EncodeRef<Enc> for FlexibleResult<T, E>
267where
268 Enc: Encoder + ?Sized,
269 T: EncodeRef<Enc>,
270 E: EncodeRef<Enc>,
271{
272 fn encode_ref(
273 &self,
274 encoder: &mut Enc,
275 out: &mut MaybeUninit<Self::Encoded>,
276 ) -> Result<(), EncodeError> {
277 self.as_ref().encode(encoder, out)
278 }
279}
280
281impl<T, WT, E, WE> FromWire<WireFlexibleResult<'_, WT, WE>> for FlexibleResult<T, E>
282where
283 T: FromWire<WT>,
284 E: FromWire<WE>,
285{
286 fn from_wire(wire: WireFlexibleResult<'_, WT, WE>) -> Self {
287 match wire.to_flexible_result() {
288 FlexibleResult::Ok(value) => Self::Ok(T::from_wire(value)),
289 FlexibleResult::Err(error) => Self::Err(E::from_wire(error)),
290 FlexibleResult::FrameworkErr(framework_error) => Self::FrameworkErr(framework_error),
291 }
292 }
293}
294
295impl<T, WT, E, WE> FromWireRef<WireFlexibleResult<'_, WT, WE>> for FlexibleResult<T, E>
296where
297 T: FromWireRef<WT>,
298 E: FromWireRef<WE>,
299{
300 fn from_wire_ref(wire: &WireFlexibleResult<'_, WT, WE>) -> Self {
301 match wire.as_ref() {
302 FlexibleResult::Ok(value) => Self::Ok(T::from_wire_ref(value)),
303 FlexibleResult::Err(error) => Self::Err(E::from_wire_ref(error)),
304 FlexibleResult::FrameworkErr(framework_error) => Self::FrameworkErr(framework_error),
305 }
306 }
307}
308
309#[cfg(test)]
310mod tests {
311 use fidl_next_codec::{chunks, WireI32};
312
313 use super::{FlexibleResult, WireFlexibleResult};
314 use crate::testing::{assert_decoded, assert_encoded};
315 use crate::FrameworkError;
316
317 #[test]
318 fn encode_flexible_result() {
319 assert_encoded(
320 FlexibleResult::<(), i32>::Ok(()),
321 &chunks![
322 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323 0x01, 0x00,
324 ],
325 );
326 assert_encoded(
327 FlexibleResult::<(), i32>::Err(0x12345678),
328 &chunks![
329 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12, 0x00, 0x00,
330 0x01, 0x00,
331 ],
332 );
333 assert_encoded(
334 FlexibleResult::<(), i32>::FrameworkErr(FrameworkError::UnknownMethod),
335 &chunks![
336 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
337 0x01, 0x00,
338 ],
339 );
340 }
341
342 #[test]
343 fn decode_flexible_result() {
344 assert_decoded::<WireFlexibleResult<'_, (), WireI32>>(
345 &mut chunks![
346 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 0x01, 0x00,
348 ],
349 |x| assert!(matches!(x.as_ref(), FlexibleResult::Ok(()))),
350 );
351 assert_decoded::<WireFlexibleResult<'_, (), WireI32>>(
352 &mut chunks![
353 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12, 0x00, 0x00,
354 0x01, 0x00,
355 ],
356 |x| assert!(matches!(x.as_ref(), FlexibleResult::Err(WireI32(0x12345678)))),
357 );
358 assert_decoded::<WireFlexibleResult<'_, (), WireI32>>(
359 &mut chunks![
360 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
361 0x01, 0x00,
362 ],
363 |x| {
364 assert!(matches!(
365 x.as_ref(),
366 FlexibleResult::FrameworkErr(FrameworkError::UnknownMethod)
367 ))
368 },
369 );
370 }
371}