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 Flexible<'de, T> {
19 raw: wire::Union,
20 _phantom: PhantomData<(&'de mut [Chunk], T)>,
21}
22
23impl<T> Drop for Flexible<'_, T> {
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_FRAMEWORK_ERR => {
30 let _ = unsafe { self.raw.get().read_unchecked::<wire::FrameworkError>() };
31 }
32 _ => unsafe { ::core::hint::unreachable_unchecked() },
33 }
34 }
35}
36
37impl<T: Constrained<Constraint = ()>> Constrained for Flexible<'_, T> {
38 type Constraint = ();
39
40 fn validate(_: Slot<'_, Self>, _: Self::Constraint) -> Result<(), ValidationError> {
41 Ok(())
42 }
43}
44
45unsafe impl<T> Wire for Flexible<'static, T>
46where
47 T: Wire<Constraint = ()>,
48{
49 type Narrowed<'de> = Flexible<'de, T::Narrowed<'de>>;
50
51 #[inline]
52 fn zero_padding(out: &mut MaybeUninit<Self>) {
53 munge!(let Self { raw, _phantom: _ } = out);
54 wire::Union::zero_padding(raw);
55 }
56}
57
58const ORD_OK: u64 = 1;
59const ORD_FRAMEWORK_ERR: u64 = 3;
60
61impl<T> Flexible<'_, T> {
62 pub fn is_ok(&self) -> bool {
64 self.raw.ordinal() == ORD_OK
65 }
66
67 pub fn is_framework_err(&self) -> bool {
69 self.raw.ordinal() == ORD_FRAMEWORK_ERR
70 }
71
72 pub fn ok(&self) -> Option<&T> {
74 self.is_ok().then(|| unsafe { self.raw.get().deref_unchecked() })
75 }
76
77 pub fn framework_err(&self) -> Option<crate::FrameworkError> {
79 self.is_framework_err()
80 .then(|| unsafe { (*self.raw.get().deref_unchecked::<wire::FrameworkError>()).into() })
81 }
82
83 pub fn unwrap(&self) -> &T {
87 self.ok().unwrap()
88 }
89
90 pub fn unwrap_framework_err(&self) -> crate::FrameworkError {
94 self.framework_err().unwrap()
95 }
96
97 pub fn as_ref(&self) -> crate::Flexible<&T> {
99 match self.raw.ordinal() {
100 ORD_OK => unsafe { crate::Flexible::Ok(self.raw.get().deref_unchecked()) },
101 ORD_FRAMEWORK_ERR => unsafe {
102 crate::Flexible::FrameworkErr(
103 (*self.raw.get().deref_unchecked::<wire::FrameworkError>()).into(),
104 )
105 },
106 _ => unsafe { ::core::hint::unreachable_unchecked() },
107 }
108 }
109
110 pub fn as_result(&self) -> Result<&T, crate::FrameworkError> {
112 match self.raw.ordinal() {
113 ORD_OK => unsafe { Ok(self.raw.get().deref_unchecked()) },
114 ORD_FRAMEWORK_ERR => unsafe {
115 Err((*self.raw.get().deref_unchecked::<wire::FrameworkError>()).into())
116 },
117 _ => unsafe { ::core::hint::unreachable_unchecked() },
118 }
119 }
120
121 pub fn to_flexible(self) -> crate::Flexible<T> {
123 let this = ManuallyDrop::new(self);
124 match this.raw.ordinal() {
125 ORD_OK => unsafe { crate::Flexible::Ok(this.raw.get().read_unchecked()) },
126 ORD_FRAMEWORK_ERR => unsafe {
127 crate::Flexible::FrameworkErr(
128 this.raw.get().read_unchecked::<wire::FrameworkError>().into(),
129 )
130 },
131 _ => unsafe { ::core::hint::unreachable_unchecked() },
132 }
133 }
134}
135
136impl<T: Clone> Clone for Flexible<'_, T> {
137 fn clone(&self) -> Self {
138 Self {
139 raw: match self.raw.ordinal() {
140 ORD_OK => unsafe { self.raw.clone_inline_unchecked::<T>() },
141 ORD_FRAMEWORK_ERR => unsafe {
142 self.raw.clone_inline_unchecked::<wire::FrameworkError>()
143 },
144 _ => unsafe { ::core::hint::unreachable_unchecked() },
145 },
146 _phantom: PhantomData,
147 }
148 }
149}
150
151impl<T> fmt::Debug for Flexible<'_, T>
152where
153 T: fmt::Debug,
154{
155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156 self.as_ref().fmt(f)
157 }
158}
159
160unsafe impl<'de, D, T> Decode<D> for Flexible<'de, T>
161where
162 D: Decoder<'de> + ?Sized,
163 T: Decode<D, Constraint = ()>,
164{
165 fn decode(
166 slot: Slot<'_, Self>,
167 decoder: &mut D,
168 constraint: Self::Constraint,
169 ) -> Result<(), DecodeError> {
170 munge!(let Self { mut raw, _phantom: _ } = slot);
171
172 match wire::Union::encoded_ordinal(raw.as_mut()) {
173 ORD_OK => wire::Union::decode_as::<D, T>(raw, decoder, constraint)?,
174 ORD_FRAMEWORK_ERR => {
175 wire::Union::decode_as::<D, wire::FrameworkError>(raw, decoder, ())?
176 }
177 ord => return Err(DecodeError::InvalidUnionOrdinal(ord as usize)),
178 }
179
180 Ok(())
181 }
182}
183
184unsafe impl<E, WT, T> Encode<Flexible<'static, WT>, E> for crate::Flexible<T>
185where
186 E: Encoder + ?Sized,
187 WT: Wire<Constraint = ()>,
188 T: Encode<WT, E>,
189{
190 fn encode(
191 self,
192 encoder: &mut E,
193 out: &mut MaybeUninit<Flexible<'static, WT>>,
194 constraint: WT::Constraint,
195 ) -> Result<(), EncodeError> {
196 munge!(let Flexible { raw, _phantom: _ } = out);
197
198 match self {
199 Self::Ok(value) => {
200 wire::Union::encode_as::<E, WT>(value, ORD_OK, encoder, raw, constraint)?
201 }
202 Self::FrameworkErr(error) => wire::Union::encode_as::<E, wire::FrameworkError>(
203 error,
204 ORD_FRAMEWORK_ERR,
205 encoder,
206 raw,
207 (),
208 )?,
209 }
210
211 Ok(())
212 }
213}
214
215unsafe impl<'a, E, WT, T> Encode<Flexible<'static, WT>, E> for &'a crate::Flexible<T>
216where
217 E: Encoder + ?Sized,
218 WT: Wire<Constraint = ()>,
219 &'a T: Encode<WT, E>,
220{
221 fn encode(
222 self,
223 encoder: &mut E,
224 out: &mut MaybeUninit<Flexible<'static, WT>>,
225 constraint: WT::Constraint,
226 ) -> Result<(), EncodeError> {
227 self.as_ref().encode(encoder, out, constraint)
228 }
229}
230
231impl<T, WT> FromWire<Flexible<'_, WT>> for crate::Flexible<T>
232where
233 T: FromWire<WT>,
234{
235 fn from_wire(wire: Flexible<'_, WT>) -> Self {
236 match wire.to_flexible() {
237 crate::Flexible::Ok(value) => Self::Ok(T::from_wire(value)),
238 crate::Flexible::FrameworkErr(framework_error) => Self::FrameworkErr(framework_error),
239 }
240 }
241}
242
243impl<T: IntoNatural> IntoNatural for Flexible<'_, T> {
244 type Natural = crate::Flexible<T::Natural>;
245}
246
247impl<T, WT> FromWireRef<Flexible<'_, WT>> for crate::Flexible<T>
248where
249 T: FromWireRef<WT>,
250{
251 fn from_wire_ref(wire: &Flexible<'_, WT>) -> Self {
252 match wire.as_ref() {
253 crate::Flexible::Ok(value) => Self::Ok(T::from_wire_ref(value)),
254 crate::Flexible::FrameworkErr(framework_error) => Self::FrameworkErr(framework_error),
255 }
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use fidl_next_codec::{DecoderExt as _, EncoderExt, chunks};
262
263 use crate::wire;
264
265 #[test]
266 fn encode_flexible_result() {
267 assert_eq!(
268 Vec::encode(crate::Flexible::<()>::Ok(())).unwrap(),
269 chunks![
270 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
271 0x01, 0x00,
272 ],
273 );
274 assert_eq!(
275 Vec::encode(crate::Flexible::<()>::FrameworkErr(crate::FrameworkError::UnknownMethod))
276 .unwrap(),
277 chunks![
278 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
279 0x01, 0x00,
280 ],
281 );
282 }
283
284 #[test]
285 fn decode_flexible_result() {
286 assert_eq!(
287 chunks![
288 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 0x01, 0x00,
290 ]
291 .as_mut_slice()
292 .decode::<wire::Flexible<'_, ()>>()
293 .unwrap()
294 .as_ref(),
295 crate::Flexible::Ok(&()),
296 );
297 assert_eq!(
298 chunks![
299 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
300 0x01, 0x00,
301 ]
302 .as_mut_slice()
303 .decode::<wire::Flexible<'_, ()>>()
304 .unwrap()
305 .as_ref(),
306 crate::Flexible::<&()>::FrameworkErr(crate::FrameworkError::UnknownMethod),
307 );
308 }
309}