asn1_rs/
class.rs

1use core::convert::TryFrom;
2use core::fmt;
3
4#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5pub struct BerClassFromIntError(pub(crate) ());
6
7/// BER Object class of tag
8#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
9#[repr(u8)]
10pub enum Class {
11    /// `Universal` class of tags (`0b00`)
12    Universal = 0b00,
13    /// `Application` class of tags (`0b01`)
14    Application = 0b01,
15    /// `Context-Specific` class of tags (`0b10`)
16    ContextSpecific = 0b10,
17    /// `Private` class of tags (`0b11`)
18    Private = 0b11,
19}
20
21impl Class {
22    /// `Universal` class of tags (`0b00`)
23    pub const UNIVERSAL: u8 = 0b00;
24    /// `Application` class of tags (`0b01`)
25    pub const APPLICATION: u8 = 0b01;
26    /// `Context-Specific` class of tags (`0b10`)
27    pub const CONTEXT_SPECIFIC: u8 = 0b10;
28    /// `Private` class of tags (`0b11`)
29    pub const PRIVATE: u8 = 0b11;
30
31    pub const fn assert_eq(&self, class: Class) -> Result<(), crate::error::Error> {
32        if *self as u8 == class as u8 {
33            Ok(())
34        } else {
35            Err(crate::error::Error::UnexpectedClass {
36                expected: Some(class),
37                actual: *self,
38            })
39        }
40    }
41
42    pub const fn new_unwrap(value: u8) -> Self {
43        match value {
44            0b00 => Class::Universal,
45            0b01 => Class::Application,
46            0b10 => Class::ContextSpecific,
47            0b11 => Class::Private,
48            _ => panic!("Value outside range"),
49        }
50    }
51}
52
53impl fmt::Display for Class {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        let s = match self {
56            Class::Universal => "UNIVERSAL",
57            Class::Application => "APPLICATION",
58            Class::ContextSpecific => "CONTEXT-SPECIFIC",
59            Class::Private => "PRIVATE",
60        };
61        write!(f, "{}", s)
62    }
63}
64
65impl TryFrom<u8> for Class {
66    type Error = BerClassFromIntError;
67
68    #[inline]
69    fn try_from(value: u8) -> Result<Self, Self::Error> {
70        match value {
71            0b00 => Ok(Class::Universal),
72            0b01 => Ok(Class::Application),
73            0b10 => Ok(Class::ContextSpecific),
74            0b11 => Ok(Class::Private),
75            _ => Err(BerClassFromIntError(())),
76        }
77    }
78}
79
80#[cfg(all(test, feature = "std"))]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn methods_class() {
86        let c = Class::Universal;
87        assert!(c.assert_eq(Class::Universal).is_ok());
88        assert!(c.assert_eq(Class::Private).is_err());
89
90        assert_eq!(Class::Universal.to_string().as_str(), "UNIVERSAL");
91        assert_eq!(Class::Application.to_string().as_str(), "APPLICATION");
92        assert_eq!(
93            Class::ContextSpecific.to_string().as_str(),
94            "CONTEXT-SPECIFIC"
95        );
96        assert_eq!(Class::Private.to_string().as_str(), "PRIVATE");
97
98        assert!(Class::try_from(0b00).is_ok());
99        assert!(Class::try_from(0b01).is_ok());
100        assert!(Class::try_from(0b10).is_ok());
101        assert!(Class::try_from(0b11).is_ok());
102        assert!(Class::try_from(4).is_err());
103    }
104}