Skip to main content

rustrade_macro/
lib.rs

1#![deny(
2    clippy::unwrap_used,
3    clippy::expect_used,
4    clippy::cast_possible_truncation,
5    clippy::cast_sign_loss
6)]
7
8extern crate proc_macro;
9
10use convert_case::{Boundary, Case, Casing};
11use proc_macro::TokenStream;
12use quote::quote;
13use syn::DeriveInput;
14
15#[proc_macro_derive(DeExchange)]
16pub fn de_exchange_derive(input: TokenStream) -> TokenStream {
17    // Parse Rust code abstract syntax tree with Syn from TokenStream -> DeriveInput
18    #[allow(clippy::expect_used)] // Proc-macro: panic produces compile error (idiomatic)
19    let ast: DeriveInput =
20        syn::parse(input).expect("de_exchange_derive() failed to parse input TokenStream");
21
22    // Determine execution name
23    let exchange = &ast.ident;
24
25    let generated = quote! {
26        impl<'de> serde::Deserialize<'de> for #exchange {
27            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
28            where
29                D: serde::de::Deserializer<'de>
30            {
31                let input = <String as serde::Deserialize>::deserialize(deserializer)?;
32                let exchange = #exchange::ID;
33                let expected = exchange.as_str();
34
35                if input.as_str() == expected {
36                    Ok(Self::default())
37                } else {
38                    Err(serde::de::Error::invalid_value(
39                        serde::de::Unexpected::Str(input.as_str()),
40                        &expected
41                    ))
42                }
43            }
44        }
45    };
46
47    TokenStream::from(generated)
48}
49
50#[proc_macro_derive(SerExchange)]
51pub fn ser_exchange_derive(input: TokenStream) -> TokenStream {
52    // Parse Rust code abstract syntax tree with Syn from TokenStream -> DeriveInput
53    #[allow(clippy::expect_used)] // Proc-macro: panic produces compile error (idiomatic)
54    let ast: DeriveInput =
55        syn::parse(input).expect("ser_exchange_derive() failed to parse input TokenStream");
56
57    // Determine Exchange
58    let exchange = &ast.ident;
59
60    let generated = quote! {
61        impl serde::Serialize for #exchange {
62            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
63            where
64                S: serde::ser::Serializer,
65            {
66                serializer.serialize_str(#exchange::ID.as_str())
67            }
68        }
69    };
70
71    TokenStream::from(generated)
72}
73
74#[proc_macro_derive(DeSubKind)]
75pub fn de_sub_kind_derive(input: TokenStream) -> TokenStream {
76    // Parse Rust code abstract syntax tree with Syn from TokenStream -> DeriveInput
77    #[allow(clippy::expect_used)] // Proc-macro: panic produces compile error (idiomatic)
78    let ast: DeriveInput =
79        syn::parse(input).expect("de_sub_kind_derive() failed to parse input TokenStream");
80
81    // Determine SubKind name
82    let sub_kind = &ast.ident;
83
84    let expected_sub_kind = sub_kind
85        .to_string()
86        .from_case(Case::Pascal)
87        .remove_boundaries(&Boundary::letter_digit())
88        .to_case(Case::Snake);
89
90    let generated = quote! {
91        impl<'de> serde::Deserialize<'de> for #sub_kind {
92            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
93            where
94                D: serde::de::Deserializer<'de>
95            {
96                let input = <String as serde::Deserialize>::deserialize(deserializer)?;
97
98                if input == #expected_sub_kind {
99                    Ok(Self)
100                } else {
101                    Err(serde::de::Error::invalid_value(
102                        serde::de::Unexpected::Str(input.as_str()),
103                        &#expected_sub_kind
104                    ))
105                }
106            }
107        }
108    };
109
110    TokenStream::from(generated)
111}
112
113#[proc_macro_derive(SerSubKind)]
114pub fn ser_sub_kind_derive(input: TokenStream) -> TokenStream {
115    // Parse Rust code abstract syntax tree with Syn from TokenStream -> DeriveInput
116    #[allow(clippy::expect_used)] // Proc-macro: panic produces compile error (idiomatic)
117    let ast: DeriveInput =
118        syn::parse(input).expect("ser_sub_kind_derive() failed to parse input TokenStream");
119
120    // Determine SubKind name
121    let sub_kind = &ast.ident;
122    let sub_kind_string = sub_kind.to_string().to_case(Case::Snake);
123    let sub_kind_str = sub_kind_string.as_str();
124
125    let generated = quote! {
126        impl serde::Serialize for #sub_kind {
127            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
128            where
129                S: serde::ser::Serializer,
130            {
131                serializer.serialize_str(#sub_kind_str)
132            }
133        }
134    };
135
136    TokenStream::from(generated)
137}