1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//! Custom derive support for the [`der`] crate.
//!
//! This crate contains custom derive macros intended to be used in the
//! following way:
//!
//! - [`Decodable`][`derive@Decodable`] and [`Encodable`][`derive@Encodable`]:
//!   for representing ASN.1 `CHOICE` as a Rust enum
//! - [`Message`][`derive@Message`]: for representing ASN.1 `SEQUENCE` as a Rust struct
//!
//! Note that this crate shouldn't be used directly, but instead accessed
//! by using the `derive` feature of the `der` crate.
//!
//! # `#[asn1(type = "...")]` attribute
//!
//! This attribute can be used to specify the ASN.1 type for a particular
//! enum variant or struct field.
//!
//! It's presently mandatory for all struct fields, even when using one of the
//! ASN.1 types defined by this crate.
//!
//! For structs, placing this attribute on a field makes it possible to
//! decode/encode types which don't directly implement the `Decode`/`Encode`
//! traits but do impl `From` and `TryInto` and `From` for one of the ASN.1 types
//! listed below (use the ASN.1 type keywords as the `type`):
//!
//! - `BIT STRING`: performs an intermediate conversion to [`der::BitString`]
//! - `GeneralizedTime`: performs an intermediate conversion to [`der::GeneralizedTime`]
//! - `OCTET STRING`: performs an intermediate conversion to [`der::OctetString`]
//! - `PrintableString`: performs an intermediate conversion to [`der::PrintableString`]
//! - `UTCTime`: performs an intermediate conversion to [`der::UtcTime`]
//! - `UTF8String`: performs an intermediate conversion to [`der::Utf8String`]
//!
//! Example:
//!
//! ```ignore
//! // NOTE: requires the `derive` feature of `der`
//! use der::{Decodable, Encodable};
//!
//! /// `Time` as defined in RFC 5280
//! #[derive(Decodable, Encodable)]
//! pub enum Time {
//!     #[asn1(type = "UTCTime")]
//!     UtcTime(UtcTime),
//!
//!     #[asn1(type = "GeneralizedTime")]
//!     GeneralTime(GeneralizedTime),
//! }
//! ```
//!
//! Note: please open a GitHub Issue if you would like to request support
//! for additional ASN.1 types.
//!
//! [`der`]: https://docs.rs/der/
//! [`der::BitString`]: https://docs.rs/der/latest/der/struct.BitString.html
//! [`der::GeneralizedTime`]: https://docs.rs/der/latest/der/struct.GeneralizedTime.html
//! [`der::OctetString`]: https://docs.rs/der/latest/der/struct.OctetString.html
//! [`der::PrintableString`]: https://docs.rs/der/latest/der/struct.PrintableString.html
//! [`der::UtcTime`]: https://docs.rs/der/latest/der/struct.UtcTime.html
//! [`der::Utf8String`]: https://docs.rs/der/latest/der/struct.Utf8String.html

#![crate_type = "proc-macro"]
#![warn(rust_2018_idioms, trivial_casts, unused_qualifications)]

mod attributes;
mod choice;
mod sequence;
mod types;

use crate::{
    attributes::Asn1Attrs,
    choice::{DeriveDecodableForEnum, DeriveEncodableForEnum},
    sequence::DeriveMessageForStruct,
    types::Asn1Type,
};
use proc_macro2::TokenStream;
use syn::{Generics, Lifetime};
use synstructure::{decl_derive, Structure};

decl_derive!(
    [Decodable, attributes(asn1)] =>

    /// Derive the [`Decodable`][1] trait on an enum.
    ///
    /// This custom derive macro can be used to automatically impl the
    /// `Decodable` trait for any enum representing a message which is
    /// encoded as an ASN.1 `CHOICE`.
    ///
    /// See [toplevel documentation for the `der_derive` crate][2] for more
    /// information about how to use this macro.
    ///
    /// [1]: https://docs.rs/der/latest/der/trait.Decodable.html
    /// [2]: https://docs.rs/der_derive/
    derive_decodable
);

decl_derive!(
    [Encodable, attributes(asn1)] =>

    /// Derive the [`Encodable`][1] trait on an enum.
    ///
    /// This custom derive macro can be used to automatically impl the
    /// `Decodable` trait for any enum representing a message which is
    /// encoded as an ASN.1 `CHOICE`.
    ///
    /// See [toplevel documentation for the `der_derive` crate][2] for more
    /// information about how to use this macro.
    ///
    /// [1]: https://docs.rs/der/latest/der/trait.Encodable.html
    /// [2]: https://docs.rs/der_derive/
    derive_encodable
);

decl_derive!(
    [Message, attributes(asn1)] =>

    /// Derive the [`Message`][1] trait on a struct.
    ///
    /// This custom derive macro can be used to automatically impl the
    /// `Message` trait for any struct representing a message which is
    /// encoded as an ASN.1 `SEQUENCE`.
    ///
    /// See [toplevel documentation for the `der_derive` crate][2] for more
    /// information about how to use this macro.
    ///
    /// [1]: https://docs.rs/der/latest/der/trait.Message.html
    /// [2]: https://docs.rs/der_derive/
    derive_message
);

/// Custom derive for `der::Decodable`
fn derive_decodable(s: Structure<'_>) -> TokenStream {
    let ast = s.ast();
    let lifetime = parse_lifetime(&ast.generics);

    match &ast.data {
        syn::Data::Enum(data) => DeriveDecodableForEnum::derive(s, data, lifetime),
        other => panic!("can't derive `Decodable` on: {:?}", other),
    }
}

/// Custom derive for `der::Encodable`
fn derive_encodable(s: Structure<'_>) -> TokenStream {
    let ast = s.ast();

    match &ast.data {
        syn::Data::Enum(data) => DeriveEncodableForEnum::derive(s, data),
        other => panic!("can't derive `Encodable` on: {:?}", other),
    }
}

/// Custom derive for `der::Message`
fn derive_message(s: Structure<'_>) -> TokenStream {
    let ast = s.ast();
    let lifetime = parse_lifetime(&ast.generics);

    match &ast.data {
        syn::Data::Struct(data) => DeriveMessageForStruct::derive(s, data, lifetime),
        other => panic!("can't derive `Message` on: {:?}", other),
    }
}

/// Parse the first lifetime of the "self" type of the custom derive
///
/// Returns `None` if there is no first lifetime.
fn parse_lifetime(generics: &Generics) -> Option<&Lifetime> {
    generics
        .lifetimes()
        .next()
        .map(|ref lt_ref| &lt_ref.lifetime)
}