diff --git a/parsers/src/util/macro_tests.rs b/parsers/src/util/macro_tests.rs index 2ef80fc4..8c8c6909 100644 --- a/parsers/src/util/macro_tests.rs +++ b/parsers/src/util/macro_tests.rs @@ -587,3 +587,26 @@ fn boxed_child_roundtrip_nested_2() { }; roundtrip_full::("") } + +#[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::("") +} + +#[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::() >= 0); + assert!(std::mem::size_of::() >= 0); +} diff --git a/xso-proc/src/meta.rs b/xso-proc/src/meta.rs index a4f148ab..e751f21f 100644 --- a/xso-proc/src/meta.rs +++ b/xso-proc/src/meta.rs @@ -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, + + /// The value assigned to `iterator` inside `#[xml(..)]`, if any. + pub(crate) iterator: Option, } impl XmlCompoundMeta { @@ -167,6 +173,8 @@ impl XmlCompoundMeta { fn parse_from_attribute(attr: &Attribute) -> Result { 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, }) } diff --git a/xso-proc/src/structs.rs b/xso-proc/src/structs.rs index e9233800..ea601084 100644 --- a/xso-proc/src/structs.rs +++ b/xso-proc/src/structs.rs @@ -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(), }) } diff --git a/xso/ChangeLog b/xso/ChangeLog index 6b7ee3ed..fd8b23b6 100644 --- a/xso/ChangeLog +++ b/xso/ChangeLog @@ -2,20 +2,16 @@ Version NEXT: 0000-00-00 Jonas Schäfer * 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 diff --git a/xso/src/from_xml_doc.md b/xso/src/from_xml_doc.md index a0251051..e148ea65 100644 --- a/xso/src/from_xml_doc.md +++ b/xso/src/from_xml_doc.md @@ -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,