1#![allow(clippy::too_many_arguments)]
17#![allow(clippy::needless_late_init)]
18#![allow(clippy::type_complexity)]
19#![allow(missing_docs)]
20
21mod de;
22mod en;
23mod expander;
24mod internals;
25mod types;
26
27use proc_macro::TokenStream;
28use quote::ToTokens;
29use syn::parse::ParseStream;
30
31const MUSLI_CRATE: &str = "musli";
32const MUSLI_CORE_CRATE: &str = "musli_core";
33
34#[proc_macro_derive(Encode, attributes(musli))]
35#[doc(hidden)]
36pub fn musli_derive_encode(input: TokenStream) -> TokenStream {
37 derive_encode(input, MUSLI_CRATE)
38}
39
40#[proc_macro_derive(Decode, attributes(musli))]
41#[doc(hidden)]
42pub fn musli_derive_decode(input: TokenStream) -> TokenStream {
43 derive_decode(input, MUSLI_CRATE)
44}
45
46fn derive_encode(input: TokenStream, crate_default: &str) -> TokenStream {
47 let input = syn::parse_macro_input!(input as syn::DeriveInput);
48 let expander = expander::Expander::new(&input, crate_default);
49
50 match expander.expand_encode() {
51 Ok(tokens) => tokens.into(),
52 Err(()) => to_compile_errors(expander.into_errors()).into(),
53 }
54}
55
56fn derive_decode(input: TokenStream, crate_default: &str) -> TokenStream {
57 let input = syn::parse_macro_input!(input as syn::DeriveInput);
58 let expander = expander::Expander::new(&input, crate_default);
59
60 match expander.expand_decode() {
61 Ok(tokens) => tokens.into(),
62 Err(()) => to_compile_errors(expander.into_errors()).into(),
63 }
64}
65
66#[proc_macro_attribute]
67#[doc(hidden)]
68pub fn musli_trait_defaults(attr: TokenStream, input: TokenStream) -> TokenStream {
69 trait_defaults(attr, input, MUSLI_CRATE)
70}
71
72#[proc_macro_attribute]
73#[doc(hidden)]
74pub fn musli_core_trait_defaults(attr: TokenStream, input: TokenStream) -> TokenStream {
75 trait_defaults(attr, input, MUSLI_CORE_CRATE)
76}
77
78fn trait_defaults(
79 attr: TokenStream,
80 input: TokenStream,
81 default_crate: &'static str,
82) -> TokenStream {
83 let attr = syn::parse_macro_input!(attr as types::Attr);
84 let parser = move |input: ParseStream| types::parse(input, attr, default_crate);
85
86 match syn::parse::Parser::parse(parser, input) {
87 Ok(types) => types.to_token_stream().into(),
88 Err(err) => err.to_compile_error().into(),
89 }
90}
91
92fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
93 let mut output = proc_macro2::TokenStream::new();
94
95 for e in errors {
96 output.extend(e.to_compile_error());
97 }
98
99 output
100}