summaryrefslogtreecommitdiff
path: root/src/class.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/class.rs')
-rw-r--r--src/class.rs94
1 files changed, 94 insertions, 0 deletions
diff --git a/src/class.rs b/src/class.rs
new file mode 100644
index 0000000..9a4f9de
--- /dev/null
+++ b/src/class.rs
@@ -0,0 +1,94 @@
+use core::convert::TryFrom;
+use core::fmt;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct BerClassFromIntError(pub(crate) ());
+
+/// BER Object class of tag
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[repr(u8)]
+pub enum Class {
+ /// `Universal` class of tags (`0b00`)
+ Universal = 0b00,
+ /// `Application` class of tags (`0b01`)
+ Application = 0b01,
+ /// `Context-Specific` class of tags (`0b10`)
+ ContextSpecific = 0b10,
+ /// `Private` class of tags (`0b11`)
+ Private = 0b11,
+}
+
+impl Class {
+ /// `Universal` class of tags (`0b00`)
+ pub const UNIVERSAL: u8 = 0b00;
+ /// `Application` class of tags (`0b01`)
+ pub const APPLICATION: u8 = 0b01;
+ /// `Context-Specific` class of tags (`0b10`)
+ pub const CONTEXT_SPECIFIC: u8 = 0b10;
+ /// `Private` class of tags (`0b11`)
+ pub const PRIVATE: u8 = 0b11;
+
+ pub const fn assert_eq(&self, class: Class) -> Result<(), crate::error::Error> {
+ if *self as u8 == class as u8 {
+ Ok(())
+ } else {
+ Err(crate::error::Error::UnexpectedClass {
+ expected: Some(class),
+ actual: *self,
+ })
+ }
+ }
+}
+
+impl fmt::Display for Class {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let s = match self {
+ Class::Universal => "UNIVERSAL",
+ Class::Application => "APPLICATION",
+ Class::ContextSpecific => "CONTEXT-SPECIFIC",
+ Class::Private => "PRIVATE",
+ };
+ write!(f, "{}", s)
+ }
+}
+
+impl TryFrom<u8> for Class {
+ type Error = BerClassFromIntError;
+
+ #[inline]
+ fn try_from(value: u8) -> Result<Self, Self::Error> {
+ match value {
+ 0b00 => Ok(Class::Universal),
+ 0b01 => Ok(Class::Application),
+ 0b10 => Ok(Class::ContextSpecific),
+ 0b11 => Ok(Class::Private),
+ _ => Err(BerClassFromIntError(())),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn methods_class() {
+ let c = Class::Universal;
+ assert!(c.assert_eq(Class::Universal).is_ok());
+ assert!(c.assert_eq(Class::Private).is_err());
+
+ assert_eq!(Class::Universal.to_string().as_str(), "UNIVERSAL");
+ assert_eq!(Class::Application.to_string().as_str(), "APPLICATION");
+ assert_eq!(
+ Class::ContextSpecific.to_string().as_str(),
+ "CONTEXT-SPECIFIC"
+ );
+ assert_eq!(Class::Private.to_string().as_str(), "PRIVATE");
+
+ assert!(Class::try_from(0b00).is_ok());
+ assert!(Class::try_from(0b01).is_ok());
+ assert!(Class::try_from(0b10).is_ok());
+ assert!(Class::try_from(0b11).is_ok());
+ assert!(Class::try_from(4).is_err());
+ }
+}