experiment_codec_derive/
lib.rs1extern crate proc_macro;
18use proc_macro2;
19
20#[macro_use]
21extern crate syn;
22
23#[macro_use]
24extern crate quote;
25
26use proc_macro::TokenStream;
27use proc_macro2::Span;
28use syn::{DeriveInput, Ident, parse::Error};
29use proc_macro_crate::crate_name;
30
31use std::env;
32
33mod decode;
34mod encode;
35mod utils;
36mod trait_bounds;
37
38fn include_susy_codec_crate() -> proc_macro2::TokenStream {
40 if env::var("CARGO_PKG_NAME").unwrap() == "experiment-codec" {
42 quote!( extern crate susy_codec as _susy_codec; )
43 } else {
44 match crate_name("experiment-codec") {
45 Ok(susy_codec_crate) => {
46 let ident = Ident::new(&susy_codec_crate, Span::call_site());
47 quote!( extern crate #ident as _susy_codec; )
48 },
49 Err(e) => Error::new(Span::call_site(), &e).to_compile_error(),
50 }
51 }
52}
53
54#[proc_macro_derive(Encode, attributes(codec))]
55pub fn encode_derive(input: TokenStream) -> TokenStream {
56 let mut input: DeriveInput = match syn::parse(input) {
57 Ok(input) => input,
58 Err(e) => return e.to_compile_error().into(),
59 };
60
61 if let Err(e) = trait_bounds::add(
62 &input.ident,
63 &mut input.generics,
64 &input.data,
65 parse_quote!(_susy_codec::Encode)
66 ) {
67 return e.to_compile_error().into();
68 }
69
70 let name = &input.ident;
71 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
72
73 let self_ = quote!(self);
74 let dest_ = quote!(dest);
75 let encoding = encode::quote(&input.data, name, &self_, &dest_);
76
77 let impl_block = quote! {
78 impl #impl_generics _susy_codec::Encode for #name #ty_generics #where_clause {
79 fn encode_to<EncOut: _susy_codec::Output>(&#self_, #dest_: &mut EncOut) {
80 #encoding
81 }
82 }
83 };
84
85 let mut new_name = "_IMPL_ENCODE_FOR_".to_string();
86 new_name.push_str(name.to_string().trim_start_matches("r#"));
87 let dummy_const = Ident::new(&new_name, Span::call_site());
88 let susy_codec_crate = include_susy_codec_crate();
89
90 let generated = quote! {
91 #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
92 const #dummy_const: () = {
93 #[allow(unknown_lints)]
94 #[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
95 #[allow(rust_2018_idioms)]
96 #susy_codec_crate
97 #impl_block
98 };
99 };
100
101 generated.into()
102}
103
104#[proc_macro_derive(Decode, attributes(codec))]
105pub fn decode_derive(input: TokenStream) -> TokenStream {
106 let mut input: DeriveInput = match syn::parse(input) {
107 Ok(input) => input,
108 Err(e) => return e.to_compile_error().into(),
109 };
110
111 if let Err(e) = trait_bounds::add(
112 &input.ident,
113 &mut input.generics,
114 &input.data,
115 parse_quote!(_susy_codec::Decode),
116 ) {
117 return e.to_compile_error().into();
118 }
119
120 let name = &input.ident;
121 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
122
123 let input_ = quote!(input);
124 let decoding = decode::quote(&input.data, name, &input_);
125
126 let impl_block = quote! {
127 impl #impl_generics _susy_codec::Decode for #name #ty_generics #where_clause {
128 fn decode<DecIn: _susy_codec::Input>(#input_: &mut DecIn) -> Option<Self> {
129 #decoding
130 }
131 }
132 };
133
134 let mut new_name = "_IMPL_DECODE_FOR_".to_string();
135 new_name.push_str(name.to_string().trim_start_matches("r#"));
136 let dummy_const = Ident::new(&new_name, Span::call_site());
137 let susy_codec_crate = include_susy_codec_crate();
138
139 let generated = quote! {
140 #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
141 const #dummy_const: () = {
142 #[allow(unknown_lints)]
143 #[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
144 #[allow(rust_2018_idioms)]
145 #susy_codec_crate
146 #impl_block
147 };
148 };
149
150 generated.into()
151}