fidl_next_codec/decode/
mod.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Provides decoding for FIDL types.
6
7mod error;
8
9pub use self::error::*;
10
11use crate::{Slot, WireF32, WireF64, WireI16, WireI32, WireI64, WireU16, WireU32, WireU64};
12
13/// Decodes a value from the given slot.
14///
15/// # Safety
16///
17/// If `decode` returns `Ok`, then the provided `slot` will contain a valid `Self` after the
18/// decoder is committed.
19pub unsafe trait Decode<D: ?Sized> {
20    /// Decodes a value into a slot using a decoder.
21    ///
22    /// If decoding succeeds, `slot` will contain a valid `Self` after the decoder is committed. If
23    /// decoding fails, an error will be returned.
24    fn decode(slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError>;
25}
26
27macro_rules! impl_primitive {
28    ($ty:ty) => {
29        unsafe impl<D: ?Sized> Decode<D> for $ty {
30            #[inline]
31            fn decode(_: Slot<'_, Self>, _: &mut D) -> Result<(), DecodeError> {
32                Ok(())
33            }
34        }
35    };
36}
37
38macro_rules! impl_primitives {
39    ($($ty:ty),* $(,)?) => {
40        $(
41            impl_primitive!($ty);
42        )*
43    }
44}
45
46impl_primitives! {
47    (),
48
49    i8,
50    WireI16,
51    WireI32,
52    WireI64,
53
54    u8,
55    WireU16,
56    WireU32,
57    WireU64,
58
59    WireF32,
60    WireF64,
61}
62
63unsafe impl<D: ?Sized> Decode<D> for bool {
64    #[inline]
65    fn decode(slot: Slot<'_, Self>, _: &mut D) -> Result<(), DecodeError> {
66        let value = unsafe { slot.as_ptr().cast::<u8>().read() };
67        match value {
68            0 | 1 => (),
69            invalid => return Err(DecodeError::InvalidBool(invalid)),
70        }
71        Ok(())
72    }
73}
74
75unsafe impl<D: ?Sized, T: Decode<D>, const N: usize> Decode<D> for [T; N] {
76    fn decode(mut slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
77        for i in 0..N {
78            T::decode(slot.index(i), decoder)?;
79        }
80        Ok(())
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use crate::{chunks, WireF32, WireF64, WireI16, WireI32, WireI64, WireU16, WireU32, WireU64};
87
88    use crate::testing::assert_decoded;
89    use crate::wire::{WireBox, WireString, WireVector};
90    use crate::{WireOptionalString, WireOptionalVector};
91
92    #[test]
93    fn decode_unit() {
94        assert_decoded::<()>(&mut chunks![], |_| ());
95    }
96
97    #[test]
98    fn decode_bool() {
99        assert_decoded::<bool>(&mut chunks![0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], |x| {
100            assert!(*x)
101        });
102        assert_decoded::<bool>(&mut chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], |x| {
103            assert!(!*x)
104        });
105    }
106
107    #[test]
108    fn decode_ints() {
109        assert_decoded::<u8>(&mut chunks![0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], |x| {
110            assert_eq!(*x, 0xa3u8)
111        });
112        assert_decoded::<i8>(&mut chunks![0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], |x| {
113            assert_eq!(*x, -0x45i8)
114        });
115
116        assert_decoded::<WireU16>(
117            &mut chunks![0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
118            |x| assert_eq!(*x, 0x1234u16),
119        );
120        assert_decoded::<WireI16>(
121            &mut chunks![0xcc, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
122            |x| assert_eq!(*x, -0x1234i16),
123        );
124
125        assert_decoded::<WireU32>(
126            &mut chunks![0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00],
127            |x| assert_eq!(*x, 0x12345678u32),
128        );
129        assert_decoded::<WireI32>(
130            &mut chunks![0x88, 0xa9, 0xcb, 0xed, 0x00, 0x00, 0x00, 0x00],
131            |x| assert_eq!(*x, -0x12345678i32),
132        );
133
134        assert_decoded::<WireU64>(
135            &mut chunks![0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12],
136            |x| assert_eq!(*x, 0x123456789abcdef0u64),
137        );
138        assert_decoded::<WireI64>(
139            &mut chunks![0x10, 0x21, 0x43, 0x65, 0x87, 0xa9, 0xcb, 0xed],
140            |x| assert_eq!(*x, -0x123456789abcdef0i64),
141        );
142    }
143
144    #[test]
145    fn decode_floats() {
146        assert_decoded::<WireF32>(
147            &mut chunks![0xdb, 0x0f, 0x49, 0x40, 0x00, 0x00, 0x00, 0x00],
148            |x| assert_eq!(*x, ::core::f32::consts::PI),
149        );
150        assert_decoded::<WireF64>(
151            &mut chunks![0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40],
152            |x| assert_eq!(*x, ::core::f64::consts::PI),
153        );
154    }
155
156    #[test]
157    fn decode_box() {
158        assert_decoded::<WireBox<WireU64>>(
159            &mut chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
160            |x| assert_eq!(x.as_ref(), None),
161        );
162        assert_decoded::<WireBox<WireU64>>(
163            &mut chunks![
164                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56,
165                0x34, 0x12,
166            ],
167            |x| assert_eq!(*x.as_ref().unwrap(), 0x123456789abcdef0u64),
168        );
169    }
170
171    #[test]
172    fn decode_vec() {
173        assert_decoded::<WireOptionalVector<WireU32>>(
174            &mut chunks![
175                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176                0x00, 0x00,
177            ],
178            |x| assert!(x.as_ref().is_none()),
179        );
180        assert_decoded::<WireVector<WireU32>>(
181            &mut chunks![
182                0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
183                0xff, 0xff, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a,
184            ],
185            |x| assert_eq!(x.as_slice(), [0x12345678, 0x9abcdef0].as_slice(),),
186        );
187        assert_decoded::<WireVector<WireU32>>(
188            &mut chunks![
189                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
190                0xff, 0xff,
191            ],
192            |x| assert_eq!(x.len(), 0),
193        );
194    }
195
196    #[test]
197    fn decode_string() {
198        assert_decoded::<WireOptionalString>(
199            &mut chunks![
200                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201                0x00, 0x00,
202            ],
203            |x| assert!(x.is_none()),
204        );
205        assert_decoded::<WireString>(
206            &mut chunks![
207                0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
208                0xff, 0xff, 0x30, 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00,
209            ],
210            |x| assert_eq!(x.as_str(), "0123"),
211        );
212        assert_decoded::<WireString>(
213            &mut chunks![
214                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
215                0xff, 0xff,
216            ],
217            |x| assert_eq!(x.len(), 0),
218        );
219    }
220}