use crate::util::ExpectLit;
use syn::{punctuated::Punctuated, spanned::Spanned as _, Attribute, LitStr, Meta, Token};
pub(super) fn parse_doc_attr(input: &Attribute) -> syn::Result<Option<LitStr>> {
input.parse_meta().and_then(|meta| {
Ok(match meta {
Meta::NameValue(kv) => Some(kv.lit.expect_str()?),
_ => None
})
})
}
fn unknown(meta: Meta, error_on_unknown: bool) -> syn::Result<()> {
if error_on_unknown {
Err(syn::Error::new(
match meta {
Meta::Path(path) => path.span(),
Meta::List(list) => list.span(),
Meta::NameValue(kv) => kv.path.span()
},
"Unexpected token"
))
} else {
Ok(())
}
}
#[derive(Default)]
pub(super) struct ContainerAttributes {
pub(super) doc: Vec<String>,
pub(super) rename: Option<LitStr>,
pub(super) rename_all: Option<LitStr>,
pub(super) tag: Option<LitStr>,
pub(super) content: Option<LitStr>,
pub(super) untagged: bool,
pub(super) deny_unknown_fields: bool
}
impl ContainerAttributes {
pub(super) fn parse_from(&mut self, input: &Attribute, error_on_unknown: bool) -> syn::Result<()> {
let tokens: Punctuated<Meta, Token![,]> = input.parse_args_with(Punctuated::parse_terminated)?;
for token in tokens {
match token {
Meta::NameValue(kv) if kv.path.is_ident("rename") => {
self.rename = Some(kv.lit.expect_str()?);
},
Meta::NameValue(kv) if kv.path.is_ident("rename_all") => {
self.rename_all = Some(kv.lit.expect_str()?);
},
Meta::NameValue(kv) if kv.path.is_ident("tag") => {
self.tag = Some(kv.lit.expect_str()?);
},
Meta::NameValue(kv) if kv.path.is_ident("content") => {
self.content = Some(kv.lit.expect_str()?);
},
Meta::Path(path) if path.is_ident("untagged") => {
self.untagged = true;
},
Meta::Path(path) if path.is_ident("deny_unknown_fields") => {
self.deny_unknown_fields = true;
},
meta => unknown(meta, error_on_unknown)?
}
}
Ok(())
}
}
#[derive(Default)]
pub(super) struct FieldAttributes {
pub(super) rename: Option<LitStr>,
pub(super) nullable: bool,
pub(super) flatten: bool,
pub(super) skip_serializing: bool,
pub(super) skip_deserializing: bool
}
impl FieldAttributes {
pub(super) fn parse_from(&mut self, input: &Attribute, error_on_unknown: bool) -> syn::Result<()> {
let tokens: Punctuated<Meta, Token![,]> = input.parse_args_with(Punctuated::parse_terminated)?;
for token in tokens {
match token {
Meta::NameValue(kv) if kv.path.is_ident("rename") => {
self.rename = Some(kv.lit.expect_str()?);
},
Meta::Path(path) if path.is_ident("default") => {
self.nullable = true;
},
Meta::NameValue(kv) if kv.path.is_ident("default") => {
self.nullable = true;
},
Meta::Path(path) if path.is_ident("flatten") => {
self.flatten = true;
},
Meta::Path(path) if path.is_ident("skip") => {
self.nullable = true;
self.skip_serializing = true;
self.skip_deserializing = true;
},
Meta::Path(path) if path.is_ident("skip_serializing") => {
self.nullable = true;
self.skip_serializing = true;
},
Meta::Path(path) if path.is_ident("skip_deserializing") => {
self.nullable = true;
self.skip_deserializing = true;
},
Meta::NameValue(kv) if kv.path.is_ident("skip_serializing_if") => {
self.nullable = true;
},
meta => unknown(meta, error_on_unknown)?
}
}
Ok(())
}
}