der/tag/
number.rs

1//! ASN.1 tag numbers
2
3use super::Tag;
4use crate::{Error, ErrorKind, Result};
5use core::fmt;
6
7/// ASN.1 tag numbers (i.e. lower 5 bits of a [`Tag`]).
8///
9/// From X.690 Section 8.1.2.2:
10///
11/// > bits 5 to 1 shall encode the number of the tag as a binary integer with
12/// > bit 5 as the most significant bit.
13///
14/// This library supports tag numbers ranging from zero to 30 (inclusive),
15/// which can be represented as a single identifier octet.
16///
17/// Section 8.1.2.4 describes how to support multi-byte tag numbers, which are
18/// encoded by using a leading tag number of 31 (`0b11111`). This library
19/// deliberately does not support this: tag numbers greater than 30 are
20/// disallowed.
21#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
22pub struct TagNumber(pub(super) u8);
23
24impl TagNumber {
25    /// Tag number `0`
26    pub const N0: Self = Self(0);
27
28    /// Tag number `1`
29    pub const N1: Self = Self(1);
30
31    /// Tag number `2`
32    pub const N2: Self = Self(2);
33
34    /// Tag number `3`
35    pub const N3: Self = Self(3);
36
37    /// Tag number `4`
38    pub const N4: Self = Self(4);
39
40    /// Tag number `5`
41    pub const N5: Self = Self(5);
42
43    /// Tag number `6`
44    pub const N6: Self = Self(6);
45
46    /// Tag number `7`
47    pub const N7: Self = Self(7);
48
49    /// Tag number `8`
50    pub const N8: Self = Self(8);
51
52    /// Tag number `9`
53    pub const N9: Self = Self(9);
54
55    /// Tag number `10`
56    pub const N10: Self = Self(10);
57
58    /// Tag number `11`
59    pub const N11: Self = Self(11);
60
61    /// Tag number `12`
62    pub const N12: Self = Self(12);
63
64    /// Tag number `13`
65    pub const N13: Self = Self(13);
66
67    /// Tag number `14`
68    pub const N14: Self = Self(14);
69
70    /// Tag number `15`
71    pub const N15: Self = Self(15);
72
73    /// Tag number `16`
74    pub const N16: Self = Self(16);
75
76    /// Tag number `17`
77    pub const N17: Self = Self(17);
78
79    /// Tag number `18`
80    pub const N18: Self = Self(18);
81
82    /// Tag number `19`
83    pub const N19: Self = Self(19);
84
85    /// Tag number `20`
86    pub const N20: Self = Self(20);
87
88    /// Tag number `21`
89    pub const N21: Self = Self(21);
90
91    /// Tag number `22`
92    pub const N22: Self = Self(22);
93
94    /// Tag number `23`
95    pub const N23: Self = Self(23);
96
97    /// Tag number `24`
98    pub const N24: Self = Self(24);
99
100    /// Tag number `25`
101    pub const N25: Self = Self(25);
102
103    /// Tag number `26`
104    pub const N26: Self = Self(26);
105
106    /// Tag number `27`
107    pub const N27: Self = Self(27);
108
109    /// Tag number `28`
110    pub const N28: Self = Self(28);
111
112    /// Tag number `29`
113    pub const N29: Self = Self(29);
114
115    /// Tag number `30`
116    pub const N30: Self = Self(30);
117
118    /// Mask value used to obtain the tag number from a tag octet.
119    pub(super) const MASK: u8 = 0b11111;
120
121    /// Maximum tag number supported (inclusive).
122    const MAX: u8 = 30;
123
124    /// Create a new tag number (const-friendly).
125    ///
126    /// Panics if the tag number is greater than `30`.
127    /// For a fallible conversion, use [`TryFrom`] instead.
128    #[allow(clippy::no_effect)]
129    pub const fn new(byte: u8) -> Self {
130        // TODO(tarcieri): hax! use const panic when available
131        ["tag number out of range"][(byte > Self::MAX) as usize];
132        Self(byte)
133    }
134
135    /// Create an `APPLICATION` tag with this tag number.
136    pub fn application(self, constructed: bool) -> Tag {
137        Tag::Application {
138            constructed,
139            number: self,
140        }
141    }
142
143    /// Create a `CONTEXT-SPECIFIC` tag with this tag number.
144    pub fn context_specific(self, constructed: bool) -> Tag {
145        Tag::ContextSpecific {
146            constructed,
147            number: self,
148        }
149    }
150
151    /// Create a `PRIVATE` tag with this tag number.
152    pub fn private(self, constructed: bool) -> Tag {
153        Tag::Private {
154            constructed,
155            number: self,
156        }
157    }
158
159    /// Get the inner value.
160    pub fn value(self) -> u8 {
161        self.0
162    }
163}
164
165impl TryFrom<u8> for TagNumber {
166    type Error = Error;
167
168    fn try_from(byte: u8) -> Result<Self> {
169        match byte {
170            0..=Self::MAX => Ok(Self(byte)),
171            _ => Err(ErrorKind::TagNumberInvalid.into()),
172        }
173    }
174}
175
176impl From<TagNumber> for u8 {
177    fn from(tag_number: TagNumber) -> u8 {
178        tag_number.0
179    }
180}
181
182impl fmt::Display for TagNumber {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        write!(f, "{}", self.0)
185    }
186}