1use core::fmt;
6use core::marker::PhantomData;
7use core::mem::MaybeUninit;
8
9use fidl_next_codec::{
10 munge, Decode, DecodeError, Decoder, Encodable, Encode, EncodeError, EncodeRef, Encoder,
11 RawWireUnion, Slot, TakeFrom, ZeroPadding,
12};
13
14use crate::{FrameworkError, WireFrameworkError};
15
16#[derive(Debug)]
18pub enum Flexible<T> {
19 Ok(T),
21 FrameworkErr(FrameworkError),
23}
24
25impl<T> Flexible<T> {
26 pub fn as_ref(&self) -> Flexible<&T> {
28 match self {
29 Self::Ok(value) => Flexible::Ok(value),
30 Self::FrameworkErr(framework_error) => Flexible::FrameworkErr(*framework_error),
31 }
32 }
33}
34
35#[repr(transparent)]
37pub struct WireFlexible<T> {
38 raw: RawWireUnion,
39 _phantom: PhantomData<T>,
40}
41
42unsafe impl<T> ZeroPadding for WireFlexible<T> {
43 #[inline]
44 fn zero_padding(out: &mut MaybeUninit<Self>) {
45 munge!(let Self { raw, _phantom: _ } = out);
46 RawWireUnion::zero_padding(raw);
47 }
48}
49
50const ORD_OK: u64 = 1;
51const ORD_FRAMEWORK_ERR: u64 = 3;
52
53impl<T> WireFlexible<T> {
54 pub fn is_ok(&self) -> bool {
56 self.raw.ordinal() == ORD_OK
57 }
58
59 pub fn is_framework_err(&self) -> bool {
61 self.raw.ordinal() == ORD_FRAMEWORK_ERR
62 }
63
64 pub fn ok(&self) -> Option<&T> {
66 self.is_ok().then(|| unsafe { self.raw.get().deref_unchecked() })
67 }
68
69 pub fn framework_err(&self) -> Option<FrameworkError> {
71 self.is_framework_err()
72 .then(|| unsafe { (*self.raw.get().deref_unchecked::<WireFrameworkError>()).into() })
73 }
74
75 pub fn unwrap(&self) -> &T {
79 self.ok().unwrap()
80 }
81
82 pub fn unwrap_framework_err(&self) -> FrameworkError {
86 self.framework_err().unwrap()
87 }
88
89 pub fn as_ref(&self) -> Flexible<&T> {
91 match self.raw.ordinal() {
92 ORD_OK => unsafe { Flexible::Ok(self.raw.get().deref_unchecked()) },
93 ORD_FRAMEWORK_ERR => unsafe {
94 Flexible::FrameworkErr(
95 (*self.raw.get().deref_unchecked::<WireFrameworkError>()).into(),
96 )
97 },
98 _ => unsafe { ::core::hint::unreachable_unchecked() },
99 }
100 }
101
102 pub fn as_result(&self) -> Result<&T, FrameworkError> {
104 match self.raw.ordinal() {
105 ORD_OK => unsafe { Ok(self.raw.get().deref_unchecked()) },
106 ORD_FRAMEWORK_ERR => unsafe {
107 Err((*self.raw.get().deref_unchecked::<WireFrameworkError>()).into())
108 },
109 _ => unsafe { ::core::hint::unreachable_unchecked() },
110 }
111 }
112}
113
114impl<T> fmt::Debug for WireFlexible<T>
115where
116 T: fmt::Debug,
117{
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 self.as_ref().fmt(f)
120 }
121}
122
123unsafe impl<D, T> Decode<D> for WireFlexible<T>
124where
125 D: Decoder + ?Sized,
126 T: Decode<D>,
127{
128 fn decode(slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
129 munge!(let Self { mut raw, _phantom: _ } = slot);
130
131 match RawWireUnion::encoded_ordinal(raw.as_mut()) {
132 ORD_OK => RawWireUnion::decode_as::<D, T>(raw, decoder)?,
133 ORD_FRAMEWORK_ERR => RawWireUnion::decode_as::<D, WireFrameworkError>(raw, decoder)?,
134 ord => return Err(DecodeError::InvalidUnionOrdinal(ord as usize)),
135 }
136
137 Ok(())
138 }
139}
140
141impl<T> Encodable for Flexible<T>
142where
143 T: Encodable,
144{
145 type Encoded = WireFlexible<T::Encoded>;
146}
147
148unsafe impl<E, T> Encode<E> for Flexible<T>
149where
150 E: Encoder + ?Sized,
151 T: Encode<E>,
152{
153 fn encode(
154 self,
155 encoder: &mut E,
156 out: &mut MaybeUninit<Self::Encoded>,
157 ) -> Result<(), EncodeError> {
158 munge!(let WireFlexible { raw, _phantom: _ } = out);
159
160 match self {
161 Self::Ok(value) => RawWireUnion::encode_as::<E, T>(value, ORD_OK, encoder, raw)?,
162 Self::FrameworkErr(error) => RawWireUnion::encode_as::<E, FrameworkError>(
163 error,
164 ORD_FRAMEWORK_ERR,
165 encoder,
166 raw,
167 )?,
168 }
169
170 Ok(())
171 }
172}
173
174unsafe impl<E, T> EncodeRef<E> for Flexible<T>
175where
176 E: Encoder + ?Sized,
177 T: EncodeRef<E>,
178{
179 fn encode_ref(
180 &self,
181 encoder: &mut E,
182 out: &mut MaybeUninit<Self::Encoded>,
183 ) -> Result<(), EncodeError> {
184 self.as_ref().encode(encoder, out)
185 }
186}
187
188impl<T, WT> TakeFrom<WireFlexible<WT>> for Flexible<T>
189where
190 T: TakeFrom<WT>,
191{
192 fn take_from(from: &WireFlexible<WT>) -> Self {
193 match from.as_ref() {
194 Flexible::Ok(value) => Self::Ok(T::take_from(value)),
195 Flexible::FrameworkErr(framework_error) => Self::FrameworkErr(framework_error),
196 }
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use fidl_next_codec::chunks;
203
204 use super::{Flexible, WireFlexible};
205 use crate::testing::{assert_decoded, assert_encoded};
206 use crate::FrameworkError;
207
208 #[test]
209 fn encode_flexible_result() {
210 assert_encoded(
211 Flexible::<()>::Ok(()),
212 &chunks![
213 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214 0x01, 0x00,
215 ],
216 );
217 assert_encoded(
218 Flexible::<()>::FrameworkErr(FrameworkError::UnknownMethod),
219 &chunks![
220 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
221 0x01, 0x00,
222 ],
223 );
224 }
225
226 #[test]
227 fn decode_flexible_result() {
228 assert_decoded::<WireFlexible<()>>(
229 &mut chunks![
230 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x01, 0x00,
232 ],
233 |x| assert!(matches!(x.as_ref(), Flexible::Ok(()))),
234 );
235 assert_decoded::<WireFlexible<()>>(
236 &mut chunks![
237 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
238 0x01, 0x00,
239 ],
240 |x| {
241 assert!(matches!(x.as_ref(), Flexible::FrameworkErr(FrameworkError::UnknownMethod)))
242 },
243 );
244 }
245}