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