1//! ASN.1 tag numbers
23use super::Tag;
4use crate::{Error, ErrorKind, Result};
5use core::fmt;
67/// 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);
2324impl TagNumber {
25/// Tag number `0`
26pub const N0: Self = Self(0);
2728/// Tag number `1`
29pub const N1: Self = Self(1);
3031/// Tag number `2`
32pub const N2: Self = Self(2);
3334/// Tag number `3`
35pub const N3: Self = Self(3);
3637/// Tag number `4`
38pub const N4: Self = Self(4);
3940/// Tag number `5`
41pub const N5: Self = Self(5);
4243/// Tag number `6`
44pub const N6: Self = Self(6);
4546/// Tag number `7`
47pub const N7: Self = Self(7);
4849/// Tag number `8`
50pub const N8: Self = Self(8);
5152/// Tag number `9`
53pub const N9: Self = Self(9);
5455/// Tag number `10`
56pub const N10: Self = Self(10);
5758/// Tag number `11`
59pub const N11: Self = Self(11);
6061/// Tag number `12`
62pub const N12: Self = Self(12);
6364/// Tag number `13`
65pub const N13: Self = Self(13);
6667/// Tag number `14`
68pub const N14: Self = Self(14);
6970/// Tag number `15`
71pub const N15: Self = Self(15);
7273/// Tag number `16`
74pub const N16: Self = Self(16);
7576/// Tag number `17`
77pub const N17: Self = Self(17);
7879/// Tag number `18`
80pub const N18: Self = Self(18);
8182/// Tag number `19`
83pub const N19: Self = Self(19);
8485/// Tag number `20`
86pub const N20: Self = Self(20);
8788/// Tag number `21`
89pub const N21: Self = Self(21);
9091/// Tag number `22`
92pub const N22: Self = Self(22);
9394/// Tag number `23`
95pub const N23: Self = Self(23);
9697/// Tag number `24`
98pub const N24: Self = Self(24);
99100/// Tag number `25`
101pub const N25: Self = Self(25);
102103/// Tag number `26`
104pub const N26: Self = Self(26);
105106/// Tag number `27`
107pub const N27: Self = Self(27);
108109/// Tag number `28`
110pub const N28: Self = Self(28);
111112/// Tag number `29`
113pub const N29: Self = Self(29);
114115/// Tag number `30`
116pub const N30: Self = Self(30);
117118/// Mask value used to obtain the tag number from a tag octet.
119pub(super) const MASK: u8 = 0b11111;
120121/// Maximum tag number supported (inclusive).
122const MAX: u8 = 30;
123124/// 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.
128pub const fn new(byte: u8) -> Self {
129#[allow(clippy::panic)]
130if byte > Self::MAX {
131panic!("tag number out of range");
132 }
133134Self(byte)
135 }
136137/// Create an `APPLICATION` tag with this tag number.
138pub fn application(self, constructed: bool) -> Tag {
139 Tag::Application {
140 constructed,
141 number: self,
142 }
143 }
144145/// Create a `CONTEXT-SPECIFIC` tag with this tag number.
146pub fn context_specific(self, constructed: bool) -> Tag {
147 Tag::ContextSpecific {
148 constructed,
149 number: self,
150 }
151 }
152153/// Create a `PRIVATE` tag with this tag number.
154pub fn private(self, constructed: bool) -> Tag {
155 Tag::Private {
156 constructed,
157 number: self,
158 }
159 }
160161/// Get the inner value.
162pub fn value(self) -> u8 {
163self.0
164}
165}
166167impl TryFrom<u8> for TagNumber {
168type Error = Error;
169170fn try_from(byte: u8) -> Result<Self> {
171match byte {
1720..=Self::MAX => Ok(Self(byte)),
173_ => Err(ErrorKind::TagNumberInvalid.into()),
174 }
175 }
176}
177178impl From<TagNumber> for u8 {
179fn from(tag_number: TagNumber) -> u8 {
180 tag_number.0
181}
182}
183184impl fmt::Display for TagNumber {
185fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186write!(f, "{}", self.0)
187 }
188}
189190// 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 {
194fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
195Ok(Self::new(u.int_in_range(0..=Self::MAX)?))
196 }
197198fn size_hint(depth: usize) -> (usize, Option<usize>) {
199 u8::size_hint(depth)
200 }
201}