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    pub const fn new(byte: u8) -> Self {
129        #[allow(clippy::panic)]
130        if byte > Self::MAX {
131            panic!("tag number out of range");
132        }
133
134        Self(byte)
135    }
136
137    /// Create an `APPLICATION` tag with this tag number.
138    pub fn application(self, constructed: bool) -> Tag {
139        Tag::Application {
140            constructed,
141            number: self,
142        }
143    }
144
145    /// Create a `CONTEXT-SPECIFIC` tag with this tag number.
146    pub fn context_specific(self, constructed: bool) -> Tag {
147        Tag::ContextSpecific {
148            constructed,
149            number: self,
150        }
151    }
152
153    /// Create a `PRIVATE` tag with this tag number.
154    pub fn private(self, constructed: bool) -> Tag {
155        Tag::Private {
156            constructed,
157            number: self,
158        }
159    }
160
161    /// Get the inner value.
162    pub fn value(self) -> u8 {
163        self.0
164    }
165}
166
167impl TryFrom<u8> for TagNumber {
168    type Error = Error;
169
170    fn try_from(byte: u8) -> Result<Self> {
171        match byte {
172            0..=Self::MAX => Ok(Self(byte)),
173            _ => Err(ErrorKind::TagNumberInvalid.into()),
174        }
175    }
176}
177
178impl From<TagNumber> for u8 {
179    fn from(tag_number: TagNumber) -> u8 {
180        tag_number.0
181    }
182}
183
184impl fmt::Display for TagNumber {
185    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186        write!(f, "{}", self.0)
187    }
188}
189
190// Implement by hand because the derive would create invalid values.
191// Use the constructor to create a valid value.
192#[cfg(feature = "arbitrary")]
193impl<'a> arbitrary::Arbitrary<'a> for TagNumber {
194    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
195        Ok(Self::new(u.int_in_range(0..=Self::MAX)?))
196    }
197
198    fn size_hint(depth: usize) -> (usize, Option<usize>) {
199        u8::size_hint(depth)
200    }
201}