rasn_derive/
lib.rs

1#[macro_use]
2extern crate quote;
3
4mod asn_type;
5mod config;
6mod decode;
7mod encode;
8mod r#enum;
9mod ext;
10mod tag;
11
12use config::Config;
13use syn::DataStruct;
14
15const CRATE_NAME: &str = "rasn";
16
17/// Helper function print out the derive.
18fn __print_stream(stream: proc_macro2::TokenStream) -> proc_macro::TokenStream {
19    println!("{}", stream);
20    stream.into()
21}
22
23/// An automatic derive of the `Decode` trait.
24///
25/// Will automatically generate a decode implementation using the your
26/// container's definition. See [`AsnType`](`asn_type_derive`) for information
27/// on available attributes.
28#[proc_macro_derive(Decode, attributes(rasn))]
29pub fn decode_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
30    let input = syn::parse_macro_input!(input as syn::DeriveInput);
31    let config = Config::from_attributes(&input);
32    let name = input.ident;
33    let generics = input.generics;
34    let crate_root = &config.crate_root;
35
36    match input.data {
37        // Unit structs are treated as ASN.1 NULL values.
38        syn::Data::Struct(DataStruct {
39            fields: syn::Fields::Unit,
40            ..
41        }) => quote! {
42            impl #crate_root::Decode for #name {
43                fn decode_with_tag_and_constraints<D: #crate_root::Decoder>(
44                    decoder: &mut D,
45                    tag: #crate_root::Tag,
46                    _: #crate_root::prelude::Constraints,
47                ) -> Result<Self, D::Error> {
48                    decoder.decode_null(tag).map(|_| #name)
49                }
50            }
51        },
52        syn::Data::Struct(v) => decode::derive_struct_impl(name, generics, v, &config),
53        syn::Data::Enum(syn::DataEnum { variants, .. }) => r#enum::Enum {
54            name,
55            generics,
56            variants,
57            config,
58        }
59        .impl_decode(),
60        _ => panic!("Union types are not supported."),
61    }
62    .into()
63}
64
65/// An automatic derive of the `Encode` trait.
66///
67/// Will automatically generate a encode implementation using the your
68/// container's definition. See [`AsnType`](`asn_type_derive`) for information
69/// on available attributes.
70#[proc_macro_derive(Encode, attributes(rasn))]
71pub fn encode_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
72    // Parse the input tokens into a syntax tree
73    let input = syn::parse_macro_input!(input as syn::DeriveInput);
74    let config = Config::from_attributes(&input);
75
76    let name = input.ident;
77    let generics = input.generics;
78    let crate_root = &config.crate_root;
79
80    match input.data {
81        // Unit structs are treated as ASN.1 NULL values.
82        syn::Data::Struct(DataStruct {
83            fields: syn::Fields::Unit,
84            ..
85        }) => quote! {
86            impl #crate_root::Encode for #name {
87                fn encode_with_tag_and_constraints<E: #crate_root::Encoder>(
88                    &self,
89                    encoder: &mut E,
90                    tag: #crate_root::Tag,
91                    _: #crate_root::prelude::Constraints,
92                ) -> Result<(), E::Error> {
93                    encoder.encode_null(tag).map(drop)
94                }
95            }
96        },
97        syn::Data::Struct(v) => encode::derive_struct_impl(name, generics, v, &config),
98        syn::Data::Enum(syn::DataEnum { variants, .. }) => r#enum::Enum {
99            name,
100            generics,
101            variants,
102            config,
103        }
104        .impl_encode(),
105        _ => todo!(),
106    }
107    .into()
108}
109
110/// An automatic derive of the `AsnType` trait.
111///
112/// This macro will automatically generate an implementation of `AsnType`,
113/// and generate a *compile-time* check that all of your fields (if struct) or
114/// variants (if a choice style enum) have distinct tags.
115///
116/// ##### Shared Attributes
117/// These attributes are available on containers, variants, and fields.
118/// - *`tag([class], number)`* — override the default tag with the one
119///   specified with this attribute. E.g. `#[rasn(tag(context, 0))]`, you can also
120///   wrapp `[class], number` in `explicit` to mark it as a explicit tag
121///   (e.g.  `#[rasn(tag(explicit(0)))]`.)
122///
123/// ##### Container Attributes
124/// - `crate_root` The path to the `rasn` library to use in the macro.
125/// - `enumerated/choice` Use either `#[rasn(choice)]` or `#[rasn(enumerated)]`
126/// - `delegate` Only available for newtype wrappers (e.g. `struct Delegate(T)`);
127///   uses the inner `T` type for implementing the trait.
128#[proc_macro_derive(AsnType, attributes(rasn))]
129pub fn asn_type_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
130    // Parse the input tokens into a syntax tree
131    let input = syn::parse_macro_input!(input as syn::DeriveInput);
132    let config = Config::from_attributes(&input);
133    let name = input.ident;
134    let generics = input.generics;
135
136    match input.data {
137        syn::Data::Struct(v) => asn_type::derive_struct_impl(name, generics, v, &config),
138        syn::Data::Enum(syn::DataEnum { variants, .. }) => r#enum::Enum {
139            name,
140            generics,
141            variants,
142            config,
143        }
144        .impl_asntype(),
145        _ => panic!("Union types are not supported."),
146    }
147    .into()
148}