1use proc_macro::TokenStream as TokenStream1;
2
3use proc_macro2::{Ident, Span};
4use quote::quote;
5use syn::{parse_macro_input, parse_quote, DeriveInput, GenericParam};
6
7use crate::ctxt::{Ctxt, Target};
8
9mod ctxt;
10mod enums;
11mod flags;
12mod generator;
13mod lifetime;
14mod parse;
15
16static ENDER: &str = "ender";
17
18fn dollar_crate(name: &str) -> Ident {
20 let crate_name = std::env::var("CARGO_PKG_NAME").expect("Can't obtain current crate name");
21 Ident::new(
22 &if crate_name == name {
23 "crate".to_owned()
24 } else {
25 name.replace("-", "_")
26 },
27 Span::call_site(),
28 )
29}
30
31#[proc_macro_derive(Encode, attributes(ender))]
32pub fn encode(input: TokenStream1) -> TokenStream1 {
33 let input = parse_macro_input!(input as DeriveInput);
34 let ctxt = match Ctxt::parse_from(&input, Target::Encode) {
35 Ok(ctxt) => ctxt,
36 Err(err) => return TokenStream1::from(err.to_compile_error()),
37 };
38
39 let ref encoder_generic = ctxt.encoder_generic;
40 let ref crate_name = ctxt.flags.crate_name;
41 let type_param = if ctxt.requires_seeking_impl() {
42 parse_quote!(#encoder_generic: #crate_name::io::Write + #crate_name::io::Seek)
43 } else {
44 parse_quote!(#encoder_generic: #crate_name::io::Write)
45 };
46
47 let mut generics = ctxt.generics.clone();
49 generics.params.push(GenericParam::Type(type_param));
50
51 let (impl_generics, _, _) = generics.split_for_impl();
53 let (_, ty_generics, where_clause) = ctxt.generics.split_for_impl();
55 let ref item_name = ctxt.item_name;
56 let ref encoder = ctxt.encoder;
57
58 let body = match ctxt.derive() {
59 Ok(ctxt) => ctxt,
60 Err(err) => return TokenStream1::from(err.to_compile_error()),
61 };
62
63 quote!(
64 #[automatically_derived]
65 #[allow(unused)]
66 #[allow(dead_code)]
67 impl #impl_generics #crate_name::Encode<#encoder_generic> for #item_name #ty_generics #where_clause {
68 fn encode(&self, #encoder: &mut #crate_name::Encoder<#encoder_generic>) -> #crate_name::EncodingResult<()> {
69 #body
70 }
71 }
72 ).into()
73}
74
75#[proc_macro_derive(Decode, attributes(ender))]
76pub fn decode(input: TokenStream1) -> TokenStream1 {
77 let input = parse_macro_input!(input as DeriveInput);
78 let ctxt = match Ctxt::parse_from(&input, Target::Decode) {
79 Ok(ctxt) => ctxt,
80 Err(err) => return TokenStream1::from(err.to_compile_error()),
81 };
82
83 let ref encoder_generic = ctxt.encoder_generic;
84 let ref crate_name = ctxt.flags.crate_name;
85 let ref decoder_lif = ctxt.borrow_data.decoder;
86
87 let type_param = if ctxt.requires_borrowing_impl() {
88 if ctxt.requires_seeking_impl() {
89 parse_quote!(#encoder_generic: #crate_name::io::BorrowRead<#decoder_lif> + #crate_name::io::Seek)
90 } else {
91 parse_quote!(#encoder_generic: #crate_name::io::BorrowRead<#decoder_lif>)
92 }
93 } else {
94 if ctxt.requires_seeking_impl() {
95 parse_quote!(#encoder_generic: #crate_name::io::Read + #crate_name::io::Seek)
96 } else {
97 parse_quote!(#encoder_generic: #crate_name::io::Read)
98 }
99 };
100
101 let lif = if ctxt.borrow_data.sub_lifetimes.is_empty() {
102 parse_quote!(
103 #decoder_lif
104 )
105 } else {
106 let sub_lifs = ctxt.borrow_data.sub_lifetimes.iter();
107 parse_quote!(
108 #decoder_lif: #(#sub_lifs)+*
109 )
110 };
111
112 let mut generics = ctxt.generics.clone();
114 generics.params.push(GenericParam::Type(type_param));
115 if ctxt.requires_borrowing_impl() {
116 generics.params.insert(0, GenericParam::Lifetime(lif));
117 }
118
119 let (impl_generics, _, _) = generics.split_for_impl();
121 let (_, ty_generics, where_clause) = ctxt.generics.split_for_impl();
123 let ref item_name = ctxt.item_name;
124 let ref encoder = ctxt.encoder;
125
126 let body = match ctxt.derive() {
127 Ok(ctxt) => ctxt,
128 Err(err) => return TokenStream1::from(err.to_compile_error()),
129 };
130
131 quote!(
132 #[automatically_derived]
133 #[allow(unused)]
134 #[allow(dead_code)]
135 impl #impl_generics #crate_name::Decode<#encoder_generic> for #item_name #ty_generics #where_clause {
136 fn decode(#encoder: &mut #crate_name::Encoder<#encoder_generic>) -> #crate_name::EncodingResult<Self> {
137 #body
138 }
139 }
140 ).into()
141}