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,
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<'de, T> {
38 raw: RawWireUnion,
39 _phantom: PhantomData<(&'de mut [Chunk], T)>,
40}
41
42unsafe impl<T: Wire> Wire for WireFlexible<'static, T> {
43 type Decoded<'de> = WireFlexible<'de, T::Decoded<'de>>;
44
45 #[inline]
46 fn zero_padding(out: &mut MaybeUninit<Self>) {
47 munge!(let Self { raw, _phantom: _ } = out);
48 RawWireUnion::zero_padding(raw);
49 }
50}
51
52const ORD_OK: u64 = 1;
53const ORD_FRAMEWORK_ERR: u64 = 3;
54
55impl<T> WireFlexible<'_, T> {
56 pub fn is_ok(&self) -> bool {
58 self.raw.ordinal() == ORD_OK
59 }
60
61 pub fn is_framework_err(&self) -> bool {
63 self.raw.ordinal() == ORD_FRAMEWORK_ERR
64 }
65
66 pub fn ok(&self) -> Option<&T> {
68 self.is_ok().then(|| unsafe { self.raw.get().deref_unchecked() })
69 }
70
71 pub fn framework_err(&self) -> Option<FrameworkError> {
73 self.is_framework_err()
74 .then(|| unsafe { (*self.raw.get().deref_unchecked::<WireFrameworkError>()).into() })
75 }
76
77 pub fn unwrap(&self) -> &T {
81 self.ok().unwrap()
82 }
83
84 pub fn unwrap_framework_err(&self) -> FrameworkError {
88 self.framework_err().unwrap()
89 }
90
91 pub fn as_ref(&self) -> Flexible<&T> {
93 match self.raw.ordinal() {
94 ORD_OK => unsafe { Flexible::Ok(self.raw.get().deref_unchecked()) },
95 ORD_FRAMEWORK_ERR => unsafe {
96 Flexible::FrameworkErr(
97 (*self.raw.get().deref_unchecked::<WireFrameworkError>()).into(),
98 )
99 },
100 _ => unsafe { ::core::hint::unreachable_unchecked() },
101 }
102 }
103
104 pub fn as_result(&self) -> Result<&T, FrameworkError> {
106 match self.raw.ordinal() {
107 ORD_OK => unsafe { Ok(self.raw.get().deref_unchecked()) },
108 ORD_FRAMEWORK_ERR => unsafe {
109 Err((*self.raw.get().deref_unchecked::<WireFrameworkError>()).into())
110 },
111 _ => unsafe { ::core::hint::unreachable_unchecked() },
112 }
113 }
114
115 pub fn to_flexible(self) -> Flexible<T> {
117 match self.raw.ordinal() {
118 ORD_OK => unsafe { Flexible::Ok(self.raw.get().read_unchecked()) },
119 ORD_FRAMEWORK_ERR => unsafe {
120 Flexible::FrameworkErr(self.raw.get().read_unchecked::<WireFrameworkError>().into())
121 },
122 _ => unsafe { ::core::hint::unreachable_unchecked() },
123 }
124 }
125}
126
127impl<T> fmt::Debug for WireFlexible<'_, T>
128where
129 T: fmt::Debug,
130{
131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 self.as_ref().fmt(f)
133 }
134}
135
136unsafe impl<D, T> Decode<D> for WireFlexible<'static, T>
137where
138 D: Decoder + ?Sized,
139 T: Decode<D>,
140{
141 fn decode(slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
142 munge!(let Self { mut raw, _phantom: _ } = slot);
143
144 match RawWireUnion::encoded_ordinal(raw.as_mut()) {
145 ORD_OK => RawWireUnion::decode_as::<D, T>(raw, decoder)?,
146 ORD_FRAMEWORK_ERR => RawWireUnion::decode_as::<D, WireFrameworkError>(raw, decoder)?,
147 ord => return Err(DecodeError::InvalidUnionOrdinal(ord as usize)),
148 }
149
150 Ok(())
151 }
152}
153
154impl<T> Encodable for Flexible<T>
155where
156 T: Encodable,
157{
158 type Encoded = WireFlexible<'static, T::Encoded>;
159}
160
161unsafe impl<E, T> Encode<E> for Flexible<T>
162where
163 E: Encoder + ?Sized,
164 T: Encode<E>,
165{
166 fn encode(
167 self,
168 encoder: &mut E,
169 out: &mut MaybeUninit<Self::Encoded>,
170 ) -> Result<(), EncodeError> {
171 munge!(let WireFlexible { raw, _phantom: _ } = out);
172
173 match self {
174 Self::Ok(value) => RawWireUnion::encode_as::<E, T>(value, ORD_OK, encoder, raw)?,
175 Self::FrameworkErr(error) => RawWireUnion::encode_as::<E, FrameworkError>(
176 error,
177 ORD_FRAMEWORK_ERR,
178 encoder,
179 raw,
180 )?,
181 }
182
183 Ok(())
184 }
185}
186
187unsafe impl<E, T> EncodeRef<E> for Flexible<T>
188where
189 E: Encoder + ?Sized,
190 T: EncodeRef<E>,
191{
192 fn encode_ref(
193 &self,
194 encoder: &mut E,
195 out: &mut MaybeUninit<Self::Encoded>,
196 ) -> Result<(), EncodeError> {
197 self.as_ref().encode(encoder, out)
198 }
199}
200
201impl<T, WT> FromWire<WireFlexible<'_, WT>> for Flexible<T>
202where
203 T: FromWire<WT>,
204{
205 fn from_wire(wire: WireFlexible<'_, WT>) -> Self {
206 match wire.to_flexible() {
207 Flexible::Ok(value) => Self::Ok(T::from_wire(value)),
208 Flexible::FrameworkErr(framework_error) => Self::FrameworkErr(framework_error),
209 }
210 }
211}
212
213impl<T, WT> FromWireRef<WireFlexible<'_, WT>> for Flexible<T>
214where
215 T: FromWireRef<WT>,
216{
217 fn from_wire_ref(wire: &WireFlexible<'_, WT>) -> Self {
218 match wire.as_ref() {
219 Flexible::Ok(value) => Self::Ok(T::from_wire_ref(value)),
220 Flexible::FrameworkErr(framework_error) => Self::FrameworkErr(framework_error),
221 }
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use fidl_next_codec::chunks;
228
229 use super::{Flexible, WireFlexible};
230 use crate::testing::{assert_decoded, assert_encoded};
231 use crate::FrameworkError;
232
233 #[test]
234 fn encode_flexible_result() {
235 assert_encoded(
236 Flexible::<()>::Ok(()),
237 &chunks![
238 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239 0x01, 0x00,
240 ],
241 );
242 assert_encoded(
243 Flexible::<()>::FrameworkErr(FrameworkError::UnknownMethod),
244 &chunks![
245 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
246 0x01, 0x00,
247 ],
248 );
249 }
250
251 #[test]
252 fn decode_flexible_result() {
253 assert_decoded::<WireFlexible<'_, ()>>(
254 &mut chunks![
255 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256 0x01, 0x00,
257 ],
258 |x| assert!(matches!(x.as_ref(), Flexible::Ok(()))),
259 );
260 assert_decoded::<WireFlexible<'_, ()>>(
261 &mut chunks![
262 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
263 0x01, 0x00,
264 ],
265 |x| {
266 assert!(matches!(x.as_ref(), Flexible::FrameworkErr(FrameworkError::UnknownMethod)))
267 },
268 );
269 }
270}