1use core::fmt;
6use core::marker::PhantomData;
7use core::mem::{MaybeUninit, forget};
8use core::ops::Deref;
9
10use fidl_next_codec::{
11 Chunk, Constrained, Decode, DecodeError, Decoder, Encode, EncodeError, Encoder, FromWire,
12 FromWireRef, IntoNatural, Slot, ValidationError, Wire, munge, wire,
13};
14
15const ORD_OK: u64 = 1;
16
17#[repr(transparent)]
19pub struct Flexible<'de, T> {
20 raw: wire::Union,
21 _phantom: PhantomData<(&'de mut [Chunk], T)>,
22}
23
24impl<T> Drop for Flexible<'_, T> {
25 fn drop(&mut self) {
26 let _ = unsafe { self.raw.get().read_unchecked::<T>() };
27 }
28}
29
30impl<T> Constrained for Flexible<'_, T>
31where
32 T: Constrained<Constraint = ()>,
33{
34 type Constraint = ();
35
36 fn validate(_: Slot<'_, Self>, _: Self::Constraint) -> Result<(), ValidationError> {
37 Ok(())
38 }
39}
40
41unsafe impl<T> Wire for Flexible<'static, T>
42where
43 T: Wire<Constraint = ()>,
44{
45 type Narrowed<'de> = Flexible<'de, T::Narrowed<'de>>;
46
47 #[inline]
48 fn zero_padding(out: &mut MaybeUninit<Self>) {
49 munge!(let Self { raw, _phantom: _ } = out);
50 wire::Union::zero_padding(raw);
51 }
52}
53
54impl<T> Deref for Flexible<'_, T> {
55 type Target = T;
56
57 fn deref(&self) -> &Self::Target {
58 unsafe { self.raw.get().deref_unchecked() }
59 }
60}
61
62impl<T> AsRef<T> for Flexible<'_, T> {
63 fn as_ref(&self) -> &T {
64 Deref::deref(self)
65 }
66}
67
68impl<T> Flexible<'_, T> {
69 pub fn into_inner(self) -> T {
71 let result = unsafe { self.raw.get().read_unchecked() };
72 forget(self);
73 result
74 }
75}
76
77impl<T: Clone> Clone for Flexible<'_, T> {
78 fn clone(&self) -> Self {
79 Self { raw: unsafe { self.raw.clone_inline_unchecked::<T>() }, _phantom: PhantomData }
80 }
81}
82
83impl<T: fmt::Debug> fmt::Debug for Flexible<'_, T> {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 self.as_ref().fmt(f)
86 }
87}
88
89unsafe impl<'de, D, T> Decode<D> for Flexible<'de, T>
90where
91 D: Decoder<'de> + ?Sized,
92 T: Decode<D, Constraint = ()>,
93{
94 fn decode(slot: Slot<'_, Self>, decoder: &mut D, _: ()) -> Result<(), DecodeError> {
95 munge!(let Self { mut raw, _phantom: _ } = slot);
96
97 let ordinal = wire::Union::encoded_ordinal(raw.as_mut());
98 if ordinal != ORD_OK {
99 return Err(DecodeError::InvalidUnionOrdinal(ordinal as usize));
100 }
101 wire::Union::decode_as::<D, T>(raw, decoder, ())?;
102 Ok(())
103 }
104}
105
106unsafe impl<E, W, T> Encode<Flexible<'static, W>, E> for crate::Flexible<T>
107where
108 E: Encoder + ?Sized,
109 W: Wire<Constraint = ()>,
110 T: Encode<W, E>,
111{
112 fn encode(
113 self,
114 encoder: &mut E,
115 out: &mut MaybeUninit<Flexible<'static, W>>,
116 _: (),
117 ) -> Result<(), EncodeError> {
118 munge!(let Flexible { raw, _phantom: _ } = out);
119 wire::Union::encode_as::<E, W>(self.0, ORD_OK, encoder, raw, ())?;
120 Ok(())
121 }
122}
123
124unsafe impl<'a, E, W, T> Encode<Flexible<'static, W>, E> for &'a crate::Flexible<T>
125where
126 E: Encoder + ?Sized,
127 W: Wire<Constraint = ()>,
128 &'a T: Encode<W, E>,
129{
130 fn encode(
131 self,
132 encoder: &mut E,
133 out: &mut MaybeUninit<Flexible<'static, W>>,
134 _: (),
135 ) -> Result<(), EncodeError> {
136 crate::Flexible(self.as_ref()).encode(encoder, out, ())
137 }
138}
139
140impl<T, W> FromWire<Flexible<'_, W>> for crate::Flexible<T>
141where
142 T: FromWire<W>,
143{
144 #[inline]
145 fn from_wire(wire: Flexible<'_, W>) -> Self {
146 crate::Flexible(T::from_wire(wire.into_inner()))
147 }
148}
149
150impl<T: IntoNatural> IntoNatural for Flexible<'_, T> {
151 type Natural = crate::Flexible<T::Natural>;
152}
153
154impl<T, W> FromWireRef<Flexible<'_, W>> for crate::Flexible<T>
155where
156 T: FromWireRef<W>,
157{
158 #[inline]
159 fn from_wire_ref(wire: &Flexible<'_, W>) -> Self {
160 crate::Flexible(T::from_wire_ref(wire.as_ref()))
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::Flexible;
167
168 use fidl_next_codec::{DecoderExt as _, EncoderExt as _, chunks, wire};
169
170 #[test]
171 fn encode_flexible() {
172 assert_eq!(
173 Vec::encode(crate::Flexible::<i32>(0x12345678)).unwrap(),
174 chunks![
175 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12, 0x00, 0x00,
176 0x01, 0x00,
177 ],
178 );
179 }
180
181 #[test]
182 fn decode_result() {
183 assert_eq!(
184 chunks![
185 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12, 0x00, 0x00,
186 0x01, 0x00,
187 ]
188 .as_mut_slice()
189 .decode::<Flexible<'_, wire::Int32>>()
190 .unwrap()
191 .as_ref()
192 .0,
193 0x12345678,
194 );
195 }
196}