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
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
#![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 [`macro@FromXml`] and [`macro@IntoXml`] derive macros
on your struct. See in particular the documentation of [`macro@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 derives the [`FromXml`] trait. This trait (like [`IntoXml`] and
[`DynNamespace`]) can be derived on structs and enums.

Each Rust item (struct or enum) is mapped to an XML subtree, starting at the
header of an element. In order to fully describe this element, additional
information ("metadata" or short "meta") needs to be added to the Rust item
and its members.

For this, we use Rust attributes (similarly to how serde operates). Because
the "attribute" word is also used in the XML context, we will instead use the
term "meta", which is similar to the terminology used in the Rust language
reference itself.

## 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.

## Meta types

The values accepted by the Rust attributes (we call them "meta" here to
disambiguate between Rust and XML attributes) used by this crate may be of
one of the following types:

- *path*: A path is a (qualified) Rust name, such as `foo::bar`,
  `::std::vec::Vec`, or just `xyz`.
- *string literal*: A string literal, like `"Hello World!"`.
- *flag*: In that case, the meta does *not* accept a value. Its mere presence
  changes the behavior and it must not be followed by `=`.
- *ident* or *identifier*: A Rust identifier (such as `Foo` or `bar`), without
  path delimiters (`::`).
- *nested*: The meta is followed by more arguments wrapped in `()`.

## Struct, enum and enum variant metadata

These meta are available on structs, enums and/or enum variants. Almost all
meta listed here are available on structs. Some are only available on enums,
others are only available on enum variants.

| Meta | Type | Available on | Short description |
| --- | --- | --- | --- |
| [`namespace`](#namespace-meta-on-items) | path or `dyn` | *see below* | Specifies the XML namespace of the struct. |
| [`name`](#namespace-meta) | string literal | *see below* | Specifies the XML name of the struct. |
| [`attribute`](#attribute-meta-on-items) | string literal | *see below* | Specifies the XML attribute to match (enums only). |
| [`value`](#value-meta) | string literal | *see below* | Specifies the XML attribute's value to match (enum variants only). |
| [`validate`](#validate-meta) | path | enums | Function to allow validation or postprocessing of the item after parsing. |
| [`prepare`](#prepare-meta) | path | enums | Function to allow preprocessing of the item before serialisation. |
| [`on_unknown_attribute`](#on-unknown-attribute-meta) | ident | variants | [`UnknownAttributePolicy`] variant to use |
| [`on_unknown_child`](#on-unknown-child-meta) | ident | variants | [`UnknownChildPolicy`] variant to use |
| [`transparent`](#transparent-meta) | flag | variants | Transarently wrap the inner item. |
| [`element`](#element-meta-on-items) | flag or nested | variants | Transparently parse a [`minidom::Element`] |
| [`wrapped_with`](#wrapped-with-meta) | nested | enums | Add an XML wrapper around the item |
| [`fallback`](#fallback-meta) | flag | enum variants only | Mark the enum variant as fallback variant |
| [`exhaustive`](#exhaustive-meta) | flag | enums only | Mark the enum as exhaustive |
| [`normalize_with`](#normalize-with-meta) | path | enums only | Preprocess an attribute value before matching it |

### Struct (de-)serialisation

Structs can be laid out in three different ways:

- Normal struct: The XML namespace and name are fixed. The
  [`namespace`](#namespace-meta-on-items) and [`name`](#name-meta) meta must
  be set on the struct, and `transparent` or `element` cannot be set.

  The struct can have any contents, provided they are convertible to/from XML
  or have been marked as to be ignored.

- Transparent struct: The struct must have exactly one member and that member
  must be unnamed and it must implement `FromXml` and/or `IntoXml`. Such a
  struct has the [`transparent`](#transparent-meta) flag set and must not have
  `namespace`, `name` or `element` metas.

  The struct will be parsed and serialised using the member's implementations,
  but wrapped in the struct on the Rust level. The XML representation does not
  change.

- Element struct: The struct must have exactly one member and that member
  must be unnamed and must be of type [`minidom::Element`]. Such a
  struct has the [`element`](#element-meta-on-items) meta and must not have
  `namespace`, `name` or `transparent` metas.

  This struct may accept any XML subtree, provided its element header matches
  the additional optional selector in the `element` meta.

### Enum (de-)serialisation

For enums, there are three different modes for matching a given XML element
against the enum:

- Name matched: The XML namespace is fixed and the XML name determines the enum
  variant. The [`namespace`](#namespace-meta-on-items) meta is required on the
  enum and variants must have the [`name`](#name-meta) meta set.

- Attribute matched: The XML namespace and name are fixed. A specific XML
  attribute must exist on the element and its value determines the variant.
  variant. The [`namespace`](#namespace-meta-on-items), [`name`](#name-meta)
  and [`attribute`](#attribute-meta-on-items) meta must be set on the enum,
  and the [`value`](#value-meta) meta must be set on each variant.

- Fully dynamic: Each variant is matched separately. Each variant has almost
  the same behaviour as structs, with the notable difference that
  `prepare`, `validate` and `wrapped_with` are only available on the enum
  itself.

### Item meta reference

#### `namespace` meta (on items)

The `namespace` meta controls the XML namespace of the XML element
representing a Rust struct, enum, or enum variant. It may be specified in one
of two ways:

- A *path* which refers to a `&'static str` `static` which contains the
  namespace URI to match.

- The keyword `dyn`: The XML namespace is matched using a member field
  via the [`DynNamespaceEnum`] trait. For this to work, exactly one field
  must be marked with the [`namespace`](#namespace-on-members) meta and have
  a type implementing [`DynNamespaceEnum`].

#### `name` meta

The `name` meta controls the XML name of the XML element representing a Rust
struct, enum, or enum variant. It must be specified as string literal.

#### `attribute` meta (on items)

The `attribute` meta controls the XML attribute used for XML attribute value
matched enums. The attribute name must be specified as string literal.

Presence of this meta requires presence of the `namespace` and `name` metas
and is only allowed on enums.

#### `value` meta

The `value` meta controls the value of the XML attribute matched for XML
attribute value matched enums. It is only allowed on enum variants inside
enums which have the `attribute` meta.

#### `validate` meta

The `validate` meta is optional and allows specifying the name of a function
which is called after successful deserialisation. That function must have
the signature `fn(&mut T) -> Result<(), xso::error::Error>` where `T` is the
type of the Rust enum or struct on which this meta is declared.

#### `prepare` meta

The `prepare` meta is optional and allows specifying the name of a function
which is called before serialisation. That function must have the signature
`fn(&mut T) -> ()` where `T` is the type of the Rust enum or struct on which
this meta is declared.

#### `on_unknown_attribute` meta

This meta controls how unknown attributes are handled. If set, it must be the
idenifier of a [`UnknownAttributePolicy`] enum variant.

See the documentation of [`UnknownAttributePolicy`] for available variants
and their effects.

Note that this policy only affects the processing of attributes of the
item it is declared on; it has no effect on the handling of unexpected
attributes on children, which is controlled by the respective item's policy.

#### `on_unknown_value` meta

This meta controls how unknown child elements are handled. If set, it must be
the idenifier of a [`UnknownChildPolicy`] enum variant.

See the documentation of [`UnknownChildPolicy`] for available variants
and their effects.

Note that this policy only affects the processing of direct children of the
item it is declared on; it has no effect on the handling of unexpected
grandchildren, which is controlled by the respective item's policy.

#### `transparent` meta

If present, it switches the struct or enum variant into
[transparent mode](#struct-de-serialisation).

#### `element` meta (on items)

If present, it switches the struct or enum variant into
[element mode](#struct-de-serialisation).

This meta can either be used standalone, or it may contain additional
arguments in `key = value` syntax. The following keys are supported, all of
them accepting only string literals:

- `namespace`: Restrict the matched elements to XML elements with the given
  namespace URI.

- `name`: Restrict the matched elements to XML elements with the given
  name.

Note that both `namespace` and `name` are optional and can be used separately.
For expamle, the following is valid (albeit weird):

```ignore
#[derive(FromXml, IntoXml)]
#[xml(element(name = "foo"))]
struct Foo(minidom::Element);
```

And it matches all XML elements (no matter the namespace) which have the local
name `foo`.

#### `wrapped_with` meta

If present, it wraps the item in an additional XML element, both when parsing
and serialising. The XML element is specified by additional arguments to the
`wrapped_with` meta which must be specified as comma-separated `key = value`
pairs inside parentheses:

- `namespace`: Sets the XML namespace URI of the wrapping element.
- `name`: Sets the XML name of the wrapping element.

Both are required. Example:

```ignore
#[derive(FromXml, IntoXml)]
#[xml(namespace = "uri:foo", name = "baz", wrapped_with(namespace = "uri:foo", name = "bar"))]
struct Foo();
```
This would match (and generate) `<bar xmlns="uri:foo"><baz/></bar>`.

#### `exhaustive` meta

If present, the enum considers itself authoritative. That means that if the
XML name (for name matched enums) or attribute value (for attribute matched
enums) does not match any of the variants, a hard parse error is emitted.

By contrast, if the meta is *not* present, in such a situation, parsing may
continue with other attempts (e.g. if the enum is itself a member of a dynamic
enum).

This meta can only be used on XML name or attribute name matched enums. It
cannot be used on structs or dynamically matched enums.

#### `fallback` meta

If set on an enum variant and an unexpected XML name (for name matched enums)
or attribute value (for attribute matched enums) is encountered, this variant
is assumed.

This meta can only be used on variants inside XML name or attribute name
matched enums. It may only be present on one variant.

#### `normalize_with` meta

This meta can only be used on XML attribute matched enums.

The `normalize_with` meta may be set to the path referring to a function. This
function will be called on the attribute value before it is compared against
the values of the enum variants.

The function must have the signature `fn(&str) -> Cow<'_, str>`.

## Field metadata

| Meta | XML representation |
| --- | --- |
| [`attribute`](#attribute-meta-on-fields) | Attribute |
| [`child`](#child-meta) | Child element, processed with [`FromXml`]/[`IntoXml`] |
| [`children`](#children-meta) | Collection of child elements, processed with [`FromXml`]/[`IntoXml`] |
| [`element`](#element-meta-on-fields) | Child element, as `minidom::Element` |
| [`elements`](#elements-meta) | Collection of elements, as `minidom::Element` |
| [`text`](#text-meta) | Character data (text) |
| [`namespace`](#namespace-meta-on-fields) | Parent element's XML namespace |
| [`ignore`](#ignore-meta) | none |

### Field metadata reference

#### `attribute` meta (on fields)

#### `child` meta

#### `children` meta

#### `element` meta (on fields)

#### `elements` meta

#### `text` meta

#### `namespace` meta (on fields)

#### `ignore` meta

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

This derives the [`IntoXml`] trait. For a complete reference on the attributes
required and accepted by this macro, see the [`macro@FromXml`] documentation.
*/
pub use xso_proc::IntoXml;

/**
# Make a struct fully dynamically namespaceable

This derives the [`DynNamespace`] trait. For a complete reference on the
attributes required and accepted by this macro, see the [`macro@FromXml`]
documentation.
*/
pub use xso_proc::DynNamespace;

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

pub mod minidom_compat;

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
    }
}

impl<'a> IntoXmlText for &'a str {
    fn into_xml_text(self) -> String {
        self.to_owned()
    }
}

/// 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
    }
}

/// 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> + IntoXmlText {
    /// 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>;
}

/// 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.
///
/// This trait is automatically implemented on [`minidom::Element`] for all
/// types which can be converted to and from `minidom::Element` with an error
/// which is convertible to [`crate::error::Error`].
pub trait ElementCodec<T>: Sized {
    /// Transform the destructured value further toward the field type.
    fn decode(value: Self) -> Result<T, self::error::Error>;

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

impl<T, U: ElementCodec<T>> ElementCodec<Option<T>> for Option<U> {
    fn decode(value: Self) -> Result<Option<T>, self::error::Error> {
        value.map(|inner| U::decode(inner)).transpose()
    }

    fn encode(value: Option<T>) -> Result<Self, self::error::Error> {
        value.map(|inner| U::encode(inner)).transpose()
    }
}

impl<EI, EF, T> ElementCodec<T> for minidom::Element
where
    T: TryFrom<minidom::Element, Error = EF>,
    minidom::Element: TryFrom<T, Error = EI>,
    self::error::Error: From<EI>,
    self::error::Error: From<EF>,
{
    fn decode(value: Self) -> Result<T, self::error::Error> {
        match value.try_into().map_err(|e| self::error::Error::from(e)) {
            Ok(v) => Ok(v),
            // we must isolate TypeMismatch away so that it is never returned
            // from [`try_from_element`] unless it is caused by the target
            // type of the `try_from_element` call.
            Err(self::error::Error::TypeMismatch(_, _, _)) => Err(self::error::Error::ParseError(
                "minidom::Element did not match target type",
            )),
            Err(other) => Err(other),
        }
    }

    fn encode(value: T) -> Result<Self, self::error::Error> {
        Ok(value.try_into()?)
    }
}

/// 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(())
    }
}

/// Trait allowing to iterate the contents of a struct as serialisable
/// [`rxml::Item`] items.
pub trait IterItems {
    /// The iterator type.
    type ItemIter<'x>: Iterator<Item = Result<rxml::Item<'x>, self::error::Error>>
    where
        Self: 'x;

    /// Return an iterator which emits the contents of the struct or enum as
    /// serialisable [`rxml::Item`] items.
    fn iter_items(&self) -> Self::ItemIter<'_>;
}

/// Trait allowing to consume a struct and iterate its contents as
/// serialisable [`rxml::Event`] items.
pub trait IntoXml {
    /// The iterator type.
    type EventIter: Iterator<Item = Result<rxml::Event, self::error::Error>>;

    /// Return an iterator which emits the contents of the struct or enum as
    /// serialisable [`rxml::Event`] items.
    fn into_event_iter(self) -> Result<Self::EventIter, self::error::Error>;
}

/// Event iterator for `Option<T>`.
pub struct OptionEventIter<T>(Option<T>);

impl<T: Iterator<Item = Result<rxml::Event, self::error::Error>>> Iterator for OptionEventIter<T> {
    type Item = Result<rxml::Event, self::error::Error>;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.as_mut()?.next()
    }
}

impl<T: IntoXml> IntoXml for Option<T> {
    type EventIter = OptionEventIter<T::EventIter>;

    fn into_event_iter(self) -> Result<Self::EventIter, self::error::Error> {
        Ok(OptionEventIter(
            self.map(|x| x.into_event_iter()).transpose()?,
        ))
    }
}

/// Trait for a temporary object allowing to construct a struct from
/// [`rxml::Event] items.
pub trait FromEventsBuilder {
    /// The type which will be constructed by this builder.
    type Output;

    /// Feed another [`rxml::Event`] into the element construction
    /// process.
    ///
    /// If the event contains unexpected or invalid data, an error is
    /// returned.
    ///
    /// If the construction of the object is complete, it is returned as
    /// `Ok(Some(.))`. Once that has happened, `feed` may panic if called
    /// again.
    fn feed(&mut self, ev: rxml::Event) -> Result<Option<Self::Output>, self::error::Error>;
}

/// Builder to construct an `Option<T>` from XML events.
pub struct OptionFromEventsBuilder<T>(T);

impl<T: FromEventsBuilder> FromEventsBuilder for OptionFromEventsBuilder<T> {
    type Output = Option<T::Output>;

    fn feed(&mut self, ev: rxml::Event) -> Result<Option<Self::Output>, self::error::Error> {
        self.0.feed(ev).map(|ok| ok.map(|some| Some(some)))
    }
}

impl<T: FromXml> FromXml for Option<T> {
    type Builder = OptionFromEventsBuilder<T::Builder>;

    fn from_events(
        qname: rxml::QName,
        attrs: rxml::AttrMap,
    ) -> Result<Self::Builder, FromEventsError> {
        Ok(OptionFromEventsBuilder(T::from_events(qname, attrs)?))
    }
}

/// Error returned from [`FromXml::from_events`].
#[derive(Debug)]
pub enum FromEventsError {
    /// The `name` and/or `attrs` passed to `FromXml::from_events` did not
    /// match the element's type.
    Mismatch {
        /// The `name` passed to `from_events`.
        name: rxml::QName,

        /// The `attrs` passed to `from_events`.
        attrs: rxml::AttrMap,
    },

    /// The `name` and `attrs` passed to `FromXml::from_events` matched the
    /// element's type, but the data was invalid. Details are in the inner
    /// error.
    Invalid(self::error::Error),
}

impl From<self::error::Error> for FromEventsError {
    fn from(other: self::error::Error) -> Self {
        Self::Invalid(other)
    }
}

/// Trait allowing to construct a struct from a stream of
/// [`rxml::Event`] items.
///
/// To use this, first call [`FromXml::from_events`] with the qualified
/// name and the attributes of the corresponding
/// [`rxml::Event::StartElement`] event. If the call succeeds, the
/// returned builder object must be fed with the events representing the
/// contents of the element, and then with the `EndElement` event.
///
/// The `StartElement` passed to `from_events` must not be passed to `feed`.
pub trait FromXml {
    /// A builder type used to construct the element.
    type Builder: FromEventsBuilder<Output = Self>;

    /// Attempt to initiate the streamed construction of this struct from XML.
    ///
    /// If the passed qualified `name` and `attrs` match the element's type,
    /// the [`Self::Builder`] is returned and should be fed with XML events
    /// by the caller.
    ///
    /// Otherwise, an appropriate error is returned.
    fn from_events(
        name: rxml::QName,
        attrs: rxml::AttrMap,
    ) -> Result<Self::Builder, FromEventsError>;
}

/// [`FromEventsBuilder`] implementation which consumes and discards the
/// entire XML element.
pub struct DiscardEvents {
    depth: usize,
}

impl DiscardEvents {
    /// Create a new discarder.
    ///
    /// This is ready to use and assumes that the initial start element event
    /// has already been processed.
    pub fn new() -> Self {
        Self { depth: 0 }
    }
}

impl FromEventsBuilder for DiscardEvents {
    type Output = ();

    fn feed(&mut self, ev: rxml::Event) -> Result<Option<Self::Output>, self::error::Error> {
        match ev {
            rxml::Event::StartElement { .. } => {
                self.depth = match self.depth.checked_add(1) {
                    Some(v) => v,
                    None => return Err(self::error::Error::ParseError("maximum depth exceeded")),
                };
            }
            rxml::Event::EndElement { .. } => {
                self.depth = match self.depth.checked_sub(1) {
                    Some(v) => v,
                    None => return Ok(Some(())),
                };
            }
            _ => (),
        }
        Ok(None)
    }
}

/// Attempt to transform a type implementing [`IntoXml`] into another
/// type which implements [`FromXml`].
pub fn transform<T: FromXml, F: IntoXml>(from: F) -> Result<T, self::error::Error> {
    let mut iter = from.into_event_iter()?;
    let (qname, attrs) = match iter.next() {
        Some(Ok(rxml::Event::StartElement(_, qname, attrs))) => (qname, attrs),
        Some(Err(e)) => return Err(e),
        _ => panic!("into_event_iter did not start with StartElement event!"),
    };
    let mut sink = match T::from_events(qname, attrs) {
        Ok(v) => v,
        Err(FromEventsError::Mismatch { .. }) => {
            return Err(self::error::Error::ParseError(
                "transform source element did not match transform target's selector",
            ))
        }
        Err(FromEventsError::Invalid(e)) => return Err(e),
    };
    for event in iter {
        let event = event?;
        match sink.feed(event)? {
            Some(v) => return Ok(v),
            None => (),
        }
    }
    Err(self::error::Error::ParseError(
        "transform source did not produce enough events to complete element",
    ))
}

/// Attempt to convert a [`minidom::Element`] into a type implementing
/// [`FromXml`], fallably.
///
/// Unlike [`transform`] (which can also be used with an element), this
/// function will return the element unharmed as
/// [`crate::error::Error::TypeMismatch`] variant.
pub fn try_from_element<T: FromXml>(from: minidom::Element) -> Result<T, self::error::Error> {
    let (qname, attrs) = minidom_compat::make_start_ev_parts(&from)?;
    let mut sink = match T::from_events(qname, attrs) {
        Ok(v) => v,
        Err(FromEventsError::Mismatch { .. }) => {
            return Err(self::error::Error::TypeMismatch("", "", from))
        }
        Err(FromEventsError::Invalid(e)) => return Err(e),
    };

    let mut iter = from.into_event_iter()?;
    iter.next().expect("first event from minidom::Element")?;
    for event in iter {
        let event = event?;
        match sink.feed(event)? {
            Some(v) => return Ok(v),
            None => (),
        }
    }
    // unreachable! instead of error here, because minidom::Element always
    // produces the complete event sequence of a single element, and FromXml
    // implementations must be constructible from that.
    unreachable!("minidom::Element did not produce enough events to complete element")
}