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