asn1_rs/asn1_types/
boolean.rs

1use crate::*;
2use core::convert::TryFrom;
3
4/// ASN.1 `BOOLEAN` type
5///
6/// BER objects consider any non-zero value as `true`, and `0` as `false`.
7///
8/// DER objects must use value `0x0` (`false`) or `0xff` (`true`).
9#[derive(Debug, PartialEq, Eq)]
10pub struct Boolean {
11    pub value: u8,
12}
13
14impl Boolean {
15    /// `BOOLEAN` object for value `false`
16    pub const FALSE: Boolean = Boolean::new(0);
17    /// `BOOLEAN` object for value `true`
18    pub const TRUE: Boolean = Boolean::new(0xff);
19
20    /// Create a new `Boolean` from the provided logical value.
21    #[inline]
22    pub const fn new(value: u8) -> Self {
23        Boolean { value }
24    }
25
26    /// Return the `bool` value from this object.
27    #[inline]
28    pub const fn bool(&self) -> bool {
29        self.value != 0
30    }
31}
32
33impl<'a> TryFrom<Any<'a>> for Boolean {
34    type Error = Error;
35
36    fn try_from(any: Any<'a>) -> Result<Boolean> {
37        TryFrom::try_from(&any)
38    }
39}
40
41// non-consuming version
42impl<'a, 'b> TryFrom<&'b Any<'a>> for Boolean {
43    type Error = Error;
44
45    fn try_from(any: &'b Any<'a>) -> Result<Boolean> {
46        any.tag().assert_eq(Self::TAG)?;
47        // X.690 section 8.2.1:
48        // The encoding of a boolean value shall be primitive. The contents octets shall consist of a single octet
49        if any.header.length != Length::Definite(1) {
50            return Err(Error::InvalidLength);
51        }
52        let value = any.data[0];
53        Ok(Boolean { value })
54    }
55}
56
57impl CheckDerConstraints for Boolean {
58    fn check_constraints(any: &Any) -> Result<()> {
59        let c = any.data[0];
60        // X.690 section 11.1
61        if !(c == 0 || c == 0xff) {
62            return Err(Error::DerConstraintFailed(DerConstraint::InvalidBoolean));
63        }
64        Ok(())
65    }
66}
67
68impl DerAutoDerive for Boolean {}
69
70impl Tagged for Boolean {
71    const TAG: Tag = Tag::Boolean;
72}
73
74#[cfg(feature = "std")]
75impl ToDer for Boolean {
76    fn to_der_len(&self) -> Result<usize> {
77        // 3 = 1 (tag) + 1 (length) + 1 (value)
78        Ok(3)
79    }
80
81    fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
82        writer.write(&[Self::TAG.0 as u8, 0x01]).map_err(Into::into)
83    }
84
85    fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
86        let b = if self.value != 0 { 0xff } else { 0x00 };
87        writer.write(&[b]).map_err(Into::into)
88    }
89
90    /// Similar to using `to_der`, but uses header without computing length value
91    fn write_der_raw(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
92        let sz = writer.write(&[Self::TAG.0 as u8, 0x01, self.value])?;
93        Ok(sz)
94    }
95}
96
97impl<'a> TryFrom<Any<'a>> for bool {
98    type Error = Error;
99
100    fn try_from(any: Any<'a>) -> Result<bool> {
101        TryFrom::try_from(&any)
102    }
103}
104
105impl<'a, 'b> TryFrom<&'b Any<'a>> for bool {
106    type Error = Error;
107
108    fn try_from(any: &'b Any<'a>) -> Result<bool> {
109        any.tag().assert_eq(Self::TAG)?;
110        let b = Boolean::try_from(any)?;
111        Ok(b.bool())
112    }
113}
114
115impl CheckDerConstraints for bool {
116    fn check_constraints(any: &Any) -> Result<()> {
117        let c = any.data[0];
118        // X.690 section 11.1
119        if !(c == 0 || c == 0xff) {
120            return Err(Error::DerConstraintFailed(DerConstraint::InvalidBoolean));
121        }
122        Ok(())
123    }
124}
125
126impl DerAutoDerive for bool {}
127
128impl Tagged for bool {
129    const TAG: Tag = Tag::Boolean;
130}
131
132#[cfg(feature = "std")]
133impl ToDer for bool {
134    fn to_der_len(&self) -> Result<usize> {
135        // 3 = 1 (tag) + 1 (length) + 1 (value)
136        Ok(3)
137    }
138
139    fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
140        writer.write(&[Self::TAG.0 as u8, 0x01]).map_err(Into::into)
141    }
142
143    fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
144        let b = if *self { 0xff } else { 0x00 };
145        writer.write(&[b]).map_err(Into::into)
146    }
147}