Detailed changes
@@ -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,