mwapi_responses_derive/
builder.rs1use proc_macro2::TokenStream as TokenStream2;
19use quote::{format_ident, quote, ToTokens};
20use syn::{Ident, Visibility};
21
22pub(crate) struct StructBuilder {
23 pub(crate) ident: Ident,
24 pub(crate) fields: Vec<StructField>,
25 pub(crate) visibility: Visibility,
26 pub(crate) extra_derive: Option<TokenStream2>,
27}
28
29impl ToTokens for StructBuilder {
30 fn to_tokens(&self, tokens: &mut TokenStream2) {
31 let ident = &self.ident;
32 let visiblity = &self.visibility;
33 let extra_derive = &self.extra_derive;
34 let fields = &self.fields;
35 let stream = quote! {
36 #[doc(hidden)]
37 #extra_derive
38 #[derive(Debug, Clone, ::mwapi_responses::serde::Deserialize)]
39 #[serde(crate = "::mwapi_responses::serde")]
40 #visiblity struct #ident {
41 #(#fields)*
42 }
43 };
44
45 stream.to_tokens(tokens);
46 }
47}
48
49#[derive(Debug)]
50pub(crate) struct StructField {
51 pub(crate) name: String,
52 pub(crate) type_: TokenStream2,
53 pub(crate) default: bool,
54 pub(crate) rename: Option<String>,
55 pub(crate) deserialize_with: Option<String>,
56}
57
58impl ToTokens for StructField {
59 fn to_tokens(&self, tokens: &mut TokenStream2) {
66 let (name, rename) = match &self.rename {
67 Some(rename) => {
68 let name = &self.name;
69 (
70 rename.to_string(),
71 Some(quote! {
72 #[serde(rename = #name)]
73 }),
74 )
75 }
76 None => (self.name.to_string(), None),
77 };
78 let name = format_ident!("{}", name);
79 let type_ = &self.type_;
80 let default = if self.default {
81 Some(quote! {
82 #[serde(default)]
83 })
84 } else {
85 None
86 };
87 let deser_with = self.deserialize_with.as_ref().map(|function| {
88 quote! {
89 #[serde(deserialize_with = #function)]
90 }
91 });
92 let stream = quote! {
93 #default #rename #deser_with pub #name: #type_,
94 };
95
96 stream.to_tokens(tokens);
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103 fn stringify<P: ToTokens>(thing: P) -> String {
104 let mut stream = quote! {};
105 thing.to_tokens(&mut stream);
106 stream.to_string()
107 }
108
109 #[test]
110 fn test_builder() {
111 let builder = StructBuilder {
112 ident: format_ident!("{}", "Name"),
113 fields: vec![StructField {
114 name: "abc".to_string(),
115 type_: quote! { u32 },
116 default: false,
117 rename: None,
118 deserialize_with: None,
119 }],
120 visibility: Visibility::Inherited,
121 extra_derive: None,
122 };
123 assert_eq!(
124 &stringify(builder),
125 "# [doc (hidden)] # [derive (Debug , Clone , :: mwapi_responses :: serde :: Deserialize)] # [serde (crate = \"::mwapi_responses::serde\")] struct Name { pub abc : u32 , }"
126 );
127 }
128
129 #[test]
130 fn test_field() {
131 let field = StructField {
132 name: "abc".to_string(),
133 type_: quote! { u32 },
134 default: false,
135 rename: None,
136 deserialize_with: None,
137 };
138 assert_eq!(&stringify(field), "pub abc : u32 ,");
139 let field = StructField {
140 name: "abc".to_string(),
141 type_: quote! { u32 },
142 default: true,
143 rename: None,
144 deserialize_with: None,
145 };
146 assert_eq!(&stringify(field), "# [serde (default)] pub abc : u32 ,");
147 let field = StructField {
148 name: "abc".to_string(),
149 type_: quote! { u32 },
150 default: true,
151 rename: Some("def".to_string()),
152 deserialize_with: None,
153 };
154 assert_eq!(
155 &stringify(field),
156 "# [serde (default)] # [serde (rename = \"abc\")] pub def : u32 ,"
157 );
158 let field = StructField {
159 name: "abc".to_string(),
160 type_: quote! { u32 },
161 default: false,
162 rename: None,
163 deserialize_with: Some("::foo::bar".to_string()),
164 };
165 assert_eq!(
166 &stringify(field),
167 "# [serde (deserialize_with = \"::foo::bar\")] pub abc : u32 ,"
168 );
169 }
170}