packet_encoding/
lib.rs

1// Copyright 2020 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//! Generic utilities for encoding/decoding packets.
6
7/// Generates an enum value where each variant can be converted into a constant in the given
8/// raw_type.
9///
10/// For example:
11/// decodable_enum! {
12///     pub(crate) enum Color<u8, MyError, MyError::Variant> {
13///        Red = 1,
14///        Blue = 2,
15///        Green = 3,
16///     }
17/// }
18///
19/// Color::try_from(2) -> Color::Red
20/// u8::from(&Color::Red) -> 1.
21#[macro_export]
22macro_rules! decodable_enum {
23    ($(#[$meta:meta])* $visibility:vis enum $name:ident<
24        $raw_type:ty,
25        $error_type:ident,
26        $error_path:ident
27    > {
28        $($(#[$variant_meta:meta])* $variant:ident = $val:expr),*,
29    }) => {
30        $(#[$meta])*
31        #[derive(
32            ::core::clone::Clone,
33            ::core::marker::Copy,
34            ::core::fmt::Debug,
35            ::core::cmp::Eq,
36            ::core::hash::Hash,
37            ::core::cmp::PartialEq)]
38        $visibility enum $name {
39            $($(#[$variant_meta])* $variant = $val),*
40        }
41
42        impl $name {
43            pub const VALUES : &'static [$raw_type] = &[$($val),*,];
44            pub const VARIANTS : &'static [$name] = &[$($name::$variant),*,];
45            pub fn name(&self) -> &'static ::core::primitive::str {
46                match self {
47                    $($name::$variant => ::core::stringify!($variant)),*
48                }
49            }
50        }
51
52        impl ::core::convert::From<&$name> for $raw_type {
53            fn from(v: &$name) -> $raw_type {
54                match v {
55                    $($name::$variant => $val),*,
56                }
57            }
58        }
59
60        impl ::core::convert::TryFrom<$raw_type> for $name {
61            type Error = $error_type;
62
63            fn try_from(value: $raw_type) -> ::core::result::Result<Self, $error_type> {
64                match value {
65                    $($val => ::core::result::Result::Ok($name::$variant)),*,
66                    _ => ::core::result::Result::Err($error_type::$error_path),
67                }
68            }
69        }
70    }
71}
72
73/// A decodable type can be created from a byte buffer.
74/// The type returned is separate (copied) from the buffer once decoded.
75pub trait Decodable: ::core::marker::Sized {
76    type Error;
77
78    /// Decodes into a new object, or returns an error.
79    fn decode(buf: &[u8]) -> ::core::result::Result<Self, Self::Error>;
80}
81
82/// An encodable type can write itself into a byte buffer.
83pub trait Encodable: ::core::marker::Sized {
84    type Error;
85
86    /// Returns the number of bytes necessary to encode |self|.
87    fn encoded_len(&self) -> ::core::primitive::usize;
88    /// Writes the encoded version of |self| at the start of |buf|.
89    /// |buf| must be at least |self.encoded_len()| length.
90    fn encode(&self, buf: &mut [u8]) -> ::core::result::Result<(), Self::Error>;
91}
92
93#[macro_export]
94macro_rules! codable_as_bitmask {
95    ($type:ty, $raw_type:ty, $error_type:ident, $error_path:ident) => {
96        impl $type {
97            pub fn from_bits(
98                v: $raw_type,
99            ) -> impl ::std::iter::Iterator<Item = ::core::result::Result<$type, $error_type>> {
100                (0..<$raw_type>::BITS).map(|bit| 1 << bit).filter(move |val| (v & val) != 0).map(
101                    |val| {
102                        ::std::convert::TryInto::<$type>::try_into(val)
103                            .map_err(|_| $error_type::$error_path)
104                    },
105                )
106            }
107
108            pub fn to_bits<'a>(
109                mut it: impl ::std::iter::Iterator<Item = &'a $type>,
110            ) -> ::core::result::Result<$raw_type, $error_type> {
111                it.try_fold(0, |acc, item| {
112                    let v = ::std::convert::Into::<$raw_type>::into(item);
113                    if v == 0 {
114                        return ::core::result::Result::Err($error_type::$error_path);
115                    }
116                    if (v as f64).log2().ceil() != (v as f64).log2().floor() {
117                        return ::core::result::Result::Err($error_type::$error_path);
118                    }
119                    ::core::result::Result::Ok(acc | v)
120                })
121            }
122        }
123    };
124}
125
126#[cfg(test)]
127#[no_implicit_prelude]
128mod test {
129    use ::assert_matches::assert_matches;
130    use ::core::convert::{From, TryFrom};
131    use ::core::option::Option::Some;
132    use ::core::result::Result;
133    use ::core::{assert, assert_eq, panic};
134    use ::std::collections::HashSet;
135    use ::std::iter::{IntoIterator, Iterator};
136    use ::std::vec;
137
138    #[derive(Debug, PartialEq)]
139    pub(crate) enum TestError {
140        OutOfRange,
141    }
142
143    decodable_enum! {
144        pub(crate) enum TestEnum<u16, TestError, OutOfRange> {
145            One = 0x0001,
146            Two = 0x0002,
147            Max = 0xFFFF,
148        }
149    }
150    codable_as_bitmask!(TestEnum, u16, TestError, OutOfRange);
151
152    decodable_enum! {
153        pub(crate) enum TestEnum2<u16, TestError, OutOfRange> {
154            One = 0x0001,  // bit 0
155            Two = 0x0002,  // bit 1
156            Big = 0x4000,  // bit 14
157        }
158    }
159    codable_as_bitmask!(TestEnum2, u16, TestError, OutOfRange);
160
161    #[test]
162    fn try_from_success() {
163        let one = TestEnum::try_from(1);
164        assert!(one.is_ok());
165        assert_eq!(TestEnum::One, one.unwrap());
166        let two = TestEnum::try_from(2);
167        assert!(two.is_ok());
168        assert_eq!(TestEnum::Two, two.unwrap());
169        let max = TestEnum::try_from(65535);
170        assert!(max.is_ok());
171        assert_eq!(TestEnum::Max, max.unwrap());
172    }
173
174    #[test]
175    fn try_from_error() {
176        let err = TestEnum::try_from(5);
177        assert_matches!(err.err(), Some(TestError::OutOfRange));
178    }
179
180    #[test]
181    fn into_rawtype() {
182        let raw = u16::from(&TestEnum::One);
183        assert_eq!(1, raw);
184        let raw = u16::from(&TestEnum::Two);
185        assert_eq!(2, raw);
186        let raw = u16::from(&TestEnum::Max);
187        assert_eq!(65535, raw);
188    }
189
190    #[test]
191    fn test_values() {
192        let v = TestEnum::VALUES.to_vec();
193        assert_eq!(3, v.len());
194        assert_eq!(1, v[0]);
195        assert_eq!(2, v[1]);
196        assert_eq!(65535, v[2]);
197
198        let v = TestEnum2::VALUES.to_vec();
199        assert_eq!(v, vec![1, 2, 16384]);
200    }
201
202    #[test]
203    fn test_variants() {
204        let v = TestEnum::VARIANTS.to_vec();
205        assert_eq!(3, v.len());
206        assert_eq!(TestEnum::One, v[0]);
207        assert_eq!(TestEnum::Two, v[1]);
208        assert_eq!(TestEnum::Max, v[2]);
209    }
210
211    #[test]
212    fn test_name() {
213        assert_eq!("One", TestEnum::One.name());
214        assert_eq!("Two", TestEnum::Two.name());
215        assert_eq!("Max", TestEnum::Max.name());
216        assert_eq!("Big", TestEnum2::Big.name());
217    }
218
219    #[test]
220    fn as_bitmask() {
221        let one_and_big = 0x4001;
222
223        let enums: HashSet<TestEnum2> = TestEnum2::from_bits(one_and_big)
224            .collect::<Result<HashSet<_>, _>>()
225            .expect("should not fail");
226
227        assert_eq!(2, enums.len());
228
229        let expected_enums = [TestEnum2::One, TestEnum2::Big].into_iter().collect();
230
231        assert_eq!(enums, expected_enums);
232
233        let all = TestEnum2::VARIANTS;
234        let value = TestEnum2::to_bits(all.iter()).expect("should work");
235        assert_eq!(0x4003, value);
236    }
237
238    #[test]
239    fn bitmask_errors() {
240        // Max value has both bit one and two set which are valid TestEnum variants.
241        // The rest of the set bits are not valid TestEnum variants.
242        let max = 65535;
243        // Collecting as result shows failure.
244        let res: Result<HashSet<TestEnum>, _> = TestEnum::from_bits(max).collect();
245        let _ = res.expect_err("should have failed");
246        // Collecting as vector of results show only 2 "bit" values were valid enums.
247        let res: vec::Vec<Result<TestEnum, TestError>> = TestEnum::from_bits(max).collect();
248        let valid: vec::Vec<TestEnum> = res.into_iter().filter_map(|v| v.ok()).collect();
249        assert_eq!(valid.len(), 2);
250
251        // Fails because TestEnum::Max variant is not a bitwise flag value.
252        let all = TestEnum::VARIANTS;
253        let _ = TestEnum::to_bits(all.iter()).expect_err("should fail");
254    }
255}