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 #[allow(clippy::expect_used)] let ast: DeriveInput =
20 syn::parse(input).expect("de_exchange_derive() failed to parse input TokenStream");
21
22 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 #[allow(clippy::expect_used)] let ast: DeriveInput =
55 syn::parse(input).expect("ser_exchange_derive() failed to parse input TokenStream");
56
57 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 #[allow(clippy::expect_used)] let ast: DeriveInput =
79 syn::parse(input).expect("de_sub_kind_derive() failed to parse input TokenStream");
80
81 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 #[allow(clippy::expect_used)] let ast: DeriveInput =
118 syn::parse(input).expect("ser_sub_kind_derive() failed to parse input TokenStream");
119
120 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}