der_derive/
tag.rs

1//! Tag-related functionality.
2
3use crate::Asn1Type;
4use proc_macro2::TokenStream;
5use quote::quote;
6use std::{
7    fmt::{self, Display},
8    str::FromStr,
9};
10
11/// Tag "IR" type.
12#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
13pub(crate) enum Tag {
14    /// Universal tags with an associated [`Asn1Type`].
15    Universal(Asn1Type),
16
17    /// Context-specific tags with an associated [`TagNumber`].
18    ContextSpecific {
19        /// Is the inner ASN.1 type constructed?
20        constructed: bool,
21
22        /// Context-specific tag number
23        number: TagNumber,
24    },
25}
26
27impl Tag {
28    /// Lower this [`Tag`] to a [`TokenStream`].
29    pub fn to_tokens(self) -> TokenStream {
30        match self {
31            Tag::Universal(ty) => ty.tag(),
32            Tag::ContextSpecific {
33                constructed,
34                number,
35            } => {
36                let constructed = if constructed {
37                    quote!(true)
38                } else {
39                    quote!(false)
40                };
41
42                let number = number.to_tokens();
43
44                quote! {
45                    ::der::Tag::ContextSpecific {
46                        constructed: #constructed,
47                        number: #number,
48                    }
49                }
50            }
51        }
52    }
53}
54
55/// Tagging modes: `EXPLICIT` versus `IMPLICIT`.
56#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
57pub(crate) enum TagMode {
58    /// `EXPLICIT` tagging.
59    ///
60    /// Tag is added in addition to the inner tag of the type.
61    #[default]
62    Explicit,
63
64    /// `IMPLICIT` tagging.
65    ///
66    /// Tag replaces the existing tag of the inner type.
67    Implicit,
68}
69
70impl TagMode {
71    /// Lower this [`TagMode`] to a [`TokenStream`] with the `der`
72    /// crate's corresponding enum variant for this tag mode.
73    pub fn to_tokens(self) -> TokenStream {
74        match self {
75            TagMode::Explicit => quote!(::der::TagMode::Explicit),
76            TagMode::Implicit => quote!(::der::TagMode::Implicit),
77        }
78    }
79}
80
81impl FromStr for TagMode {
82    type Err = ParseError;
83
84    fn from_str(s: &str) -> Result<Self, ParseError> {
85        match s {
86            "EXPLICIT" | "explicit" => Ok(TagMode::Explicit),
87            "IMPLICIT" | "implicit" => Ok(TagMode::Implicit),
88            _ => Err(ParseError),
89        }
90    }
91}
92
93impl Display for TagMode {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        match self {
96            TagMode::Explicit => f.write_str("EXPLICIT"),
97            TagMode::Implicit => f.write_str("IMPLICIT"),
98        }
99    }
100}
101
102/// ASN.1 tag numbers (i.e. lower 5 bits of a [`Tag`]).
103#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
104pub(crate) struct TagNumber(pub u8);
105
106impl TagNumber {
107    /// Maximum tag number supported (inclusive).
108    pub const MAX: u8 = 30;
109
110    /// Get tokens describing this tag.
111    pub fn to_tokens(self) -> TokenStream {
112        match self.0 {
113            0 => quote!(::der::TagNumber::N0),
114            1 => quote!(::der::TagNumber::N1),
115            2 => quote!(::der::TagNumber::N2),
116            3 => quote!(::der::TagNumber::N3),
117            4 => quote!(::der::TagNumber::N4),
118            5 => quote!(::der::TagNumber::N5),
119            6 => quote!(::der::TagNumber::N6),
120            7 => quote!(::der::TagNumber::N7),
121            8 => quote!(::der::TagNumber::N8),
122            9 => quote!(::der::TagNumber::N9),
123            10 => quote!(::der::TagNumber::N10),
124            11 => quote!(::der::TagNumber::N11),
125            12 => quote!(::der::TagNumber::N12),
126            13 => quote!(::der::TagNumber::N13),
127            14 => quote!(::der::TagNumber::N14),
128            15 => quote!(::der::TagNumber::N15),
129            16 => quote!(::der::TagNumber::N16),
130            17 => quote!(::der::TagNumber::N17),
131            18 => quote!(::der::TagNumber::N18),
132            19 => quote!(::der::TagNumber::N19),
133            20 => quote!(::der::TagNumber::N20),
134            21 => quote!(::der::TagNumber::N21),
135            22 => quote!(::der::TagNumber::N22),
136            23 => quote!(::der::TagNumber::N23),
137            24 => quote!(::der::TagNumber::N24),
138            25 => quote!(::der::TagNumber::N25),
139            26 => quote!(::der::TagNumber::N26),
140            27 => quote!(::der::TagNumber::N27),
141            28 => quote!(::der::TagNumber::N28),
142            29 => quote!(::der::TagNumber::N29),
143            30 => quote!(::der::TagNumber::N30),
144            _ => unreachable!("tag number out of range: {}", self),
145        }
146    }
147}
148
149impl FromStr for TagNumber {
150    type Err = ParseError;
151
152    fn from_str(s: &str) -> Result<Self, ParseError> {
153        let n = s.parse::<u8>().map_err(|_| ParseError)?;
154
155        if n <= Self::MAX {
156            Ok(Self(n))
157        } else {
158            Err(ParseError)
159        }
160    }
161}
162
163impl Display for TagNumber {
164    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165        write!(f, "{}", self.0)
166    }
167}
168
169/// Error type
170#[derive(Debug)]
171pub(crate) struct ParseError;