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.
128#[allow(clippy::no_effect)]
129pub 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];
132Self(byte)
133 }
134135/// Create an `APPLICATION` tag with this tag number.
136pub fn application(self, constructed: bool) -> Tag {
137 Tag::Application {
138 constructed,
139 number: self,
140 }
141 }
142143/// Create a `CONTEXT-SPECIFIC` tag with this tag number.
144pub fn context_specific(self, constructed: bool) -> Tag {
145 Tag::ContextSpecific {
146 constructed,
147 number: self,
148 }
149 }
150151/// Create a `PRIVATE` tag with this tag number.
152pub fn private(self, constructed: bool) -> Tag {
153 Tag::Private {
154 constructed,
155 number: self,
156 }
157 }
158159/// Get the inner value.
160pub fn value(self) -> u8 {
161self.0
162}
163}
164165impl TryFrom<u8> for TagNumber {
166type Error = Error;
167168fn try_from(byte: u8) -> Result<Self> {
169match byte {
1700..=Self::MAX => Ok(Self(byte)),
171_ => Err(ErrorKind::TagNumberInvalid.into()),
172 }
173 }
174}
175176impl From<TagNumber> for u8 {
177fn from(tag_number: TagNumber) -> u8 {
178 tag_number.0
179}
180}
181182impl fmt::Display for TagNumber {
183fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184write!(f, "{}", self.0)
185 }
186}