Because this attribute may occur in random places, it makes no sense
failing on it. We discard it after attribute processing though, so it
can still be captured by structs which are explicitly interested in it.
The test case which is added fails to compile unless one puts the
`parent` field before the `id` field. The cause is explained somewhat by
the change, but I'll spell it out here nontheless.
Previously, the loop in `Compound::make_as_item_iter_statemachine`
assumed that the serialisation order of fields would match their
declaration order. That is not generally true: attributes must be
serialised before element content, because they must be emitted before
the element header is closed.
This change thus splits the generated states into "header" states (for
everything before the end of the element header (think `>`)) and
"body" states (for everything after and including the end of the
element header). After all fields have been processed, we can then
add the data fields of the body fields to the header states so that
they are carried through the generated state machine until they are
needed in the body.
They really clutter the documentation, because they show up in the
module's index. Downside is that users can't inspect the documentation
of those types anymore, but it's not useful anyway: the parts are
private and they just impl some traits.
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.
This avoids the need for an expensive clone. Since we switched to AsXml
instead of IntoXml, we don't necessarily have to clone the data when
building new elements, only when it's absolutely necessary. The clones
then happen implicitly in the ItemToEvent iterator used internally.
This mostly fixes#86, with the caveat that there's no absolutely cheap
test: On success, the entire element will be copied, while on failure,
you learn about it rather quickly.
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.
These more closely mirror how enums work currently with the macros.
Non-exhaustive enums may be useful though and kind of were the natural
thing to implement.
Previously, if you put `codec = FixedHex<20>.filtered(..)`, it would
cause a confusing "expected `,`" message at the place of the `.`. This
code adds a helpful "try adding a `::` before the `<`" message pointing
at the `<` in the type path.
We can do this because we know that `x < y` cannot create a
`TextCodec<T>` for any `T`. This is because `<` is guaranteed to return
a boolean value, and we simply don't implement `TextCodec<T>` on bool.
This allows stateful or configurable codecs without having to express
all configuration in the type name itself. For example, we could have a
Base64 type with configurable Base64 engines without having to duplicate
the Base64 type itself.
(Note that the different engines in the Base64 crate are values, not
types.)