1
0
mirror of https://gitlab.com/xmpp-rs/xmpp-rs.git synced 2024-06-26 17:08:26 +02:00
Commit Graph

19 Commits

Author SHA1 Message Date
Jonas Schäfer
d623b6ab9b parsers-macros: wrap Extend trait into TryExtend for flexibility
This allows containers to reject items based on their content, without
having to resort to a panic.

The use case is containers which are polymorphic, but don't support
different item types, as encountered e.g. in XEP-0060 PubSub publish vs.
retract events.
2024-04-05 15:53:48 +02:00
Jonas Schäfer
decbeb351f parsers-macros: introduce Field trait and object
This simplifies the code of FieldDef and makes it more extensible for
future ideas.
2024-04-05 15:53:48 +02:00
Jonas Schäfer
61caae9966 parsers-macros: consistently use quote_spanned for type casts
This produces much better error messages, because they will point at
the type which fails to implement a trait instead of the macro
invocation.
2024-04-05 15:53:48 +02:00
Jonas Schäfer
e8e6b12fd2 parsers-macros: implement support for extended child destructuring 2024-04-05 15:53:48 +02:00
Jonas Schäfer
c0ea48f22f parsers-macros: add options to override behavior for unknown things 2024-04-05 15:53:48 +02:00
Jonas Schäfer
5ae0bbea51 parsers-macros: add support for namespace = super on child fields
This constrains the namespace of the field to the same namespace the
parent currently has and can only be used on namespace = dyn.
2024-04-05 15:53:48 +02:00
Jonas Schäfer
eae3efc1de parsers-macros: add support for custom defaulting
This adds support for using a custom function to create a default value
during parsing instead of relying on [`std::default::Default`].
2024-04-05 15:53:48 +02:00
Jonas Schäfer
953de151c8 parsers-macros: add support for skip_if on child/children fields 2024-04-05 15:53:48 +02:00
Jonas Schäfer
3983e0d705 parsers-macros: merge ExtractMeta into XmlFieldMeta
This transforms the `extract(..)` spec into something extremely close to
a real struct type def, with the full flexibility that gives.
2024-04-05 15:53:48 +02:00
Jonas Schäfer
df0c20efde parsers-macros: add support for switching on an attribute key/value pair
Needed for the `http_upload::Header` enum, but could also be interesting
to use on an IQ stanza in the future.
2024-04-05 15:53:48 +02:00
Jonas Schäfer
e5cee6d5b0 parsers-macros: refactor element matching and parsing once more
The Compound abstraction was incorrect, as can be seen by the huge
amount of edge cases handled in obscure match statements on the
`namesace` field.

Attempting to generalize this to allow building enums which switch on an
attribute value instead of a XML element name turned out to be horror
trip.

This new abstraction has much more clear-cut responsibilities:

- Compound (de-)structures Rust fields into/from Elements.
- StructInner handles everything related to struct-like things (enum
  variants and structs), with the exception of validation/preparation.
- StructDef handles validation and preparation on top of StructInner.

And then enums get the differentiation within the type system they
deserve: Those which are fully dynamic and those which are switched on
the XML element's name. That abstraction turns out to be so useful that
it probably very straightforwardly will generalize into matching on
attribute names instead.

All in all, this should be good.
2024-04-05 15:53:48 +02:00
Jonas Schäfer
e3f405377d parsers-macros: Rework extract(..) typing
The previous approach used a lot of weird heuristics and was also not
flexible enough to handle bodies of XMPP message stanzas: Those use an
optional `xml:lang` attribute [1], the absence of which should be
preserved through a roundtrip through the Rust structs.

This sounds simple: Just invent a String newtype which does not emit an
attribute if the string is empty, right?

Yes, but: We cannot specify that type for the attribute. `extract(..)`
does not allow specifying types, it just assumes `String` for anything
text-like (text and attributes). This works because the macros add an
extra conversion layer for that special case.

That obviously breaks down under such circumstances, so this commit
revamps the entire thing.

One can now specify types on extractions, but in many cases it's
optional: they are inferred from the field type for extractions on
`#[xml(child)]` fields, and otherwise they default to String for
text-like extractions (so just like before). Only when you attempt to
extract a non-String type into a collection you'll have to specify the
type explicitly.

This also obsoletes the quirky `XmlDataItem` trait.

   [1]: Actually, it's a bit more tricky: `xml:lang` is inherited from
        parent elements according to the XML specification, so it is
        rarely fully optional.
2024-04-05 15:53:48 +02:00
Jonas Schäfer
55e4287420 parsers-macros: implement #[xml(namespace = super)] on extracted fields
This expands the usability of these fields to structs with
`#[xml(namespace = dyn)]`.
2024-04-05 15:53:48 +02:00
Jonas Schäfer
fbac723c4d parsers-macros: implement support for dynamic namespaces
Dynamic namespaces are useful for elements which may reside in either of
multiple namespaces. The main use-case for this is stanzas in an XML
stream, which may be in e.g. the `jabber:client` or `jabber:server`
namespaces.
2024-04-05 15:53:48 +02:00
Jonas Schäfer
c0e8a3d50b parsers-macros: Unify error message generation
This provides more consistent error messages and is the stepping stone
in an attempt to include as much as possible information in every error.
2024-04-05 15:53:48 +02:00
Jonas Schäfer
610477242d parsers-core, parsers-macros: Rename traits
The new names hopefully improve the clarity. The "Attribute" terminology
was replaced by "Optional", because that's what it's really about: The
value is *optional* because it may not be present on the protocol level
(attributes, or extracted child texts).

Likewise, "Text" was replaced by "XmlText", in anticipation of migrating
to CData at some point later and to distinguish it from arbitrary text.
2024-04-05 15:53:48 +02:00
Jonas Schäfer
f1dc7594e0 parsers-core, parsers-macros: Remove XmlDataCollection trait
This can be represented appropriately using Extend<T>, IntoIterator and
Default from the standard library. We keep the XmlDataItem trait for
flexibility though.
2024-04-05 15:53:48 +02:00
Jonas Schäfer
e0b528ceb7 parsers-core, parsers-macros: Remove XmlCollection trait
This can be represented appropriately using Extend<T>, IntoIterator and
Default from the standard library.
2024-04-05 15:53:48 +02:00
Jonas Schäfer
2b2bff1efa Implement #[derive(FromXml, IntoXml)]
This commit deserves some explanation.

1. Why move from the `macro_rules!` approach to a derive macro?

A derive macro is much more idiomatic to Rust. The `macro_rules!`-based
approach, while pretty clever and full-featured, is very opaque and
unclear to crate (but not partiuclarly Rust) newcomers. Not to mention
that the implementation, with all the variations it handles in the
rather functional macro_rules!-language, got very unwieldly and hard to
maintain.

2. Why add a `xmpp_parsers_core` crate? What is its purpose and its
   relation to `xmpp_parsers` and `xmpp_parsers_macros`?

From the code generated within the derive macro, we have to refer to
some traits and/or types we define. We cannot define these in the
`xmpp_parsers_macros` crate, because proc macro crates can only export
proc macros, no other items.

We also need to refer to these types unambiguously. As we don't know
which names are imported in the scopes the derive macro is invoked in,
we have to use absolute paths (such as `::foo::bar`).

That means we need a crate name.

Now there are two non-options:

- We could use `crate::`. That has the downside that the derive macro
  is only useful within the `xmpp_parsers` crate. It cannot be used
  outside, unless the traits are re-imported there.

- We could use `::xmpp_parsers::..`, except, we can't: That would
  prevent use of the macro within `xmpp_parsers`, because crates cannot
  refer to themselves by name.

So the only way that makes sense is to have a `xmpp_parsers_core` crate
which contains the traits as well as some basic implementations needed
for the macros to work, re-export the derive macros from there, and
depend on that crate from `xmpp_parsers`.

3. Oh god this is complex, how do I learn more or hack on this??

Run `cargo doc --document-private-items`. The `xmpp_parsers_macros`
crate is fully documented in the private areas, and that makes that
documentation quite accessible in your browser.
2024-04-05 15:53:48 +02:00