For codec-based error messages, this reduces the amount of errors per
violation to one. For all others, it improves the placement of the error
slightly, but we still get duplicates.
I couldn't figure out the remaining discrepancies in the spans ...
This gives us all the goodies of `default`, `type_` and `codec` without
having to duplicate lots of code (and I think the `match`-iness of the
new macro code is still within limits).
However, we still keep them as separate `#[xml(..)]` attributes, because
their semantics are very different and it is sensible to make them stand
out.
skip-changelog, because `#[xml(lang)]` was introduced in this version.
This was a bit tricky to build, because it is possible to have an
indirection through a `static` there. Thanks to Rust's extensive
const-fn capabilities, though, it's in fact possible to cover all cases.
We still do two different checks to improve user experience. If we can,
from within the proc macro, determine that two fields refer to the same
XML attribute (because their namespace/name values use the same Rust
tokens), then we reject the fields with a clear error message pointing
at both fields.
In the other case, when there's e.g. `#[xml(lang)]` and
`#[xml(attribute(namespace = rxml::XMLNS_XML, name = "lang"))]`, the
macro cannot be sure that XMLNS_XML is in fact the XML namespace. For
that case, we generate code which is evaluated at compile time (and
has no runtime impact) which panics if the namespace and name of two
attribute-matching fields is the same.
The error message will be less clear (because it contains extra,
unchangeable wording like "evaluation of constant value failed" and "the
evaluated program panicked at", which may be a bit confusing) than the
message generated by the macros themselves, but it's a price we have to
pay unfortunately.
Note that this check may seem cosmetic and purely for better user
experience, but it is in fact needed to avoid generating not-well-formed
and/or not-namespace-well-formed XML: As `AsXml` generates `xso::Item`,
where each attribute is emitted separated (and not aggregated in a
map structure), a naive (and efficient) implementation of a writer might
not double-check that no duplicate attributes are generated.
This allows exactly one arbitrary payload in any element, and is handled
after every other element with a more specific matcher has been parsed.
Both the #[xml(element(n = 1))] meta and its shortcut #[xml(element)]
are allowed and treated the exact same way.
The case this affects is a field like:
```
struct Foo {
#[xml(extract(fields(text(type_ = String)), namespace = .., name = ..))]
foo: ServiceType,
}
```
Before, we get this:
```
error[E0631]: type mismatch in closure arguments
--> muchopper/libmuchopper/src/xmpp/sjn_api.rs:188:10
|
188 | #[derive(AsXml)]
| ^^^^^
| |
| expected due to this
| found signature defined here
|
= note: expected closure signature `fn(&ServiceType) -> _`
found closure signature `fn(&'xso_proc_as_xml_iter_lifetime std::string::String) -> _`
note: required by a bound in `std::option::Option::<T>::map`
--> /home/jssfr/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:1102:12
|
1100 | pub fn map<U, F>(self, f: F) -> Option<U>
| --- required by a bound in this associated function
1101 | where
1102 | F: FnOnce(T) -> U,
| ^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
= note: this error originates in the derive macro `AsXml` (in Nightly builds, run with -Z macro-backtrace for more info)
```
Afterwards, this:
```
error[E0308]: mismatched types
--> muchopper/libmuchopper/src/xmpp/sjn_api.rs:207:20
|
206 | #[xml(extract(namespace = ECS, name = "service-type", fields(text(type_ = String))))]
| ------ expected due to this
207 | pub service_type: ServiceType,
| ^^^^^^^^^^^ expected `Option<&String>`, found `Option<&ServiceType>`
|
= note: expected enum `std::option::Option<&'xso_proc_as_xml_iter_lifetime std::string::String>`
found enum `std::option::Option<&ServiceType>`
```
skip-changelog, because this affects a feature which already has an
"Added" line in the changelog.
This reverts commit 4e5f0bc961.
Unfortunately, in std contexts, the `alloc` crate is not imported. That
means we cannot rely on it being accessible and it in fact breaks builds
of crates which are not `no_std`.
Fixes#155.
The old error message was pointing at the `FromXml` / `AsXml` invocation
and not on the field which actually caused the problem. The new error
message points exactly at the type of the affected field.
This declutters the main `xso` namespace. In addition, if (when) we
introduce more complex generic implementations, we might want to have
tests for these, and those can then live there, too, without making the
main `lib.rs` file gigantic (or moving the tests too far away from the
tested code).
This decreases indentation levels on the various implemenations, it
groups the implementations together physically, and (spoiler alert!)
we'll actually need the dyn Field trait object-ness (much) later on.