xso: add support for overriding names of generated types
In 1265f4b
, we introduced a change which may cause a conflict of type
names when deriving the traits on two different types. While a
workaround existed (use `mod`s to isolate the implementation), that is
ugly.
This commit allows overriding the choice of type names.
This commit is contained in:
parent
eb51b05c13
commit
c90752aa51
5 changed files with 77 additions and 12 deletions
|
@ -587,3 +587,26 @@ fn boxed_child_roundtrip_nested_2() {
|
|||
};
|
||||
roundtrip_full::<BoxedChild>("<elem xmlns='urn:example:ns1'><elem><elem/></elem></elem>")
|
||||
}
|
||||
|
||||
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
||||
#[xml(namespace = NS1, name = "elem", builder = RenamedBuilder, iterator = RenamedIter)]
|
||||
struct RenamedTypes;
|
||||
|
||||
#[test]
|
||||
fn renamed_types_roundtrip() {
|
||||
#[allow(unused_imports)]
|
||||
use std::{
|
||||
option::Option::{None, Some},
|
||||
result::Result::{Err, Ok},
|
||||
};
|
||||
roundtrip_full::<RenamedTypes>("<elem xmlns='urn:example:ns1'/>")
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(unused_comparisons)]
|
||||
fn renamed_types_get_renamed() {
|
||||
// these merely serve as a test that the types are declared with the names
|
||||
// given in the attributes.
|
||||
assert!(std::mem::size_of::<RenamedBuilder>() >= 0);
|
||||
assert!(std::mem::size_of::<RenamedIter>() >= 0);
|
||||
}
|
||||
|
|
|
@ -157,6 +157,12 @@ pub(crate) struct XmlCompoundMeta {
|
|||
|
||||
/// The debug flag.
|
||||
pub(crate) debug: Flag,
|
||||
|
||||
/// The value assigned to `builder` inside `#[xml(..)]`, if any.
|
||||
pub(crate) builder: Option<Ident>,
|
||||
|
||||
/// The value assigned to `iterator` inside `#[xml(..)]`, if any.
|
||||
pub(crate) iterator: Option<Ident>,
|
||||
}
|
||||
|
||||
impl XmlCompoundMeta {
|
||||
|
@ -167,6 +173,8 @@ impl XmlCompoundMeta {
|
|||
fn parse_from_attribute(attr: &Attribute) -> Result<Self> {
|
||||
let mut namespace = None;
|
||||
let mut name = None;
|
||||
let mut builder = None;
|
||||
let mut iterator = None;
|
||||
let mut debug = Flag::Absent;
|
||||
|
||||
attr.parse_nested_meta(|meta| {
|
||||
|
@ -188,6 +196,18 @@ impl XmlCompoundMeta {
|
|||
}
|
||||
debug = (&meta.path).into();
|
||||
Ok(())
|
||||
} else if meta.path.is_ident("builder") {
|
||||
if builder.is_some() {
|
||||
return Err(Error::new_spanned(meta.path, "duplicate `builder` key"));
|
||||
}
|
||||
builder = Some(meta.value()?.parse()?);
|
||||
Ok(())
|
||||
} else if meta.path.is_ident("iterator") {
|
||||
if iterator.is_some() {
|
||||
return Err(Error::new_spanned(meta.path, "duplicate `iterator` key"));
|
||||
}
|
||||
iterator = Some(meta.value()?.parse()?);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new_spanned(meta.path, "unsupported key"))
|
||||
}
|
||||
|
@ -198,6 +218,8 @@ impl XmlCompoundMeta {
|
|||
namespace,
|
||||
name,
|
||||
debug,
|
||||
builder,
|
||||
iterator,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -85,13 +85,23 @@ impl StructDef {
|
|||
return Err(Error::new(meta.span, "`name` is required on structs"));
|
||||
};
|
||||
|
||||
let builder_ty_ident = match meta.builder {
|
||||
Some(v) => v,
|
||||
None => concat_camel_case(ident, "FromXmlBuilder"),
|
||||
};
|
||||
|
||||
let item_iter_ty_ident = match meta.iterator {
|
||||
Some(v) => v,
|
||||
None => concat_camel_case(ident, "AsXmlIterator"),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
namespace,
|
||||
name,
|
||||
inner: Compound::from_fields(fields)?,
|
||||
target_ty_ident: ident.clone(),
|
||||
builder_ty_ident: concat_camel_case(ident, "FromXmlBuilder"),
|
||||
item_iter_ty_ident: concat_camel_case(ident, "AsXmlIterator"),
|
||||
builder_ty_ident,
|
||||
item_iter_ty_ident,
|
||||
debug: meta.debug.is_set(),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,20 +2,16 @@ Version NEXT:
|
|||
0000-00-00 Jonas Schäfer <jonas@zombofant.net>
|
||||
* Breaking
|
||||
- We now strip trailing underscores from identifiers before constructing
|
||||
any type names we declare from derive macros. That means that it is
|
||||
not possible to derive the traits on `Foo` and `Foo_` if both live
|
||||
in the same scope.
|
||||
any type names we declare from derive macros.
|
||||
|
||||
As a workaround, you can put either of these types into a `mod` and
|
||||
reexport them from the outer module. The types generated by the derive
|
||||
macro will then be scoped inside the `mod` and cannot conflict with
|
||||
the derived types on the other type.
|
||||
|
||||
All this is to avoid triggering the camel case lint on the types we
|
||||
generate.
|
||||
If you previously derived any of the macros on e.g. `Foo` and `Foo_`
|
||||
within the same scope, you can use the newly added `builder` and
|
||||
`iterator` meta keys to override the generated type names.
|
||||
* Added
|
||||
- Support for child elements in derive macros. Child elements may also
|
||||
be wrapped in Option or Box.
|
||||
- Support for overriding the names of the types generated by the derive
|
||||
macros.
|
||||
|
||||
Version 0.1.2:
|
||||
2024-07-26 Jonas Schäfer <jonas@zombofant.net>
|
||||
|
|
|
@ -35,6 +35,7 @@ such:
|
|||
is also a path.
|
||||
- *string literal*: A string literal, like `"hello world!"`.
|
||||
- *type*: A Rust type.
|
||||
- *ident*: A Rust identifier.
|
||||
- flag: Has no value. The key's mere presence has relevance and it must not be
|
||||
followed by a `=` sign.
|
||||
|
||||
|
@ -46,6 +47,8 @@ The following keys are defined on structs:
|
|||
| --- | --- | --- |
|
||||
| `namespace` | *string literal* or *path* | The XML element namespace to match. If it is a *path*, it must point at a `&'static str`. |
|
||||
| `name` | *string literal* or *path* | The XML element name to match. If it is a *path*, it must point at a `&'static NcNameStr`. |
|
||||
| `builder` | optional *ident* | The name to use for the generated builder type. |
|
||||
| `iterator` | optional *ident* | The name to use for the generated iterator type. |
|
||||
|
||||
Note that the `name` value must be a valid XML element name, without colons.
|
||||
The namespace prefix, if any, is assigned automatically at serialisation time
|
||||
|
@ -58,6 +61,17 @@ and cannot be overridden. The following will thus not compile:
|
|||
struct Foo;
|
||||
```
|
||||
|
||||
If `builder` or `iterator` are given, the respective generated types will use
|
||||
the given names instead of names chosen by the derive macro implementation.
|
||||
Helper types will use these names as prefix. The exact names of helper types
|
||||
are implementation defined, which is why any type name starting with the
|
||||
identifiers passed to either of these keys is considered reserved.
|
||||
|
||||
By default, the builder type uses the type's name suffixed with
|
||||
`FromXmlBuilder` and the iterator type uses the type's name suffixed with
|
||||
`AsXmlIterator`. If the target type has any trailing underscores, they are
|
||||
removed before making the type name.
|
||||
|
||||
### Field meta
|
||||
|
||||
For fields, the *meta* consists of a nested meta inside the `#[xml(..)]` meta,
|
||||
|
|
Loading…
Reference in a new issue