1 //! ASN.1 tag numbers
2 
3 use super::Tag;
4 use crate::{Error, ErrorKind, Result};
5 use 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)]
22 pub struct TagNumber(pub(super) u8);
23 
24 impl 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.
new(byte: u8) -> Self128     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.
application(self, constructed: bool) -> Tag138     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.
context_specific(self, constructed: bool) -> Tag146     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.
private(self, constructed: bool) -> Tag154     pub fn private(self, constructed: bool) -> Tag {
155         Tag::Private {
156             constructed,
157             number: self,
158         }
159     }
160 
161     /// Get the inner value.
value(self) -> u8162     pub fn value(self) -> u8 {
163         self.0
164     }
165 }
166 
167 impl TryFrom<u8> for TagNumber {
168     type Error = Error;
169 
try_from(byte: u8) -> Result<Self>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 
178 impl From<TagNumber> for u8 {
from(tag_number: TagNumber) -> u8179     fn from(tag_number: TagNumber) -> u8 {
180         tag_number.0
181     }
182 }
183 
184 impl fmt::Display for TagNumber {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result185     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")]
193 impl<'a> arbitrary::Arbitrary<'a> for TagNumber {
arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self>194     fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
195         Ok(Self::new(u.int_in_range(0..=Self::MAX)?))
196     }
197 
size_hint(depth: usize) -> (usize, Option<usize>)198     fn size_hint(depth: usize) -> (usize, Option<usize>) {
199         u8::size_hint(depth)
200     }
201 }
202