fp_bindgen/types/
structs.rs1use super::TypeIdent;
2use crate::types::format_bounds;
3use crate::{casing::Casing, docs::get_doc_lines};
4use quote::ToTokens;
5use std::convert::TryFrom;
6use syn::{
7 ext::IdentExt, parenthesized, parse::Parse, parse::ParseStream, Attribute, Error, GenericParam,
8 Ident, ItemStruct, LitStr, Result, Token,
9};
10
11#[derive(Clone, Debug, Eq, Hash, PartialEq)]
12pub struct Struct {
13 pub ident: TypeIdent,
14 pub fields: Vec<Field>,
15 pub doc_lines: Vec<String>,
16 pub options: StructOptions,
17}
18
19pub(crate) fn parse_struct_item(item: ItemStruct) -> Struct {
20 let ident = TypeIdent {
21 name: item.ident.to_string(),
22 generic_args: item
23 .generics
24 .params
25 .iter()
26 .filter_map(|param| match param {
27 GenericParam::Type(ty) => {
28 Some((TypeIdent::from(ty.ident.to_string()), format_bounds(ty)))
29 }
30 _ => None,
31 })
32 .collect(),
33 ..Default::default()
34 };
35 let fields = item
36 .fields
37 .iter()
38 .map(|field| Field {
39 name: field.ident.as_ref().map(Ident::to_string),
40 ty: TypeIdent::try_from(&field.ty)
41 .unwrap_or_else(|_| panic!("Invalid field type in struct {}", ident)),
42 doc_lines: get_doc_lines(&field.attrs),
43 attrs: FieldAttrs::from_attrs(&field.attrs),
44 })
45 .collect();
46
47 Struct {
48 ident,
49 fields,
50 doc_lines: get_doc_lines(&item.attrs),
51 options: StructOptions::from_attrs(&item.attrs),
52 }
53}
54
55#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
56pub struct StructOptions {
57 pub field_casing: Casing,
58
59 pub rust_module: Option<String>,
79}
80
81impl StructOptions {
82 pub fn from_attrs(attrs: &[Attribute]) -> Self {
83 let mut opts = Self::default();
84 for attr in attrs {
85 if attr.path.is_ident("fp") || attr.path.is_ident("serde") {
86 opts.merge_with(
87 &syn::parse2::<Self>(attr.tokens.clone()).expect("Could not parse attributes"),
88 );
89 }
90 }
91 opts
92 }
93
94 fn merge_with(&mut self, other: &Self) {
95 if other.field_casing != Casing::default() {
96 self.field_casing = other.field_casing;
97 }
98 if let Some(other_rust_module) = &other.rust_module {
99 self.rust_module = Some(other_rust_module.clone());
100 }
101 }
102
103 pub fn to_serde_attrs(&self) -> Vec<String> {
104 let mut serde_attrs = vec![];
105 if let Some(casing) = &self.field_casing.as_maybe_str() {
106 serde_attrs.push(format!("rename_all = \"{casing}\""));
107 }
108 serde_attrs
109 }
110}
111
112impl Parse for StructOptions {
113 fn parse(input: ParseStream) -> Result<Self> {
114 let content;
115 parenthesized!(content in input);
116
117 let parse_value = || -> Result<String> {
118 content.parse::<Token![=]>()?;
119 Ok(content
120 .parse::<LitStr>()?
121 .to_token_stream()
122 .to_string()
123 .trim_matches('"')
124 .to_owned())
125 };
126
127 let mut result = Self::default();
128 loop {
129 let key: Ident = content.call(IdentExt::parse_any)?;
130 match key.to_string().as_ref() {
131 "rename_all" => {
132 result.field_casing = Casing::try_from(parse_value()?.as_ref())
133 .map_err(|err| Error::new(content.span(), err))?
134 }
135 "rust_module" => {
136 result.rust_module = Some(parse_value()?);
137 }
138 other => {
139 return Err(Error::new(
140 content.span(),
141 format!("Unexpected attribute: {other}"),
142 ))
143 }
144 }
145
146 if content.is_empty() {
147 break;
148 }
149
150 content.parse::<Token![,]>()?;
151 }
152
153 Ok(result)
154 }
155}
156
157#[derive(Clone, Debug, Eq, Hash, PartialEq)]
158pub struct Field {
159 pub name: Option<String>,
160 pub ty: TypeIdent,
161 pub doc_lines: Vec<String>,
162 pub attrs: FieldAttrs,
163}
164
165#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
166pub struct FieldAttrs {
167 pub default: Option<String>,
175
176 pub deserialize_with: Option<String>,
180
181 pub flatten: bool,
185
186 pub rename: Option<String>,
191
192 pub serialize_with: Option<String>,
196
197 pub skip_serializing_if: Option<String>,
205}
206
207impl FieldAttrs {
208 pub fn from_attrs(attrs: &[Attribute]) -> Self {
209 let mut opts = Self::default();
210 for attr in attrs {
211 if attr.path.is_ident("fp") || attr.path.is_ident("serde") {
212 opts.merge_with(
213 &syn::parse2::<Self>(attr.tokens.clone())
214 .expect("Could not parse field attributes"),
215 );
216 }
217 }
218 opts
219 }
220
221 fn merge_with(&mut self, other: &Self) {
222 if other.default.is_some() {
223 self.default = other.default.clone();
224 }
225 if other.deserialize_with.is_some() {
226 self.deserialize_with = other.deserialize_with.clone();
227 }
228 if other.flatten {
229 self.flatten = other.flatten;
230 }
231 if other.rename.is_some() {
232 self.rename = other.rename.clone();
233 }
234 if other.serialize_with.is_some() {
235 self.serialize_with = other.serialize_with.clone();
236 }
237 if other.skip_serializing_if.is_some() {
238 self.skip_serializing_if = other.skip_serializing_if.clone();
239 }
240 }
241
242 pub fn to_serde_attrs(&self) -> Vec<String> {
243 let mut serde_attrs = vec![];
244 if let Some(default) = self.default.as_ref() {
245 if default.is_empty() {
246 serde_attrs.push("default".to_owned());
247 } else {
248 serde_attrs.push(format!("default = \"{default}\""));
249 }
250 }
251 match (self.deserialize_with.as_ref(), self.serialize_with.as_ref()) {
252 (Some(deserialize_with), Some(serialize_with))
253 if deserialize_with == serialize_with =>
254 {
255 serde_attrs.push(format!("with = \"{deserialize_with}\""));
256 }
257 (Some(deserialize_with), Some(serialize_with)) => {
258 serde_attrs.push(format!("deserialize_with = \"{deserialize_with}\""));
259 serde_attrs.push(format!("serialize_with = \"{serialize_with}\""));
260 }
261 (Some(deserialize_with), None) => {
262 serde_attrs.push(format!("deserialize_with = \"{deserialize_with}\""));
263 }
264 (None, Some(serialize_with)) => {
265 serde_attrs.push(format!("serialize_with = \"{serialize_with}\""));
266 }
267 (None, None) => {}
268 }
269 if self.flatten {
270 serde_attrs.push("flatten".to_owned());
271 }
272 if let Some(rename) = self.rename.as_ref() {
273 serde_attrs.push(format!("rename = \"{rename}\""));
274 }
275 if let Some(skip_serializing_if) = self.skip_serializing_if.as_ref() {
276 serde_attrs.push(format!("skip_serializing_if = \"{skip_serializing_if}\""));
277 }
278 serde_attrs
279 }
280}
281
282impl Parse for FieldAttrs {
283 fn parse(input: ParseStream) -> Result<Self> {
284 let content;
285 parenthesized!(content in input);
286
287 let parse_value = || -> Result<String> {
288 content.parse::<Token![=]>()?;
289 Ok(content
290 .parse::<LitStr>()?
291 .to_token_stream()
292 .to_string()
293 .trim_matches('"')
294 .to_owned())
295 };
296
297 let parse_optional_value = || -> Result<String> {
298 if content.peek(Token![=]) {
299 parse_value()
300 } else {
301 Ok(String::new())
302 }
303 };
304
305 let mut result = Self::default();
306 loop {
307 let key: Ident = content.call(IdentExt::parse_any)?;
308 match key.to_string().as_ref() {
309 "default" => result.default = Some(parse_optional_value()?),
310 "deserialize_with" => result.deserialize_with = Some(parse_value()?),
311 "flatten" => result.flatten = true,
312 "rename" => result.rename = Some(parse_value()?),
313 "serialize_with" => result.serialize_with = Some(parse_value()?),
314 "skip_serializing_if" => result.skip_serializing_if = Some(parse_value()?),
315 "with" => {
316 let value = parse_value()?;
317 result.deserialize_with = Some(value.clone());
318 result.serialize_with = Some(value);
319 }
320 other => {
321 return Err(Error::new(
322 content.span(),
323 format!("Unexpected field attribute: {other}"),
324 ))
325 }
326 }
327
328 if content.is_empty() {
329 break;
330 }
331
332 content.parse::<Token![,]>()?;
333 }
334
335 Ok(result)
336 }
337}