musli_macros/
lib.rs

1//! [<img alt="github" src="https://img.shields.io/badge/github-udoprog/musli-8da0cb?style=for-the-badge&logo=github" height="20">](https://github.com/udoprog/musli)
2//! [<img alt="crates.io" src="https://img.shields.io/crates/v/musli-macros.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/musli-macros)
3//! [<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-musli--macros-66c2a5?style=for-the-badge&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/musli-macros)
4//!
5//! This crate provides the macros used in [Müsli]. The API of these macros is
6//! not expected to be stable and **must not** be used directly.
7//!
8//! Use the macros through the [`musli`] or [`musli_core`] crates instead.
9//!
10//! Please refer to <https://docs.rs/musli> for documentation.
11//!
12//! [`musli_core`]: <https://docs.rs/musli_core>
13//! [`musli`]: <https://docs.rs/musli>
14//! [Müsli]: <https://docs.rs/musli>
15
16#![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;
28
29const CRATE_DEFAULT: &str = "musli";
30
31#[proc_macro_derive(Encode, attributes(musli))]
32#[doc(hidden)]
33pub fn musli_derive_encode(input: TokenStream) -> TokenStream {
34    derive_encode(input, CRATE_DEFAULT)
35}
36
37#[proc_macro_derive(Decode, attributes(musli))]
38#[doc(hidden)]
39pub fn musli_derive_decode(input: TokenStream) -> TokenStream {
40    derive_decode(input, CRATE_DEFAULT)
41}
42
43fn derive_encode(input: TokenStream, crate_default: &str) -> TokenStream {
44    let input = syn::parse_macro_input!(input as syn::DeriveInput);
45    let expander = expander::Expander::new(&input, crate_default);
46
47    match expander.expand_encode() {
48        Ok(tokens) => tokens.into(),
49        Err(()) => to_compile_errors(expander.into_errors()).into(),
50    }
51}
52
53fn derive_decode(input: TokenStream, crate_default: &str) -> TokenStream {
54    let input = syn::parse_macro_input!(input as syn::DeriveInput);
55    let expander = expander::Expander::new(&input, crate_default);
56
57    match expander.expand_decode() {
58        Ok(tokens) => tokens.into(),
59        Err(()) => to_compile_errors(expander.into_errors()).into(),
60    }
61}
62
63#[proc_macro_attribute]
64#[doc(hidden)]
65pub fn decoder(attr: TokenStream, input: TokenStream) -> TokenStream {
66    let attr = syn::parse_macro_input!(attr as types::Attr);
67    let input = syn::parse_macro_input!(input as types::Types);
68
69    match input.expand(
70        CRATE_DEFAULT,
71        &attr,
72        "decoder",
73        types::DECODER_TYPES,
74        "__UseMusliDecoderAttributeMacro",
75        types::Kind::SelfCx,
76    ) {
77        Ok(tokens) => tokens.into(),
78        Err(err) => err.to_compile_error().into(),
79    }
80}
81
82#[proc_macro_attribute]
83#[doc(hidden)]
84pub fn encoder(attr: TokenStream, input: TokenStream) -> TokenStream {
85    let attr = syn::parse_macro_input!(attr as types::Attr);
86    let input = syn::parse_macro_input!(input as types::Types);
87
88    match input.expand(
89        CRATE_DEFAULT,
90        &attr,
91        "encoder",
92        types::ENCODER_TYPES,
93        "__UseMusliEncoderAttributeMacro",
94        types::Kind::SelfCx,
95    ) {
96        Ok(tokens) => tokens.into(),
97        Err(err) => err.to_compile_error().into(),
98    }
99}
100
101#[proc_macro_attribute]
102#[doc(hidden)]
103pub fn visitor(attr: TokenStream, input: TokenStream) -> TokenStream {
104    let attr = syn::parse_macro_input!(attr as types::Attr);
105    let input = syn::parse_macro_input!(input as types::Types);
106
107    match input.expand(
108        CRATE_DEFAULT,
109        &attr,
110        "visitor",
111        types::VISITOR_TYPES,
112        "__UseMusliVisitorAttributeMacro",
113        types::Kind::GenericCx,
114    ) {
115        Ok(tokens) => tokens.into(),
116        Err(err) => err.to_compile_error().into(),
117    }
118}
119
120#[proc_macro_attribute]
121#[doc(hidden)]
122pub fn unsized_visitor(attr: TokenStream, input: TokenStream) -> TokenStream {
123    let attr = syn::parse_macro_input!(attr as types::Attr);
124    let input = syn::parse_macro_input!(input as types::Types);
125
126    match input.expand(
127        CRATE_DEFAULT,
128        &attr,
129        "unsized visitor",
130        types::UNSIZED_VISITOR_TYPES,
131        "__UseMusliUnsizedVisitorAttributeMacro",
132        types::Kind::GenericCx,
133    ) {
134        Ok(tokens) => tokens.into(),
135        Err(err) => err.to_compile_error().into(),
136    }
137}
138
139fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
140    let mut output = proc_macro2::TokenStream::new();
141
142    for e in errors {
143        output.extend(e.to_compile_error());
144    }
145
146    output
147}