binary_layout/fields/
bool.rs

1use crate::LayoutAs;
2use core::convert::Infallible;
3
4/// This error is thrown when trying to read a bool that isn't `0` or `1`.
5#[derive(Debug)]
6pub struct InvalidBoolError(pub(crate) ());
7
8impl core::fmt::Display for InvalidBoolError {
9    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
10        write!(fmt, "InvalidBoolError")
11    }
12}
13
14#[cfg(feature = "std")]
15impl std::error::Error for InvalidBoolError {}
16
17impl LayoutAs<u8> for bool {
18    type ReadError = InvalidBoolError;
19    type WriteError = Infallible;
20
21    fn try_read(v: u8) -> Result<Self, Self::ReadError> {
22        match v {
23            0 => Ok(false),
24            1 => Ok(true),
25            _ => Err(InvalidBoolError(())),
26        }
27    }
28
29    fn try_write(v: Self) -> Result<u8, Self::WriteError> {
30        match v {
31            true => Ok(1),
32            false => Ok(0),
33        }
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40    use crate::{binary_layout, WrappedFieldError};
41
42    const INVALID_BOOL: u8 = 3;
43
44    macro_rules! test_bool {
45        ($endian:ident, $endian_type:ty, $from_endian_fn:ident, $to_endian_fn:ident) => {
46            paste::paste! {
47                #[allow(non_snake_case)]
48                #[test]
49                fn [<test_bool_ $endian endian_viewapi_tryread_write>]() {
50                    binary_layout!(layout, $endian_type, {
51                        field1: bool as u8,
52                        field2: bool as u8,
53                        field3: bool as u8,
54                    });
55                    let mut storage = [0; 1024];
56                    storage[2..3].copy_from_slice(&INVALID_BOOL.$to_endian_fn()); // Invalid unicode code point into field3
57
58                    let mut view = layout::View::new(&mut storage);
59
60                    view.field1_mut().write(true);
61                    view.field2_mut().write(false);
62
63                    assert_eq!(true, view.field1().try_read().unwrap());
64                    assert_eq!(false, view.field2().try_read().unwrap());
65                    assert!(matches!(view.field3().try_read(), Err(WrappedFieldError::LayoutAsError(InvalidBoolError(_)))));
66
67                    assert_eq!(1, u8::$from_endian_fn((&storage[0..1]).try_into().unwrap()));
68                    assert_eq!(0, u8::$from_endian_fn((&storage[1..2]).try_into().unwrap()));
69                    assert_eq!(INVALID_BOOL, u8::$from_endian_fn((&storage[2..3]).try_into().unwrap()));
70                }
71
72                #[allow(non_snake_case)]
73                #[test]
74                fn [<test_bool_ $endian endian_viewapi_tryread_trywrite>]() {
75                    binary_layout!(layout, $endian_type, {
76                        field1: bool as u8,
77                        field2: bool as u8,
78                        field3: bool as u8,
79                    });
80                    let mut storage = [0; 1024];
81                    storage[2..3].copy_from_slice(&INVALID_BOOL.$to_endian_fn()); // Invalid unicode code point into field3
82
83                    let mut view = layout::View::new(&mut storage);
84
85                    view.field1_mut().write(true);
86                    view.field2_mut().write(false);
87
88                    assert_eq!(true, view.field1().try_read().unwrap());
89                    assert_eq!(false, view.field2().try_read().unwrap());
90                    assert!(matches!(view.field3().try_read(), Err(WrappedFieldError::LayoutAsError(InvalidBoolError(_)))));
91
92                    assert_eq!(1, u8::$from_endian_fn((&storage[0..1]).try_into().unwrap()));
93                    assert_eq!(0, u8::$from_endian_fn((&storage[1..2]).try_into().unwrap()));
94                    assert_eq!(INVALID_BOOL, u8::$from_endian_fn((&storage[2..3]).try_into().unwrap()));
95                }
96            }
97        }
98    }
99
100    test_bool!(little, LittleEndian, from_le_bytes, to_le_bytes);
101    test_bool!(big, BigEndian, from_be_bytes, to_be_bytes);
102    test_bool!(native, NativeEndian, from_ne_bytes, to_ne_bytes);
103}