1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
#![deny(missing_docs)]
/*!
# Core types, macros and traits for parsing structs from XML

This crate provides the facilities for parsing XML data into Rust structs, and
vice versa. Think of it as an alternative[^serde-note] to serde, more suited to
XML.

To get started, use the [`FromXml`] and [`IntoXml`] derive macros
on your struct. See in particular the documentation of [`FromXml`] for
a full reference on the supported attributes.

XSO is an acronym for XML Stream(ed) Objects, referring to the main field of
use of this library in parsing XML streams like specified in RFC 6120.

[^serde-note]: Though it should be said that you can combine serde and this
    crate on the same struct, no problem with that!
*/
pub mod error;
mod text;

#[doc(inline)]
pub use text::*;
/**
# Make a struct or enum parseable from XML

This macro generates the necessary trait implementations to convert a struct
from XML.

In order to work, structs, enums, enum variants and fields all must be
annotated using the `#[xml(..)]` meta. The insides of that meta are explained
below.

## Examples

```
# use xso::{FromXml};
static MY_NAMESPACE: &'static str = "urn:uuid:55c56882-3915-49de-a7ee-fd672d7a85cf";

#[derive(FromXml)]
#[xml(namespace = MY_NAMESPACE, name = "foo")]
struct Foo;

// parses <foo xmlns="urn:uuid:55c56882-3915-49de-a7ee-fd672d7a85cf"/>
```

## Field order

Field order **matters**. The fields are parsed in the order they are declared
(for children, anyway). If multiple fields match a given child element, the
first field which matches will be taken. The only exception is
`#[xml(elements)]` (without further arguments), which is always processed
last.

When XML is generated from a struct, the child elements are also generated
in the order of the fields. That means that passing an XML element through
FromXml and IntoXml may re-order some child elements.

Sorting order between elements which match the same field is generally
preserved, if the container preserves sort order on insertion.

## Struct attributes

- `namespace = ..`: This can be one of the following:

    - `dyn`: allows dynamic namespace matching using the [`DynNamespaceEnum`]
      trait. A struct with this namespace type needs to have exactly one field
      with the `#[xml(namespace)]` annotation.

      The type of that field must implement [`DynNamespaceEnum`] and will be
      used to match the namespace of the XML elements.
    - A path referring to a `&'static str` `static` which contains the
      namespace URI of the XML element represented by the struct.

  Required on non-`transparent` structs.

- `name = ..`: A string literal which contains the local XML name of
  of the XML element represented by the struct.

  Required on non-`transparent` structs.

- `validate = ..`: A path referring to a
  `fn(&mut T) -> Result<(), xso::error::Error>`, where `T` is the
  struct which is being defined. If set, the function will be called after
  parsing has completed. If it returns an error, that error is returned
  instead of the struct.

  This attribute has no influence on [`IntoXml`].

- `prepare = ..`: A path referring to a
  `fn(&mut T) -> ()`, where `T` is the struct which is being defined. If set,
  the function will be called before the struct is converted into Element.

  This attribute has no influence on [`FromXml`].

- `transparent`: Only allowed on tuple-like structs with exactly one field.
  If set, the parsing is fully delegated to the inner field, which must in
  turn implement `FromXml` (or `IntoXml` respectively).

  Attributes on the single struct field are rejected.

  `validate` is allowed and will be called.

- `element`, `element(..): Only allowed on tuple-like structs with exactly one
  field. That field must be of type [`minidom::Element`].

  Supports the following optional inner attributes:

  - `namespace`: If given, restricts the namespace of the elements to parse.
    Has no influence on XML generation: If the inner element has a different
    namespace when the struct is serialized, that namespace will be used.

  - `name`: If given, restricts the XML name of the elements to parse.
    Has no influence on XML generation: If the inner element has a different
    XML name when the struct is serialized, that namespace will be used.

  `validate` is allowed and will be called.

- `on_unknown_child = ..` may be set to the identifier of a member of the
  [`UnknownChildPolicy`] enum (i.e. for example `on_unknown_child = Ignore`).
  This configures the behavior when unknown child elements are encountered.
  See [`UnknownChildPolicy`] for details.

  Has no effect on grandchildren.

- `on_unknown_attribute = ..` may be set to the identifier of a member of the
  [`UnknownAttributePolicy`] enum (i.e. for example
  `on_unknown_attribute = Ignore`). This configures the behavior when unknown
  attributes are encountered. See [`UnknownAttributePolicy`] for details.

  Has no effect on children.

- `wrapped_with(namespace = .., name = ..)`: If set, the struct will be wrapped
  into an XML element with the given namespace and name. That means that
  instead of `<inner/>`, on the wire, `<outer><inner/></outer>` (with the
  corresponding XML names and namespaces) is expected and generated.

  Other than the struct itself, the wrapping element must not have any
  attributes or child elements, and it only supports static namespaces.

## Enums

Enums come in multiple flavors. All flavors have the following attributes:

- `validate = ..`: See struct attributes.
- `prepare = ..`: See struct attributes.
- `wrapped_with = ..`: See struct attributes.

The following flavors exist:

- fully dynamic: The variants must be each either transparent or specify
  their `namespace` and `name`.

- XML name matched: The enum itself defines a namespace. Each variant must
  then specify the name. The variant is picked based on the name of the XML
  element.

- XML attribute matched: The enum itself defines a namespace, a name and an
  attribute name. Each variant must specify the attribute value. The variant
  is picked based on the value of the given attribute, provided that XML name
  and namespace of the element itself match.

The flavor is determined based on the attributes of the enum declaration.

### Dynamic enums

No additional attributes are available on dynamic enumerations.

#### Dynamic enum variants

Dynamic enum variants work exactly like structs, except that the `prepare`
and `validate` attributes are not available.

### XML name matched enums

XML name matched enums support the following attributes:

- `namespace = ..` (required): This must be a path to a `&'static str`. It is
  the namespace of the enumeration.

- `exhaustive` (flag): If present, the enum considers itself authoritative for
  that namespace. If it encounters an element within the namespace which does
  not match any variant, a fatal parsing error is returned.

  This cannot be used if a variant is set as `fallback`.

  This attribute has no relation to the Rust standard `#[non_exhaustive]`
  attribute.

#### XML name matched enum variants

XML name matched enum variants support the following attributes:

- `name = ..` (required): String literal with the XML name to match against.

- `fallback` (flag): If present, the variant is parsed when no other variant
  matches.

  *Note:* When the enum is reserialized to XML, the XML name will be the one
  declared in the `name` attribute of the variant; the original XML name is
  lost.

### XML attribute matched enums

XML attribute matched enums support the following attributes:

- `namespace = ..` (required): This must be a path to a `&'static str`. It is
  the namespace of the enumeration.

- `name = ..` (required): This must be a string literal containing the XML
  name to match against.

- `attribute = ..` (required): This must be a string literal with the name of
  the XML attribute to match against.

- `exhaustive` (flag): Must currently be set unless a variant is marked as
  `fallback`. Support for non-exhaustive attribute-matched enums is not
  implemented yet.

  This cannot be used if a variant is set as `fallback`.

  This attribute has no relation to the Rust standard `#[non_exhaustive]`
  attribute.

- `normalize_with = ..`: Optional path to a thing which can be called with a
  `&str` and which returns a [`std::borrow::Cow`]. If present, the attribute
  value will be passed through that callable before it will be matched against
  the enum variants.

#### XML attribute matched enum variants

XML attribute matched enum variants support the following attributes:

- `value = ..` (required): String literal with the attribute value to match
  against.

- `fallback` (flag): If present, the variant is parsed when no other variant
  matches.

  *Note:* When the enum is reserialized to XML, the attribute value will be
  the one declared in the `value` attribute of the variant; the original value
  is lost.

## Field attributes

Field attributes are composed of a field kind, followed by a value or a list
of attributes. Examples:

```
# use xso::FromXml;
# static NS: &'static str = "urn:uuid:55c56882-3915-49de-a7ee-fd672d7a85cf";
# #[derive(FromXml)]
# #[xml(namespace = NS, name = "foo")]
# struct Foo {
#[xml(attribute)]
# f1: String,
#[xml(attribute = "foo")]
# f2: String,
#[xml(attribute(name = "foo"))]
# f3: String,
# }
```

If the `kind = ..` syntax is allowed, the attribute which is specified that
way will be marked as `default`.

The following field kinds are available:

- `attribute`, `attribute = name`, `attribute(..)`:
  Extract a string from an XML attribute. The field type must
  implement `FromOptionalXmlText` (for [`FromXml`]) or
  `IntoOptionalXmlText` (for [`IntoXml`]), unless the `codec` option is
  set.

    - `name = ..` (default): The XML name of the attribute. If this is not
      set, the field's identifier is used.
    - `namespace = ..`: The XML namespace of the attribute. This is optional,
      and if absent, only unnamespaced attributes are considered.
    - `default`, `default = ..`: If set, a field value is generated if the
      attribute is not present and [`FromOptionalXmlText`] did not create a
      value from [`None`], instead of failing to parse. If the optional
      argument is present, it must be the path to a callable which returns the
      field's type. Otherwise, [`std::default::Default::default`] is used.
    - `codec = ..`: Path to a type implementing [`TextCodec`] to use instead
      of the [`FromOptionalXmlText`] / [`IntoOptionalXmlText`] implementation
      of the field's type.

      If set, you need to explicitly add the `default` flag to fields of type
      `Option<_>`, because the default option logic of [`FromOptionalXmlText`]
      is not present.

- `child(.., extract(..))`: Extract data from a child element.

  - `name = ..` (required): The XML name of the child to match.
  - `namespace = ..` (required): The XML namespace of the child to match. This
    can be one of the following:

    - A path referring to a `&'static str` `static` which contains the
      namespace URI of the XML element represented by the struct.
    - `super`: Only usable inside compounds with `#[xml(namespace = dyn)]`,
      using `#[xml(namespace = super)]` on an extracted field allows to match
      the field's child's namespace with the dynamically determined namespace
      of the parent (both during serialisation and during deserialisation).

  - `extract(..)` (required): Specification of data to extract. See below
     for options.
  - `skip_if`: If set, this must be the path to a callable. That callable is
    invoked with a reference to the field's type at serialisation time. If
    the callable returns true, the field is omitted from the output
    completely.

    This should often be combined with `default`.
  - `default`, `default = ..`: If set, a field value is generated if the
    child is not present instead of failing to parse. If the optional argument
    is present, it must be the path to a callable which returns the field's
    type. Otherwise, [`std::default::Default::default`] is used.

    *Note:* When using `extract(..)`, this is required even when the field's
    type is `Option<..>`.


- `child`, `child(..)` (without `extract(..)`): Extract an entire child
  element. The field type must implement [`FromXml`] (for [`FromXml`])
  or `IntoXml` (for [`IntoXml`]).

  - `namespace = super`: If set, the field must also implement
    [`DynNamespace`] and the compound the field is in must be set to be
    `namespace = dyn`. In this case, the field's child is forced to be in the
    same namespace as the parent during parsing.
  - `skip_if`: If set, this must be the path to a callable. That callable is
    invoked with a reference to the field's type at serialisation time. If
    the callable returns true, the field is omitted from the output
    completely.

    This should often be combined with `default`.
  - `default`, `default = ..`: If set, a field value is generated if the
    child is not present instead of failing to parse. If the optional argument
    is present, it must be the path to a callable which returns the field's
    type. Otherwise, [`std::default::Default::default`] is used.

    *Note:* When using `extract(..)`, this is required even when the field's
    type is `Option<..>`.

  Aside from `namespace = super`, matching of the XML namespace / name is
  completely delegated to the [`FromXml`] implementation of the field's type
  and thus the `namespace` and `name` attributes are not allowed.

- `children(.., extract(..))`: Like `child(.., extract(..))`, with the following
  differences:

    - More than one clause inside `extract(..)` are allowed.
    - More than one matching child is allowed
    - The field type must implement [`Default`][`std::default::Default`],
      [`Extend<T>`][`std::iter::Extend`] and
      [`IntoIterator<Item = T>`][`std::iter::IntoIterator`].

      `T`, must be a tuple type matching the types provided by the
      extracted parts.
    - Extracts must specify their type, because it cannot be inferred through
      the collection.

- `children`, `children(..)` (without `extract(..)`): Extract zero or more
  entire child elements. The field type must implement
  [`Default`][`std::default::Default`],
  [`Extend<T>`][`std::iter::Extend`] and
  [`IntoIterator<Item = T>`][`std::iter::IntoIterator`], where `T`
  implements [`FromXml`] (and [`IntoXml`] for [`IntoXml`]).

  - `skip_if`: If set, this must be the path to a callable. That callable is
    invoked with a reference to the field's type at serialisation time. If
    the callable returns true, the field is omitted from the output
    completely.

    This should often be combined with `default`.

  The namespace and name to match are determined by the field type, thus it
  is not allowed to specify them here. `namespace = super` is not supported.

- `text`, `text(..): Extract the element's text contents. The field type must
  implement `FromXmlText` (for [`FromXml`]) or `IntoXmlText`
  (for [`IntoXml`]), unless the `codec` option is set.

    - `codec = ..`: Path to a type implementing [`TextCodec`] to use instead
      of the [`FromXmlText`] / [`IntoXmlText`] implementation of the field's
      type.

- `element`, `element(..)`: Collect a single element as [`minidom::Element`]
  instead of attempting to destructure it. The field type must implement
  `From<Element>` and `Into<Option<Element>>` ([`minidom::Element`] implements
  both).

  - `name = ..` (optional): The XML name of the element to match.
  - `namespace = ..` (optional): The XML namespace of the element to match.
  - `default`, `default = ..`: If set, a field value is generated if the
    child is not present instead of failing to parse. If the optional argument
    is present, it must be the path to a callable which returns the field's
    type. Otherwise, [`std::default::Default::default`] is used.

  If the field converts into `None` when invoking `Into<Option<Element>>`,
  the element is omitted from the output altogether.

- `elements(..)`: Collect otherwise unknown children as [`minidom::Element`].

  - `namespace = ..`: The XML namespace of the element to match.
  - `name = ..` (optional): The XML name of the element to match. If omitted,
    all elements from the given namespace are collected.

- `elements`: Collect all unknown children as [`minidom::Element`]. The field
  type must be `Vec<Element>`.

- `namespace`: Represent the parent struct/enum variant's XML namespace. This
  requires that the compound is declared with `#[xml(namespace = dyn)]`. The
  field type must implement [`DynNamespaceEnum`].

- `ignore`: The field is not considered during parsing or serialisation. The
  type must implement [`Default`].

### Extraction specification

Inside `extract(..)`, there must be a list of type annotations as used on
fields. All annotations can be used which can also be used on fields. Because
here there is no possibility to do any inferrence on the field type, the
following field attributes support an additional, optional `type` argument:

- `attribute`
- `text`

If the `extract(..)` contains exactly one part and the type of the extract
is not specified on that one part, it is assumed to be equal to the type of
the field the extract is used on.

Otherwise, the default is `String`, which is not going to work in many cases.
This limitation could be lifted, but we need a use case for it first :). So
if you run into this file an issue please!

*/
pub use xso_proc::FromXml;

/**
# Make a struct or enum convertible into XML

For all supported attributes, please see [`FromXml`].
*/
pub use xso_proc::IntoXml;

/**
# Make a struct fully dynamically namespaceable

For all supported attributes, please see [`FromXml`].
*/
pub use xso_proc::DynNamespace;

#[doc(hidden)]
pub mod exports {
    pub use minidom;
}

use jid::{BareJid, FullJid, Jid};

macro_rules! from_text_via_parse {
    ($cons:path, $($t:ty,)+) => {
        $(
            impl FromXmlText for $t {
                fn from_xml_text(s: &str) -> Result<Self, error::Error> {
                    s.parse().map_err($cons)
                }
            }

            impl IntoXmlText for $t {
                fn into_xml_text(self) -> String {
                    self.to_string()
                }
            }
        )+
    }
}

macro_rules! from_text_via_parse_swallow_error {
    ($($t:ty,)+) => {
        $(
            impl FromXmlText for $t {
                fn from_xml_text(s: &str) -> Result<Self, error::Error> {
                    s.parse().map_err(|_| error::Error::ParseError(concat!("invalid ", stringify!($t))))
                }
            }

            impl IntoXmlText for $t {
                fn into_xml_text(self) -> String {
                    self.to_string()
                }
            }
        )+
    }
}

from_text_via_parse! {
    error::Error::ParseIntError,
    u8,
    u16,
    u32,
    u64,
    u128,
    usize,
    i8,
    i16,
    i32,
    i64,
    i128,
    isize,
}

from_text_via_parse_swallow_error! {
    f32,
    f64,
}

from_text_via_parse! {
    error::Error::ParseAddrError,
    std::net::IpAddr,
    std::net::Ipv4Addr,
    std::net::Ipv6Addr,
}

from_text_via_parse! {
    error::Error::JidParseError,
    Jid,
    FullJid,
    BareJid,
}

/// Convert XML text to a value.
pub trait FromXmlText: Sized {
    /// Construct a value from XML text.
    ///
    /// This is similar to [`std::str::FromStr`], but the error type is fixed.
    fn from_xml_text(s: &str) -> Result<Self, error::Error>;
}

impl FromXmlText for String {
    /// Copy the string from the source into the result.
    fn from_xml_text(s: &str) -> Result<Self, error::Error> {
        Ok(s.to_string())
    }
}

/// Convert a value into XML text.
pub trait IntoXmlText {
    /// Consume the value and return it as XML string.
    fn into_xml_text(self) -> String;
}

impl IntoXmlText for String {
    fn into_xml_text(self) -> String {
        self
    }
}

/// Provide construction of a value from optional XML text data.
///
/// Most likely, you don't need to implement this; implement [`FromXmlText`]
/// instead (which automatically provides a [`FromOptionalXmlText`]
/// implementation).
///
/// This trait has to exist to handle the special-ness of `Option<_>` when it
/// comes to values which don't always exist.
pub trait FromOptionalXmlText: Sized {
    /// Convert the XML string to a value, maybe.
    ///
    /// This should return `None` if and only if `s` is `None`, but in some
    /// cases it makes sense to return `Some(..)` even for an input of
    /// `None`, e.g. when a specific default is desired.
    fn from_optional_xml_text(s: Option<&str>) -> Result<Option<Self>, error::Error>;
}

impl<T: FromXmlText> FromOptionalXmlText for T {
    fn from_optional_xml_text(s: Option<&str>) -> Result<Option<Self>, error::Error> {
        s.map(T::from_xml_text).transpose()
    }
}

impl<T: FromOptionalXmlText> FromOptionalXmlText for Option<T> {
    /// This implementation returns `Some(None)` for an input of `None`.
    ///
    /// That way, absent attributes with a `Option<T>` field type effectively
    /// default to `None`.
    fn from_optional_xml_text(s: Option<&str>) -> Result<Option<Self>, error::Error> {
        match s {
            None => Ok(Some(None)),
            Some(v) => Ok(Some(T::from_optional_xml_text(Some(v))?)),
        }
    }
}

/// Provide destruction of a value into optional XML text data.
///
/// Most likely, you don't need to implement this; implement [`IntoXmlText`]
/// instead (which automatically provides a [`IntoOptionalXmlText`]
/// implementation).
///
/// This trait has to exist to handle the special-ness of `Option<_>` when it
/// comes to values which don't always exist.
pub trait IntoOptionalXmlText {
    /// Destruct the value into an optional string.
    ///
    /// Returning `None` causes the resulting XML object (likely an attribute,
    /// but maybe also an extracted child) to not appear in the output.
    fn into_optional_xml_text(self) -> Option<String>;
}

impl<T: IntoXmlText> IntoOptionalXmlText for T {
    fn into_optional_xml_text(self) -> Option<String> {
        Some(self.into_xml_text())
    }
}

impl<T: IntoOptionalXmlText> IntoOptionalXmlText for Option<T> {
    fn into_optional_xml_text(self) -> Option<String> {
        match self {
            None => None,
            Some(v) => v.into_optional_xml_text(),
        }
    }
}

/// Discard the value and do not emit a value.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Discard;

impl FromXmlText for Discard {
    fn from_xml_text(_: &str) -> Result<Self, error::Error> {
        Ok(Self)
    }
}

impl IntoOptionalXmlText for Discard {
    fn into_optional_xml_text(self) -> Option<String> {
        None
    }
}

/// Provide construction of structs from XML (sub-)trees.
///
/// This trait is what is really implemented by the [`FromXml`] derive
/// macro.
pub trait FromXml: Sized {
    /// Convert an XML subtree into a struct or fail with an error.
    fn from_tree(tree: minidom::Element) -> Result<Self, error::Error>;

    /// Provide an optional default if the element is absent.
    ///
    /// This is used to automatically make `Option<T>` default to `None`.
    fn absent() -> Option<Self>;
}

impl<T: FromXml> FromXml for Option<T> {
    fn from_tree(tree: minidom::Element) -> Result<Self, error::Error> {
        Ok(Some(T::from_tree(tree)?))
    }

    fn absent() -> Option<Self> {
        Some(T::absent())
    }
}

/// Convert a struct into an XML tree.
///
/// This trait is what is really implemented by the [`IntoXml`] derive
/// macro.
pub trait IntoXml {
    /// Destruct the value into an optional [`minidom::Element`].
    ///
    /// When returning `None`, no element will appear in the output. This
    /// should only be used for values which can be constructed via
    /// [`FromXml::absent`] in order to ensure that the result can be parsed
    /// again.
    fn into_tree(self) -> Option<minidom::Element>;
}

impl<T: IntoXml> IntoXml for Option<T> {
    fn into_tree(self) -> Option<minidom::Element> {
        self?.into_tree()
    }
}

/// Enumeration of possible dynamically determined namespaces.
///
/// This trait must be implemented on types used on `#[xml(namespace)]`
/// fields.
///
/// It allows to specify XML elements which can be parsed in different
/// namespaces. This can be useful in weird protocols (looking at you, XMPP)
/// where the same element occurs in multiple different namespaces. The
/// namespace is then kept in the field and is thus available at serialisation
/// time.
///
/// This trait depends on `PartialEq<str>`; this is used to compare a value
/// against the value of an `xmlns` attribute without requiring to go through
/// (potentially costly and also error-inducing) [`Self::from_xml_text`].
pub trait DynNamespaceEnum: Sized + PartialEq<str> {
    /// Parse the namespace from the `xmlns` attribute data.
    ///
    /// This should return [`Mismatch`][`crate::error::DynNamespaceError`] for
    /// namespaces which are not part of the enumeration of matching
    /// namespaces. In such cases, the parser may attempt to parse using
    /// another [`FromXml`] implementation.
    ///
    /// You can also return [`Invalid`][`crate::error::DynNamespaceError`] to
    /// abort parsing altogether; this is probably not what you want, though.
    fn from_xml_text(s: &str) -> Result<Self, self::error::DynNamespaceError>;

    /// Convert the namespace into the text value of an `xmlns` attribute.
    fn into_xml_text(self) -> String;
}

/// Trait for structs implementing [`FromXml`] with `namespace = dyn`.
///
/// This allows to access the namespace of these structs without needing
/// knowledge about their internal structure.
pub trait DynNamespace {
    /// The namespace enum for this struct.
    type Namespace: DynNamespaceEnum;

    /// Return a reference to the struct's namespace.
    fn namespace(&self) -> &Self::Namespace;

    /// Recursively set this struct's namespace.
    ///
    /// This will set the namespace for the struct itself as well as for
    /// fields referring to child structs with `namespace = super`.
    fn set_namespace<T: Into<Self::Namespace>>(&mut self, ns: T);
}

/// Configure how unknown child elements are handled.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum UnknownChildPolicy {
    /// Fail parsing with a fatal error.
    #[cfg_attr(not(feature = "disable-validation"), default)]
    Fail,

    /// Ignore and discard any unknown child elements.
    #[cfg_attr(feature = "disable-validation", default)]
    Ignore,
}

impl UnknownChildPolicy {
    // TODO: once we have a more suitable error message structure, we should
    // not pass the entire message down to this function.
    /// Return a result describing the result of triggering the child policy.
    ///
    /// In other words, this returns an error iff the policy is set to
    /// `Fail`.
    ///
    /// **Note:** This function is not to be considered part of the public
    /// API! It is only marked `pub` because it needs to be called from
    /// macro-generated code! Its signature and behavior may change without
    /// notice and without major version bump at any time.
    pub fn trigger(&self, msg: &'static str) -> Result<(), error::Error> {
        match self {
            Self::Fail => Err(error::Error::ParseError(msg)),
            Self::Ignore => Ok(()),
        }
    }
}

/// Configure how unknown attributes are handled.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum UnknownAttributePolicy {
    /// Fail parsing with a fatal error.
    #[cfg_attr(not(feature = "disable-validation"), default)]
    Fail,

    /// Ignore and discard any unknown attributes.
    #[cfg_attr(feature = "disable-validation", default)]
    Ignore,
}

impl UnknownAttributePolicy {
    // TODO: once we have a more suitable error message structure, we should
    // not pass the entire message down to this function.
    /// Return a result describing the result of triggering the attribute
    /// policy.
    ///
    /// In other words, this returns an error iff the policy is set to
    /// `Fail`.
    ///
    /// **Note:** This function is not to be considered part of the public
    /// API! It is only marked `pub` because it needs to be called from
    /// macro-generated code! Its signature and behavior may change without
    /// notice and without major version bump at any time.
    pub fn trigger(&self, msg: &'static str) -> Result<(), error::Error> {
        match self {
            Self::Fail => Err(error::Error::ParseError(msg)),
            Self::Ignore => Ok(()),
        }
    }
}

/// Trait to support destructuring of child structs beyond what the
/// `extract(..)` attribute can deliver.
///
/// This trait can only be sensibly implemented on types which implement both
/// `FromXml` and `IntoXml`. However, as there may be corner cases where only
/// one of these other traits is needed, they're not strictly included in the
/// trait bounds.
///
/// When used as value for `codec = ..` inside a `#[xml(child(..))]` or
/// `#[xml(children(..))]` field attribute, the field is destructured using
/// the trait implementations of `FromXml` / `IntoXml` and then converted
/// to the actual field's type by invoking the `ElementCodec<T>` methods, with
/// `T` being the field type.
pub trait ElementCodec<T> {
    /// Transform the destructured value further toward the field type.
    fn decode(value: Self) -> T;

    /// Transform the field type back to something which can be structured
    /// into XML.
    fn encode(value: T) -> Self;
}

impl<T> ElementCodec<T> for T {
    fn decode(value: Self) -> Self {
        value
    }

    fn encode(value: Self) -> Self {
        value
    }
}

/// Trait for fallible extension.
///
/// You probably won't need to implement this---it is automatically implemented
/// for all containers which implement [`std::iter::Extend`].
///
/// The only useful case are containers where an extension may fail because of
/// data reasons, e.g. if you collect elements of multiple types but it can
/// only contain a single type at a time.
pub trait TryExtend<A> {
    /// Attempt extending the container with the given iterator.
    ///
    /// Upon error, the container may be partially extended.
    fn try_extend<T: IntoIterator<Item = A>>(&mut self, iter: T) -> Result<(), self::error::Error>;
}

impl<A, T: Extend<A>> TryExtend<A> for T {
    fn try_extend<I: IntoIterator<Item = A>>(&mut self, iter: I) -> Result<(), self::error::Error> {
        self.extend(iter);
        Ok(())
    }
}