mwapi_responses_derive/
builder.rsuse proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote, ToTokens};
use syn::{Ident, Visibility};
pub(crate) struct StructBuilder {
pub(crate) ident: Ident,
pub(crate) fields: Vec<StructField>,
pub(crate) visibility: Visibility,
pub(crate) extra_derive: Option<TokenStream2>,
}
impl ToTokens for StructBuilder {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let ident = &self.ident;
let visiblity = &self.visibility;
let extra_derive = &self.extra_derive;
let fields = &self.fields;
let stream = quote! {
#[doc(hidden)]
#extra_derive
#[derive(Debug, Clone, ::mwapi_responses::serde::Deserialize)]
#[serde(crate = "::mwapi_responses::serde")]
#visiblity struct #ident {
#(#fields)*
}
};
stream.to_tokens(tokens);
}
}
#[derive(Debug)]
pub(crate) struct StructField {
pub(crate) name: String,
pub(crate) type_: TokenStream2,
pub(crate) default: bool,
pub(crate) rename: Option<String>,
pub(crate) deserialize_with: Option<String>,
}
impl ToTokens for StructField {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let (name, rename) = match &self.rename {
Some(rename) => {
let name = &self.name;
(
rename.to_string(),
Some(quote! {
#[serde(rename = #name)]
}),
)
}
None => (self.name.to_string(), None),
};
let name = format_ident!("{}", name);
let type_ = &self.type_;
let default = if self.default {
Some(quote! {
#[serde(default)]
})
} else {
None
};
let deser_with = self.deserialize_with.as_ref().map(|function| {
quote! {
#[serde(deserialize_with = #function)]
}
});
let stream = quote! {
#default #rename #deser_with pub #name: #type_,
};
stream.to_tokens(tokens);
}
}
#[cfg(test)]
mod tests {
use super::*;
fn stringify<P: ToTokens>(thing: P) -> String {
let mut stream = quote! {};
thing.to_tokens(&mut stream);
stream.to_string()
}
#[test]
fn test_builder() {
let builder = StructBuilder {
ident: format_ident!("{}", "Name"),
fields: vec![StructField {
name: "abc".to_string(),
type_: quote! { u32 },
default: false,
rename: None,
deserialize_with: None,
}],
visibility: Visibility::Inherited,
extra_derive: None,
};
assert_eq!(
&stringify(builder),
"# [doc (hidden)] # [derive (Debug , Clone , :: mwapi_responses :: serde :: Deserialize)] # [serde (crate = \"::mwapi_responses::serde\")] struct Name { pub abc : u32 , }"
);
}
#[test]
fn test_field() {
let field = StructField {
name: "abc".to_string(),
type_: quote! { u32 },
default: false,
rename: None,
deserialize_with: None,
};
assert_eq!(&stringify(field), "pub abc : u32 ,");
let field = StructField {
name: "abc".to_string(),
type_: quote! { u32 },
default: true,
rename: None,
deserialize_with: None,
};
assert_eq!(&stringify(field), "# [serde (default)] pub abc : u32 ,");
let field = StructField {
name: "abc".to_string(),
type_: quote! { u32 },
default: true,
rename: Some("def".to_string()),
deserialize_with: None,
};
assert_eq!(
&stringify(field),
"# [serde (default)] # [serde (rename = \"abc\")] pub def : u32 ,"
);
let field = StructField {
name: "abc".to_string(),
type_: quote! { u32 },
default: false,
rename: None,
deserialize_with: Some("::foo::bar".to_string()),
};
assert_eq!(
&stringify(field),
"# [serde (deserialize_with = \"::foo::bar\")] pub abc : u32 ,"
);
}
}