xso-proc: add support for renaming attributes
This is akin to `#[serde(rename = ..)]` and thus useful.
This commit is contained in:
parent
0bae5d3346
commit
219d682295
4 changed files with 112 additions and 27 deletions
|
|
@ -73,30 +73,30 @@ impl FieldKind {
|
|||
/// it is not specified explicitly.
|
||||
fn from_meta(meta: XmlFieldMeta, field_ident: Option<&Ident>) -> Result<Self> {
|
||||
match meta {
|
||||
XmlFieldMeta::Attribute { span } => {
|
||||
let Some(field_ident) = field_ident else {
|
||||
return Err(Error::new(
|
||||
span,
|
||||
"attribute extraction not supported on unnamed fields",
|
||||
));
|
||||
};
|
||||
|
||||
let xml_name = match NcName::try_from(field_ident.to_string()) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return Err(Error::new(
|
||||
field_ident.span(),
|
||||
format!("invalid XML attribute name: {}", e),
|
||||
))
|
||||
XmlFieldMeta::Attribute { span, name } => {
|
||||
let xml_name = match name {
|
||||
Some(v) => v,
|
||||
None => match field_ident {
|
||||
None => return Err(Error::new(
|
||||
span,
|
||||
"attribute name must be explicitly specified using `#[xml(attribute = ..)] on unnamed fields",
|
||||
)),
|
||||
Some(field_ident) => match NcName::try_from(field_ident.to_string()) {
|
||||
Ok(value) => NameRef::Literal {
|
||||
span: field_ident.span(),
|
||||
value,
|
||||
},
|
||||
Err(e) => {
|
||||
return Err(Error::new(
|
||||
field_ident.span(),
|
||||
format!("invalid XML attribute name: {}", e),
|
||||
))
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self::Attribute {
|
||||
xml_name: NameRef::Literal {
|
||||
span: field_ident.span(),
|
||||
value: xml_name,
|
||||
},
|
||||
})
|
||||
Ok(Self::Attribute { xml_name })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,15 +203,51 @@ pub(crate) enum XmlFieldMeta {
|
|||
///
|
||||
/// This is useful for error messages.
|
||||
span: Span,
|
||||
|
||||
/// The XML name supplied.
|
||||
name: Option<NameRef>,
|
||||
},
|
||||
}
|
||||
|
||||
impl XmlFieldMeta {
|
||||
/// Parse a `#[xml(attribute(..))]` meta.
|
||||
///
|
||||
/// That meta can have three distinct syntax styles:
|
||||
/// - argument-less: `#[xml(attribute)]`
|
||||
/// - shorthand: `#[xml(attribute = ..)]`
|
||||
/// - full: `#[xml(attribute(..))]`
|
||||
fn attribute_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
|
||||
Ok(Self::Attribute {
|
||||
span: meta.path.span(),
|
||||
})
|
||||
if meta.input.peek(Token![=]) {
|
||||
// shorthand syntax
|
||||
Ok(Self::Attribute {
|
||||
span: meta.path.span(),
|
||||
name: Some(meta.value()?.parse()?),
|
||||
})
|
||||
} else if meta.input.peek(syn::token::Paren) {
|
||||
// full syntax
|
||||
let mut name: Option<NameRef> = None;
|
||||
meta.parse_nested_meta(|meta| {
|
||||
if meta.path.is_ident("name") {
|
||||
if name.is_some() {
|
||||
return Err(Error::new_spanned(meta.path, "duplicate `name` key"));
|
||||
}
|
||||
name = Some(meta.value()?.parse()?);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new_spanned(meta.path, "unsupported key"))
|
||||
}
|
||||
})?;
|
||||
Ok(Self::Attribute {
|
||||
span: meta.path.span(),
|
||||
name,
|
||||
})
|
||||
} else {
|
||||
// argument-less syntax
|
||||
Ok(Self::Attribute {
|
||||
span: meta.path.span(),
|
||||
name: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse [`Self`] from a nestd meta, switching on the identifier
|
||||
|
|
|
|||
Loading…
Reference in a new issue