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
//! Structs in, structs out, in the spirit of
//! [Glaze](https://github.com/stephenberry/glaze).
//!
//! Values are read straight into your types and written straight out of them.
//! There is no token stream and no intermediate document model: a field's
//! bytes are converted exactly once, into the member that will hold them.
//!
//! ```
//! #[derive(Default, PartialEq, Debug)]
//! struct Config {
//! name: String,
//! port: u16,
//! hosts: Vec<String>,
//! }
//!
//! structio::object!(Config { name, port, hosts });
//!
//! let json = r#"{"name":"api","port":8080,"hosts":["a","b"]}"#;
//! let config: Config = structio::from_str(json).unwrap();
//! assert_eq!(config.port, 8080);
//! assert_eq!(structio::to_string(&config), json);
//! ```
//!
//! # Two formats, one schema
//!
//! [`object!`] declares a struct's field list once. Both formats read and
//! write against it, so the same type round-trips through either without a
//! second declaration:
//!
//! - [`json`] is JSON text.
//! - [`beve`] is [BEVE](https://github.com/stephenberry/beve), a tagged binary
//! format that keeps JSON's shape and self-description while storing numbers
//! as numbers and numeric arrays as contiguous blocks.
//!
//! ```
//! # #[derive(Default, PartialEq, Debug)]
//! # struct Sample { id: u32, values: Vec<f64> }
//! # structio::object!(Sample { id, values });
//! let sample = Sample { id: 7, values: vec![1.5, 2.5, 3.5] };
//!
//! let text = structio::to_string(&sample);
//! let binary = structio::to_beve(&sample);
//!
//! assert_eq!(structio::from_str::<Sample>(&text).unwrap(), sample);
//! assert_eq!(structio::from_beve::<Sample>(&binary).unwrap(), sample);
//! ```
//!
//! # Objects and arrays
//!
//! [`object!`] encodes a struct by key. [`array!`] encodes it by position,
//! for a type whose field names carry nothing a reader does not already have:
//!
//! ```
//! #[derive(Default, PartialEq, Debug)]
//! struct Vec3 { x: f64, y: f64, z: f64 }
//! structio::array!(Vec3 [x, y, z]);
//!
//! let v = Vec3 { x: 1.0, y: 2.0, z: 3.0 };
//! assert_eq!(structio::to_string(&v), "[1,2,3]");
//! ```
//!
//! Nothing is hashed and no keys go on the wire, at the cost of a schema that
//! cannot change shape: an array of the wrong length is an error, where an
//! object can be read with a policy that steps over a field it does not
//! recognize.
//!
//! [`transparent!`] is the third reading of a struct: a one-field wrapper
//! written as that field alone, for the newtype that exists to keep two
//! `u64`s apart in Rust and means nothing to either format.
//!
//! ```
//! #[derive(Default, PartialEq, Debug)]
//! struct UserId(u64);
//! structio::transparent!(UserId { 0 });
//!
//! assert_eq!(structio::to_string(&UserId(7)), "7");
//! ```
//!
//! # Enums
//!
//! An enum's schema is its variant names, and they go on the wire as names
//! rather than as positions. A variant carrying nothing is written as its
//! name; a variant carrying a value is written as an object of one member
//! keyed by that name, and is marked `(_)` in the declaration.
//!
//! ```
//! #[derive(Default, PartialEq, Debug)]
//! enum Shape {
//! #[default]
//! Empty,
//! Sides(u32),
//! }
//! structio::tagged_enum!(Shape { Empty, Sides(_) });
//!
//! assert_eq!(structio::to_string(&Shape::Empty), "\"Empty\"");
//! assert_eq!(structio::to_string(&Shape::Sides(3)), r#"{"Sides":3}"#);
//! assert_eq!(structio::from_str::<Shape>(r#"{"Sides":3}"#).unwrap(), Shape::Sides(3));
//! ```
//!
//! [`unit_enum!`] is the same declaration for an enum whose variants all carry
//! nothing, and will not compile if one of them does, so its wire form is a
//! plain string and stays one.
//!
//! A variant carrying nothing reads back from either form, but one carrying a
//! value has only the object form, and the two macros' pages say what each
//! error means.
//! [docs/enums.md](https://github.com/matrix-research-inc/structio/blob/main/docs/enums.md)
//! is the long form.
//!
//! The crate root re-exports the JSON entry points unqualified, because JSON
//! is what most callers want first. The BEVE ones carry the format in the
//! name at the root ([`to_beve`], [`from_beve`]) and drop it inside the
//! module, so [`beve::to_vec`] and [`to_beve`] are the same function.
//!
//! # Design
//!
//! - **No dependencies.** Standard library only.
//! - **No proc-macros required.** [`object!`], [`array!`] and [`tagged_enum!`]
//! are `macro_rules!` macros, so there is no proc-macro crate to build and
//! link for the host before your code can, and nothing extra when
//! cross-compiling. It buys a smaller dependency graph rather than a faster
//! build: expanding a declaration costs about what a derive costs. The
//! `derive` feature adds `#[derive(Structio)]`, a dependency-free front end
//! that expands to the same macros, for a type you own and would rather
//! not restate.
//! - **A declaration is checked against its type.** Naming a field the struct
//! does not have has always been an error; leaving one out is now one too,
//! naming the field. End a declaration with `..` where the omission is
//! deliberate.
//! - **Keys are hashed at compile time.** [`KeyMap::build`] runs during const
//! evaluation and picks the cheapest perfect hash that fits your key set,
//! from a single byte comparison up to a full key hash. Both formats look
//! keys up in that one table.
//! - **Reads reuse what you already own.** Parsing into an existing value
//! refills its buffers instead of reallocating them.
//!
//! # What it does not do
//!
//! This is for statically known types. Reading a document you have no type
//! for is a different matter, and [`Value`] is the tree for that case: a
//! shape nothing declares and something walks by path, the register map a
//! device publishes, a setting stored under a key some plugin chose. It is a
//! destination like any other, not a stage every read passes through, and a
//! value you could have declared a type for is better read into that type. A
//! body you forward rather than look at is a different problem again, and a
//! tree is the wrong answer to it: [`json::Raw`] carries one
//! through as the text that spelled it. See [`value`](mod@value) for what it
//! holds and what it costs.
//!
//! A BEVE document can still be looked into without being decoded whole.
//! [`from_beve_at`] reads the one value a JSON Pointer names and steps over
//! everything else, and [`validate_beve`] checks a document is well formed
//! without decoding any of it. What comes back from the first is still a type
//! you declared.
//!
//! [`beve_to_json`] hands back a BEVE document's *contents* without a type
//! and without a tree: it rewrites the whole document as JSON in a single
//! walk. See [`transcode`] for what survives the trip and what does not.
//!
//! # Complex numbers and matrices
//!
//! BEVE's core covers what JSON covers; its extensions cover what scientific
//! data needs on top of that. [`Complex`] and [`Matrix`] are those two, as
//! ordinary types that work in both formats:
//!
//! ```
//! use structio::{Complex, Matrix, MatrixLayout};
//!
//! let signal = vec![Complex::new(1.0f64, 2.0), Complex::new(3.0, -4.0)];
//! let bytes = structio::to_beve(&signal);
//! assert_eq!(structio::from_beve::<Vec<Complex<f64>>>(&bytes).unwrap(), signal);
//!
//! let m = Matrix::new(MatrixLayout::RowMajor, vec![2, 3], (0..6i32).collect()).unwrap();
//! assert_eq!(
//! structio::to_string(&m),
//! r#"{"layout":"layout_right","extents":[2,3],"value":[0,1,2,3,4,5]}"#
//! );
//! assert_eq!(structio::from_beve::<Matrix<i32>>(&structio::to_beve(&m)).unwrap(), m);
//! ```
//!
//! A run of complex numbers is one header and one block, so a
//! `Vec<Complex<f64>>` moves in a single copy exactly as a `Vec<f64>` does, and
//! a `Matrix<Complex<f64>>` stores its data that way with no case of its own.
//! See [`ext`].
//!
//! # Options
//!
//! Whether the JSON is indented, whether a member that would be null is
//! written at all, and whether a key nothing claims is refused, are decided at
//! compile time by a [policy type](Options). Every entry point has a `_with`
//! twin that takes one, and the plain one is [`Standard`]:
//!
//! ```
//! use structio::{Pretty, SkipNull, to_string, to_string_with};
//!
//! # #[derive(Default)]
//! # struct Server { port: u16, tls: Option<String> }
//! # structio::object!(Server { port, tls });
//! let server = Server { port: 8080, tls: None };
//!
//! assert_eq!(to_string(&server), r#"{"port":8080,"tls":null}"#);
//! assert_eq!(
//! to_string_with::<Pretty, _>(&server),
//! "{\n \"port\": 8080,\n \"tls\": null\n}"
//! );
//! assert_eq!(to_string_with::<SkipNull, _>(&server), r#"{"port":8080}"#);
//! ```
//!
//! Indentation puts every element of an array on a line of its own, which is
//! not what a run of numbers wants. [`PrettyInlineArrays`] keeps each array on
//! the line it began on and indents everything else:
//!
//! ```
//! use structio::{PrettyInlineArrays, to_string_with};
//!
//! # #[derive(Default)]
//! # struct Sample { id: u32, values: Vec<f64> }
//! # structio::object!(Sample { id, values });
//! let sample = Sample { id: 7, values: vec![1.5, 2.5, 3.5] };
//!
//! assert_eq!(
//! to_string_with::<PrettyInlineArrays, _>(&sample),
//! "{\n \"id\": 7,\n \"values\": [1.5, 2.5, 3.5]\n}"
//! );
//! ```
//!
//! Text that is already JSON takes the same policy from the other side.
//! [`prettify`] lays out a document that did not come from a `Write` impl, and
//! emits its whitespace through the same writer, so the result is what writing
//! the same data would have produced:
//!
//! ```
//! use structio::{PrettyInlineArrays, json::prettify_with, prettify};
//!
//! assert_eq!(prettify(r#"{"a":[1,2]}"#).unwrap(), "{\n \"a\": [\n 1,\n 2\n ]\n}");
//! assert_eq!(
//! prettify_with::<PrettyInlineArrays>(r#"{"a":[1,2]}"#).unwrap(),
//! "{\n \"a\": [1, 2]\n}"
//! );
//! ```
//!
//! [`minify`] goes the other way, and has no layout to agree with: it copies
//! the document through and drops the whitespace between its tokens. That needs
//! nothing but the strings located, so it neither reads a value nor checks a
//! bracket, which is what makes it the fastest thing here.
//!
//! ```
//! assert_eq!(structio::minify("{\n \"a\": [1, 2]\n}").unwrap(), r#"{"a":[1,2]}"#);
//! ```
//!
//! Reading takes a policy the same way. It has three settings, and only one
//! of them is on by default: a key that no field claims is an
//! [`ErrorCode::UnknownKey`], which catches a typo or the wrong document
//! rather than passing over it in silence. Ask for [`SkipUnknown`] to read a
//! subset of a larger document. The other way round, a declared field the
//! document leaves out is simply left as the destination had it, since reading
//! is into a value that already exists. Mark a field `#[required]` in the
//! declaration and its absence is an [`ErrorCode::MissingKey`] under every
//! policy, which is what a mixed schema wants; [`RequireKeys`] says the same of
//! every field at once.
//!
//! ```
//! use structio::{ErrorCode, SkipUnknown, from_str, from_str_with};
//!
//! # #[derive(Default, Debug)]
//! # struct Server { port: u16 }
//! # structio::object!(Server { port });
//! let doc = r#"{"port":8080,"debug":true}"#;
//!
//! assert_eq!(from_str::<Server>(doc).unwrap_err().code, ErrorCode::UnknownKey);
//! assert_eq!(from_str_with::<SkipUnknown, Server>(doc).unwrap().port, 8080);
//! ```
//!
//! ```
//! use structio::{ErrorCode, RequireKeys, from_str, from_str_with};
//!
//! # #[derive(Default, Debug)]
//! # struct Server { port: u16, host: String }
//! # structio::object!(Server { port, host });
//! let doc = r#"{"port":8080}"#;
//!
//! assert_eq!(from_str::<Server>(doc).unwrap().host, "");
//! let e = from_str_with::<RequireKeys, Server>(doc).unwrap_err();
//! assert_eq!(e.code, ErrorCode::MissingKey);
//! // A member that is not there has no position of its own, so the offset
//! // names the object and the error names the member.
//! assert_eq!(e.key, Some("host"));
//! ```
//!
//! The third is [`AllowComments`], which reads JSONC: `//` and `/* */`
//! wherever whitespace is allowed, for the documents people edit by hand.
//!
//! The setting you do not ask for costs nothing: a compact writer emits no
//! indentation code at all. Combinations are your own unit struct and an impl,
//! since every constant on [`Options`] has a default. See [`options`].
//!
//! # Streaming
//!
//! Documents that do not fit, or have not fully arrived, go through
//! [`json::stream`] and [`beve::stream`]: [`to_writer`] drains into an
//! [`std::io::Write`], [`Documents`] pulls a sequence of values out of an
//! [`std::io::Read`], and [`Feed`] takes chunks pushed at it. The BEVE
//! counterparts are [`beve::to_writer`], [`beve::Documents`] and
//! [`beve::Feed`], and they hand out the elements of a typed array one at a
//! time as readily as whole records. [`beve_to_json_writer`] drains a transcode
//! into a sink the same way.
pub use ;
pub use ;
pub use KeyMap;
pub use OrderedMap;
pub use ;
pub use ;
pub use ;
/// Declare a type's schema from its definition: `#[derive(Structio)]`.
///
/// Available behind the `derive` feature. The derive is a front end to
/// [`object!`], [`array!`], [`transparent!`], [`unit_enum!`] and
/// [`tagged_enum!`]: it reads the
/// struct or enum and emits the declaration you would have written, with the
/// attributes translated to the macro's syntax, so a derived type and a
/// declared type are the same impls. Generics and their bounds are read off
/// the type rather than restated, and a `#[structio(skip)]` field is the `..`
/// a declaration ends with.
///
/// ```
/// # #[cfg(feature = "derive")] {
/// #[derive(Default, structio::Structio)]
/// #[structio(rename_all = "camelCase")]
/// struct Camera {
/// focal_length: f64,
/// #[structio(rename = "iso")]
/// sensitivity: u32,
/// #[structio(skip)]
/// cache: Vec<u8>,
/// }
///
/// let camera = Camera { focal_length: 50.0, sensitivity: 200, cache: vec![1] };
/// assert_eq!(structio::to_string(&camera), r#"{"focalLength":50,"iso":200}"#);
/// # }
/// ```
///
/// The attributes:
///
/// | On | Attribute | Expands to |
/// |---|---|---|
/// | the type | `rename_all = "camelCase"` | `as "camelCase"` |
/// | the type | `tag = "kind"` | `as tag "kind"`, an internally tagged enum |
/// | the type | `array`, `element = "u8"` | [`array!`], with its element type |
/// | the type | `transparent` | [`transparent!`]: a one-field struct as that field |
/// | the type | `json`, `beve` | the one-format macro |
/// | the type | `crate = "path"` | the path to this crate where it is re-exported |
/// | a field | `rename = "key"` | `"key" => field` |
/// | a field | `alias = "key"` | <code>field | "key"</code>, a further key read and never written |
/// | a field | `skip` | left out, and `..` at the end |
/// | a field | `required` | `#[required]` |
/// | a field | `with = "Adapter"` | `field as Adapter` |
/// | a variant | `rename = "name"` | `"name" => Variant` |
/// | a variant | `alias = "name"` | <code>Variant | "name"</code> |
///
/// [docs/derive.md](https://github.com/matrix-research-inc/structio/blob/main/docs/derive.md)
/// has each attribute in full, what the derive refuses and why, and the
/// attributes later stages add.
pub use Structio;
pub use ;
// The BEVE entry points carry their format in the name at the root, where
// they sit beside the unqualified JSON ones, and drop it inside the module.
pub use append as append_beve;
pub use append_aligned as append_beve_aligned;
pub use append_aligned_with as append_beve_aligned_with;
pub use append_with as append_beve_with;
pub use from_reader as from_beve_reader;
pub use from_reader_array as from_beve_reader_array;
pub use from_reader_with as from_beve_reader_with;
pub use from_slice as from_beve;
pub use from_slice_at as from_beve_at;
pub use from_slice_at_with as from_beve_at_with;
pub use from_slice_with as from_beve_with;
pub use read_array_into as read_beve_array_into;
pub use read_into as read_beve_into;
pub use read_into_at as read_beve_into_at;
pub use read_into_at_with as read_beve_into_at_with;
pub use read_into_with as read_beve_into_with;
pub use size as beve_size;
pub use size_after as beve_size_after;
pub use size_after_with as beve_size_after_with;
pub use size_aligned as beve_size_aligned;
pub use size_aligned_after as beve_size_aligned_after;
pub use size_aligned_after_with as beve_size_aligned_after_with;
pub use size_aligned_with as beve_size_aligned_with;
pub use size_with as beve_size_with;
pub use slice_ref as beve_slice_ref;
pub use to_vec as to_beve;
pub use to_vec_aligned as to_beve_aligned;
pub use to_vec_aligned_with as to_beve_aligned_with;
pub use to_vec_with as to_beve_with;
pub use to_writer as to_beve_writer;
pub use to_writer_buffered as to_beve_writer_buffered;
pub use to_writer_buffered_with as to_beve_writer_buffered_with;
pub use to_writer_with as to_beve_writer_with;
pub use validate as validate_beve;
pub use validate_reader as validate_beve_reader;
pub use write_into as write_beve_into;
pub use write_into_with as write_beve_into_with;
// Neither format's module owns this one, since it names both.
pub use ;