1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use crate::rstd::inlining::*;

use super::*;

impl Serializable for bool {
    fn serialize(&self, serializer: &mut dyn Serializer) {
        match self {
            true => serializer.write(&[0]),
            false => serializer.write(&[1]),
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum BooleanParseError {
    OutOfBounds(u8),
    Eof,
    ExtraData(usize),
}

impl Display for BooleanParseError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::OutOfBounds(value) => {
                write!(f, "boolean value out of bounds: {}", value)
            }
            Self::Eof => write!(f, "encountered EOF write parsing a boolean"),
            Self::ExtraData(length) => write!(
                f,
                "encountered extra data of length {length} while parsing a boolean",
            ),
        }
    }
}

impl Error for BooleanParseError {}

impl From<&[u8]> for BooleanParseError {
    fn from(_value: &[u8]) -> Self {
        Self::Eof
    }
}

impl AtomicBase for bool {
    type AParseError = BooleanParseError;
}

impl ImplMode for bool {
    type Mode = InliningMode;
}

impl CInliningAtomic for bool {
    fn ca_extension_error(tail: &[u8]) -> Self::AParseError {
        BooleanParseError::ExtraData(tail.len())
    }

    fn ca_ideserialize<I: Stream>(stream: I) -> AIParseResult<Self, I> {
        let (byte, stream) = stream.iread_n_const::<1>(BooleanParseError::from_ref)?;
        match byte[0] {
            0 => Ok((false, stream)),
            1 => Ok((true, stream)),
            value => Err(BooleanParseError::OutOfBounds(value)),
        }
    }
}

impl ConstSizeAtomic for bool {
    const SIZE: usize = 1;
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn can_parse_false() {
        assert!(!bool::parse_slice(&[0]).unwrap())
    }

    #[test]
    fn can_parse_true() {
        assert!(bool::parse_slice(&[1]).unwrap())
    }

    #[test]
    fn cannot_parse_out_of_bound_value() {
        assert_eq!(
            bool::parse_slice(&[2]).unwrap_err(),
            BooleanParseError::OutOfBounds(2)
        );
        assert_eq!(
            bool::parse_slice(&[2, 0]).unwrap_err(),
            BooleanParseError::OutOfBounds(2)
        );
    }

    #[test]
    fn cannot_parse_empty_slice() {
        assert_eq!(bool::parse_slice(&[]).unwrap_err(), BooleanParseError::Eof);
    }

    #[test]
    fn cannot_parse_extra_tail() {
        assert_eq!(
            bool::parse_slice(&[0, 10, 20, 30]).unwrap_err(),
            BooleanParseError::ExtraData(3)
        );
    }
}