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