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
//! Parse and write YAML compatible with deser.
//!
//! ```rust
//! use deser::{Deserialize, Serialize};
//!
//! #[derive(Deserialize, Serialize, Debug)]
//! struct Config {
//! name: String,
//! ports: Vec<u16>,
//! }
//!
//! let config: Config = deser_yaml::from_str("
//! name: web
//! ports: [80, 443]
//! ").unwrap();
//! assert_eq!(config.name, "web");
//! assert_eq!(config.ports, [80, 443]);
//!
//! assert_eq!(
//! deser_yaml::to_string(&config).unwrap(),
//! "name: web\nports:\n - 80\n - 443\n"
//! );
//! ```
//!
//! # Data Model
//!
//! The YAML parser passes the complete official
//! [YAML test suite](https://github.com/yaml/yaml-test-suite). YAML maps
//! onto the deser data model as follows:
//!
//! | YAML | deser |
//! |---------------------------------------|-----------------------------------------|
//! | `null`, `~`, empty | `Null` |
//! | `true`, `false` | `Bool` |
//! | integers | `U64`, `I64` (`u128` / `i128` if wider) |
//! | floats | `F64` |
//! | other scalars | `Str` |
//! | `!!binary` | `Bytes` |
//! | `!!timestamp` | [`Datetime`](deser_core::ext::Datetime) |
//! | mappings and sequences | maps and sequences |
//!
//! Which plain (unquoted) scalars are null, booleans or numbers depends on
//! the YAML version, see [`Version`]. As their type is inferred from
//! their text, they are passed on as
//! [`Implicit`](deser_core::Atom::Implicit) atoms: types that expect strings
//! receive the text, all others the value. `version: 1.10` is `1.1` for an
//! `f64` and `"1.10"` for a `String`, `~` is `None` for an `Option<String>`
//! and `"~"` for a `String`, and keys like `200` work for maps with string
//! keys. Quoted scalars are always strings and scalars with a standard tag
//! (like `!!int 42`) are always of the type of their tag.
//!
//! ```rust
//! #[derive(deser::Deserialize)]
//! struct Package {
//! version: String,
//! port: u16,
//! }
//!
//! let package: Package =
//! deser_yaml::from_str("version: 1.10\nport: 0x1F").unwrap();
//! assert_eq!(package.version, "1.10");
//! assert_eq!(package.port, 31);
//! ```
//! The standard tags (`!!str`, `!!int`, `!!float`, `!!bool`, `!!null`,
//! `!!binary`, `!!timestamp`, `!!seq` and `!!map`) determine the type of a
//! value, all other tags are passed on out of band (see [`tag`]).
//! Timestamps are only recognized with an explicit `!!timestamp` tag. They
//! are passed on as the well-known [`Datetime`](deser_core::ext::Datetime) type
//! (a date or an offset date-time, timestamps without time zone are in UTC)
//! which falls back to a string. Map keys can be of any
//! type.
//!
//! Aliases are expanded: every alias produces the events of the node it
//! refers to (see [`DeserializerConfig::alias_limit`]).
//!
//! # Serialization
//!
//! [`to_string`] writes values as block collections: sequences with `-`,
//! mappings with `key: value`, empty collections as `{}` and `[]`. How the
//! output looks can be configured with [`SerializerConfig`] (indentation,
//! quoting, null, bytes, ...). Values are always written so that they read
//! back as the same values, also by readers of YAML 1.1 (such as PyYAML)
//! unless configured otherwise with [`SerializerConfig::compat`]:
//!
//! | deser | YAML |
//! |-----------------------------------------|-----------------------------------------------|
//! | `Null` | `null` (see [`NullStyle`]) |
//! | `Bool`, integers | `true`, `false`, `42` |
//! | `F32`, `F64` | `1.5`, `1.0e+20`, `.inf`, `.nan` (the shortest text for the precision) |
//! | `Str` | plain if possible, otherwise quoted (see [`QuoteStyle`]), with line breaks as literal block scalar (see [`MultilineStyle`]) |
//! | [`Implicit`](deser_core::Atom::Implicit) | its text if readers read it as the same value (`1.10`, `0x1F`, `~`), otherwise the value |
//! | `Bytes` | `!!binary` (see [`SerializerConfig::binary`]) |
//! | [`Datetime`](deser_core::ext::Datetime) | timestamp (see [`SerializerConfig::timestamp_tag`]) |
//! | maps and sequences | block mappings and sequences, flow style (`[a, b]`, `{a: 1}`) if compact (see [`FlowPolicy`]), keys that are collections or long use `? key` |
//!
//! The style of individual values can be requested with hints: the
//! well-known [`Layout`](deser_core::hints::Layout) for collections (flow or
//! block) and [`ScalarStyle`](style::ScalarStyle) for strings (see
//! [`style`]). Values set them with adapters, layers can set them for
//! instance by path. Hints are preferences: a value is written in another
//! style if the requested one cannot represent it. When reading, flow
//! collections are reported as compact so that they stay flow collections
//! through a [`Recording`](deser_core::de::Recording). Plain scalars keep
//! their text the same way, `version: 1.10` read into a `deser_value::Value` or a
//! recording is written as `version: 1.10` again.
//!
//! Tags are written with [`Tagged`] or [`set_tag`] (see [`tag`]). Streams of
//! multiple documents are written with [`Serializer`].
//!
//! # Documents
//!
//! A YAML stream can contain multiple documents. [`from_str`] expects at
//! most one document, [`Deserializer`] can read them one by one:
//!
//! ```rust
//! let mut de = deser_yaml::Deserializer::from_str("--- a\n--- b\n");
//! let docs = de.iter::<String>().collect::<Result<Vec<_>, _>>().unwrap();
//! assert_eq!(docs, ["a", "b"]);
//! ```
//!
//! # Streams
//!
//! Values are read from a [`Read`](std::io::Read) with [`from_reader`]
//! and written to a [`Write`](std::io::Write) with [`to_writer`]. To read
//! or write streams of documents the configurations create readers and
//! writers of [`deser::io`](deser_core::io) ([`DeserializerConfig::reader`]
//! and [`SerializerConfig::writer`]). The reader only buffers until a
//! document is complete:
//!
//! ```rust
//! # #[cfg(feature = "io")] {
//! use deser_yaml::{DeserializerConfig, SerializerConfig};
//!
//! const ENDED: SerializerConfig =
//! SerializerConfig::new().end_documents(true);
//! let mut writer = ENDED.writer(Vec::new());
//! writer.write(&vec![1, 2]).unwrap();
//! writer.write(&"done").unwrap();
//! let output = writer.into_inner();
//! assert_eq!(output, b"- 1\n- 2\n...\n---\ndone\n...\n");
//!
//! let mut reader = DeserializerConfig::new().reader(&output[..]);
//! assert_eq!(reader.read::<Vec<u32>>().unwrap(), Some(vec![1, 2]));
//! assert_eq!(reader.read::<String>().unwrap().as_deref(), Some("done"));
//! assert_eq!(reader.read::<String>().unwrap(), None);
//! # }
//! ```
//!
//! The stream serializer ([`Serializer`]) and the stream deserializer
//! ([`StreamDeserializer`]) do not do IO themselves (see
//! [`deser::stream`](deser_core::stream)), they also work with other kinds
//! of IO (for instance async runtimes with `deser-tokio`).
//!
//! # Features
//!
//! * `io` (enabled by default): reading and writing streams of the
//! standard library, see [streams](#streams).
//! * `speedups`: validates UTF-8 with [`simdutf8`](https://docs.rs/simdutf8).
pub use ;
pub use Version;
pub use to_writer;
pub use ;
pub use StreamDeserializer;
pub use from_reader;
pub use ;