der_derive/
asn1_type.rs

1//! ASN.1 types supported by the proc macro
2
3use proc_macro2::TokenStream;
4use quote::quote;
5use std::{fmt, str::FromStr};
6
7/// ASN.1 built-in types supported by the `#[asn1(type = "...")]` attribute
8// TODO(tarcieri): support all ASN.1 types specified in `der::Tag`
9#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
10pub(crate) enum Asn1Type {
11    /// ASN.1 `BIT STRING`.
12    BitString,
13
14    /// ASN.1 `IA5String`.
15    Ia5String,
16
17    /// ASN.1 `GeneralizedTime`.
18    GeneralizedTime,
19
20    /// ASN.1 `OCTET STRING`.
21    OctetString,
22
23    /// ASN.1 `PrintableString`.
24    PrintableString,
25
26    /// ASN.1 `TeletexString`.
27    TeletexString,
28
29    /// ASN.1 `VideotexString`.
30    VideotexString,
31
32    /// ASN.1 `UTCTime`.
33    UtcTime,
34
35    /// ASN.1 `UTF8String`.
36    Utf8String,
37}
38
39impl Asn1Type {
40    /// Get the `::der::Tag` for this ASN.1 type
41    pub fn tag(self) -> TokenStream {
42        match self {
43            Asn1Type::BitString => quote!(::der::Tag::BitString),
44            Asn1Type::Ia5String => quote!(::der::Tag::Ia5String),
45            Asn1Type::GeneralizedTime => quote!(::der::Tag::GeneralizedTime),
46            Asn1Type::OctetString => quote!(::der::Tag::OctetString),
47            Asn1Type::PrintableString => quote!(::der::Tag::PrintableString),
48            Asn1Type::TeletexString => quote!(::der::Tag::TeletexString),
49            Asn1Type::VideotexString => quote!(::der::Tag::VideotexString),
50            Asn1Type::UtcTime => quote!(::der::Tag::UtcTime),
51            Asn1Type::Utf8String => quote!(::der::Tag::Utf8String),
52        }
53    }
54
55    /// Get a `der::Decoder` object for a particular ASN.1 type
56    pub fn decoder(self) -> TokenStream {
57        match self {
58            Asn1Type::BitString => quote!(::der::asn1::BitStringRef::decode(reader)?),
59            Asn1Type::Ia5String => quote!(::der::asn1::Ia5StringRef::decode(reader)?),
60            Asn1Type::GeneralizedTime => quote!(::der::asn1::GeneralizedTime::decode(reader)?),
61            Asn1Type::OctetString => quote!(::der::asn1::OctetStringRef::decode(reader)?),
62            Asn1Type::PrintableString => quote!(::der::asn1::PrintableStringRef::decode(reader)?),
63            Asn1Type::TeletexString => quote!(::der::asn1::TeletexStringRef::decode(reader)?),
64            Asn1Type::VideotexString => quote!(::der::asn1::VideotexStringRef::decode(reader)?),
65            Asn1Type::UtcTime => quote!(::der::asn1::UtcTime::decode(reader)?),
66            Asn1Type::Utf8String => quote!(::der::asn1::Utf8StringRef::decode(reader)?),
67        }
68    }
69
70    /// Get a `der::Encoder` object for a particular ASN.1 type
71    pub fn encoder(self, binding: &TokenStream) -> TokenStream {
72        let type_path = self.type_path();
73
74        match self {
75            Asn1Type::Ia5String
76            | Asn1Type::OctetString
77            | Asn1Type::PrintableString
78            | Asn1Type::TeletexString
79            | Asn1Type::VideotexString
80            | Asn1Type::Utf8String => quote!(#type_path::new(#binding)?),
81            _ => quote!(#type_path::try_from(#binding)?),
82        }
83    }
84
85    /// Get the Rust type path for a particular ASN.1 type.
86    /// Get a `der::Encoder` object for a particular ASN.1 type
87    pub fn type_path(self) -> TokenStream {
88        match self {
89            Asn1Type::BitString => quote!(::der::asn1::BitStringRef),
90            Asn1Type::Ia5String => quote!(::der::asn1::Ia5StringRef),
91            Asn1Type::GeneralizedTime => quote!(::der::asn1::GeneralizedTime),
92            Asn1Type::OctetString => quote!(::der::asn1::OctetStringRef),
93            Asn1Type::PrintableString => quote!(::der::asn1::PrintableStringRef),
94            Asn1Type::TeletexString => quote!(::der::asn1::TeletexStringRef),
95            Asn1Type::VideotexString => quote!(::der::asn1::VideotexStringRef),
96            Asn1Type::UtcTime => quote!(::der::asn1::UtcTime),
97            Asn1Type::Utf8String => quote!(::der::asn1::Utf8StringRef),
98        }
99    }
100}
101
102impl FromStr for Asn1Type {
103    type Err = ParseError;
104
105    fn from_str(s: &str) -> Result<Self, ParseError> {
106        match s {
107            "BIT STRING" => Ok(Self::BitString),
108            "IA5String" => Ok(Self::Ia5String),
109            "GeneralizedTime" => Ok(Self::GeneralizedTime),
110            "OCTET STRING" => Ok(Self::OctetString),
111            "PrintableString" => Ok(Self::PrintableString),
112            "TeletexString" => Ok(Self::TeletexString),
113            "VideotexString" => Ok(Self::VideotexString),
114            "UTCTime" => Ok(Self::UtcTime),
115            "UTF8String" => Ok(Self::Utf8String),
116            _ => Err(ParseError),
117        }
118    }
119}
120
121impl fmt::Display for Asn1Type {
122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123        f.write_str(match self {
124            Asn1Type::BitString => "BIT STRING",
125            Asn1Type::Ia5String => "IA5String",
126            Asn1Type::GeneralizedTime => "GeneralizedTime",
127            Asn1Type::OctetString => "OCTET STRING",
128            Asn1Type::PrintableString => "PrintableString",
129            Asn1Type::TeletexString => "TeletexString",
130            Asn1Type::VideotexString => "VideotexString",
131            Asn1Type::UtcTime => "UTCTime",
132            Asn1Type::Utf8String => "UTF8String",
133        })
134    }
135}
136
137/// Error type
138#[derive(Debug)]
139pub(crate) struct ParseError;