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