#![allow(clippy::too_many_arguments)]
#![allow(clippy::needless_late_init)]
use proc_macro::TokenStream;
#[cfg(feature = "test")]
mod benchmarker;
mod de;
mod en;
mod expander;
mod internals;
#[cfg(feature = "test")]
mod test;
mod types;
#[proc_macro_derive(Encode, attributes(musli))]
pub fn derive_encode(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let expander = expander::Expander::new(&input);
let dump = std::env::var("MUSLI_DUMP_ENCODE").ok();
match expander.expand_encode() {
Ok(tokens) => {
if let Some((dump, out)) = dump.as_ref().and_then(|d| d.split_once('=')) {
if input.ident.to_string().contains(dump) {
let _ = std::fs::write(out, format!("{}", tokens));
}
}
tokens.into()
}
Err(()) => to_compile_errors(expander.into_errors()).into(),
}
}
#[proc_macro_derive(Decode, attributes(musli))]
pub fn derive_decode(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let expander = expander::Expander::new(&input);
let dump = std::env::var("MUSLI_DUMP_DECODE").ok();
match expander.expand_decode() {
Ok(tokens) => {
if let Some((dump, out)) = dump.as_ref().and_then(|d| d.split_once('=')) {
if input.ident.to_string().contains(dump) {
let _ = std::fs::write(out, format!("{}", tokens));
}
}
tokens.into()
}
Err(()) => to_compile_errors(expander.into_errors()).into(),
}
}
#[proc_macro_attribute]
pub fn decoder(attr: TokenStream, input: TokenStream) -> TokenStream {
let attr = syn::parse_macro_input!(attr as types::Attr);
let input = syn::parse_macro_input!(input as types::Types);
match input.expand(
&attr,
"decoder",
types::DECODER_TYPES,
types::DECODER_FNS,
None,
"__UseMusliDecoderAttributeMacro",
types::Kind::SelfCx,
) {
Ok(tokens) => tokens.into(),
Err(err) => err.to_compile_error().into(),
}
}
#[proc_macro_attribute]
pub fn encoder(attr: TokenStream, input: TokenStream) -> TokenStream {
let attr = syn::parse_macro_input!(attr as types::Attr);
let input = syn::parse_macro_input!(input as types::Types);
match input.expand(
&attr,
"encoder",
types::ENCODER_TYPES,
&[],
Some("Ok"),
"__UseMusliEncoderAttributeMacro",
types::Kind::SelfCx,
) {
Ok(tokens) => tokens.into(),
Err(err) => err.to_compile_error().into(),
}
}
#[proc_macro_attribute]
pub fn visitor(attr: TokenStream, input: TokenStream) -> TokenStream {
let attr = syn::parse_macro_input!(attr as types::Attr);
let input = syn::parse_macro_input!(input as types::Types);
match input.expand(
&attr,
"visitor",
types::VISITOR_TYPES,
&[],
Some("Ok"),
"__UseMusliVisitorAttributeMacro",
types::Kind::GenericCx,
) {
Ok(tokens) => tokens.into(),
Err(err) => err.to_compile_error().into(),
}
}
fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
let mut output = proc_macro2::TokenStream::new();
for e in errors {
output.extend(e.to_compile_error());
}
output
}
#[cfg(feature = "test")]
#[proc_macro_derive(Generate, attributes(generate))]
pub fn derive_generate(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let mut cx = test::Ctxt::default();
if let Ok(stream) = test::expand(&mut cx, input) {
return stream.into();
}
let mut stream = proc_macro2::TokenStream::default();
for error in cx.errors {
stream.extend(error.to_compile_error());
}
stream.into()
}
#[cfg(feature = "test")]
#[proc_macro_attribute]
pub fn benchmarker(attr: TokenStream, input: TokenStream) -> TokenStream {
let attrs = syn::parse_macro_input!(attr as benchmarker::Attributes);
let input = syn::parse_macro_input!(input as benchmarker::Benchmarker);
match input.expand(&attrs) {
Ok(tokens) => tokens.into(),
Err(err) => err.to_compile_error().into(),
}
}