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
//! `serde` support: deserialize a single ABX element's attributes, child
//! elements, and direct text content into a Rust struct.
//!
//! ## Quick start
//!
//! For a document that *is* one record — a config file whose root element
//! holds the data you want — use one of the one-shot entry points, same
//! shape as `serde_json::from_slice`/`quick_xml::de::from_str`:
//!
//! ```rust,ignore
//! let pkg: Pkg = abx::from_file("pkg.abx")?; // from a path
//! let pkg: Pkg = abx::from_slice(&bytes)?; // from an in-memory buffer
//! let pkg: Pkg = abx::from_reader(reader)?; // from any std::io::Read
//! ```
//!
//! None of these check the root element's tag name against `T` —
//! deserialization is structural, not name-based.
//!
//! For a document whose interesting content is *repeated* elements under an
//! outer wrapper (AOSP's `packages.xml` shape: one `<packages>` root, many
//! `<pkg>` children), use the parser directly and name the repeated element:
//!
//! ```rust,ignore
//! let mut p = abx::open_file("packages.abx")?;
//! let pkgs: Vec<Pkg> = p.deserialize_all("pkg")?;
//! ```
//!
//! ([`crate::AbxStreamParser::deserialize_iter`] is the lazy equivalent, for
//! streaming without collecting a `Vec` upfront.)
//!
//! A struct field maps to:
//! - an **attribute** by its own name, or `#[serde(rename = "...")]` for an
//! attribute name that isn't a valid Rust identifier;
//! - a **child element**, the same way — a nested struct field consumes the
//! first matching child, a `Vec<T>` field consumes all of them, and a
//! scalar field (`String`, `i32`, ...) consumes a *leaf* child (one with
//! no attributes or children of its own) as its text content;
//! - the element's own **direct text content**, via a field renamed to
//! `$text`, the same convention `quick-xml`'s serde support uses.
//!
//! # Differences from `quick-xml`
//!
//! No `@attr` prefix: an attribute always wins over a same-named child
//! element instead of requiring `#[serde(rename = "@name")]` to
//! disambiguate. A field literally named `$text` loses silently to that
//! precedence rather than erroring.
//!
//! No `$value` enum-of-elements mapping (`xs:choice`-style heterogeneous
//! children) — every child element name maps to one field, not a variant
//! selector. And no `Serialize` side — this crate only parses ABX, so
//! deserializing into a struct is one-way.
//!
//! ## Internal layout
//!
//! `traversal` walks the event stream and builds the recursive `ElementData`
//! tree; `element` (`ElementDeserializer`) turns one `ElementData` into a
//! `serde` map; `value` (`ValueDeserializer`) turns one attribute, the text,
//! or a same-named child group into a single `serde` value. None of this is
//! public API — only the functions re-exported below are.
use Read;
use ;
use crate::;
pub use ;
/// Struct field name convention for an element's direct text content.
pub const TEXT_FIELD: &str = "$text";
/// Deserialize a single element's attributes (and optional text content)
/// into `T`, honoring `#[serde(rename = "...")]`, `Option<T>` for absent
/// attributes, and numeric/bytes coercions. This convenience entry point has
/// no child elements to offer — it's meant for callers who already have an
/// `Event::StartTag`'s attributes in hand. Nested-child mapping is only
/// available through [`crate::AbxParser::deserialize_next`] and
/// [`crate::AbxStreamParser::deserialize_next`], which build the child tree
/// by walking the event stream.
/// Deserialize an entire in-memory ABX document into `T`, using its root
/// element. The one-shot entry point for "this whole document is one
/// struct" — no parser to construct, no element name to spell out. Matches
/// quick-xml's `from_str`/serde_json's `from_slice`: the root's tag name is
/// not checked against `T` at all, so name your types however you like.
///
/// For a document whose interesting content is *repeated* elements nested
/// under an outer wrapper (e.g. AOSP's `packages.xml`), use
/// [`crate::AbxParser::deserialize_all`]/`deserialize_iter` instead — this
/// function is for when the root itself is the record you want.
/// Streaming equivalent of [`from_slice`]: deserialize the root element of
/// an ABX document read from any [`std::io::Read`] source.
/// Open a file and deserialize its root element into `T`.