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
//! A streaming writer for the [Kahon binary format].
//!
//! Kahon is a JSON-shaped binary container designed for random access:
//! arrays and objects are laid out as on-disk B+trees, so a reader can
//! index into a million-element array or look up a key in a million-key
//! object without scanning the document. Values are written as they
//! arrive and containers reference children by back-offset, so writer
//! memory stays bounded by tree depth, not document size.
//!
//! [Kahon binary format]: https://github.com/jankdc/kahon
//!
//! # Quick start
//!
//! ```
//! use kahon::Writer;
//!
//! # fn main() -> Result<(), kahon::WriteError> {
//! let mut buf: Vec<u8> = Vec::new();
//! let mut w = Writer::new(&mut buf);
//!
//! {
//! let mut monster = w.start_object();
//! monster.push_i64("hp", 80)?;
//! monster.push_bool("enraged", true)?;
//!
//! {
//! let mut weapons = monster.start_array("weapons")?;
//! weapons.push_str("fist")?;
//!
//! let mut axe = weapons.start_object();
//! axe.push_str("name", "great axe")?;
//! axe.push_i64("damage", 15)?;
//! // `axe` and `weapons` auto-close on drop.
//! }
//!
//! monster.end()?; // explicit close surfaces errors
//! }
//!
//! w.finish()?; // writes the 12-byte trailer
//! # Ok(())
//! # }
//! ```
//!
//! # Building a document
//!
//! Construction follows a flexbuffer-style builder pattern. Start at a
//! [`Writer`], push exactly one root value (scalar, array, or object),
//! then call [`Writer::finish`] to emit the trailer.
//!
//! - Scalars are pushed via `push_null`, `push_bool`, `push_i64`,
//! `push_u64`, `push_f64`, `push_str`.
//! - Arrays and objects are opened with `start_array` / `start_object`,
//! which return an [`ArrayBuilder`] or [`ObjectBuilder`]. Builders
//! borrow their parent mutably and may be nested freely.
//! - Object keys are passed positionally before the value
//! (`obj.push_i64("hp", 80)`). Duplicate keys within an object's
//! sort window resolve last-wins (the latest push for a given key
//! replaces earlier ones).
//!
//! # Closing builders: `Drop` vs `end`
//!
//! Builders close their container on `Drop`, which is convenient for the
//! happy path. If the close encounters a write error, however, `Drop`
//! has nowhere to surface it - the writer is poisoned and the error is
//! reported on the next operation (or on [`Writer::finish`]).
//!
//! Call [`ArrayBuilder::end`] or [`ObjectBuilder::end`] to close
//! explicitly and propagate errors as a `Result`.
//!
//! # Tuning the layout
//!
//! [`WriterOptions`] selects how B+tree nodes are sized and whether the
//! body is padded for page-cache friendliness:
//!
//! ```
//! use kahon::{BuildPolicy, Writer, WriterOptions};
//!
//! # fn main() -> Result<(), kahon::WriteError> {
//! # let mut sink: Vec<u8> = Vec::new();
//! // Disk-tuned: each B+tree node targets one page, trailer is page-aligned.
//! let opts = WriterOptions {
//! policy: BuildPolicy::disk_aligned(4096),
//! ..Default::default()
//! };
//! let w = Writer::with_options(&mut sink, opts)?;
//! # let _ = w;
//! # Ok(())
//! # }
//! ```
//!
//! The default ([`BuildPolicy::compact`] with fanout 128) produces the
//! tightest output and is best for in-memory or network use.
//! [`BuildPolicy::disk_aligned`] trades a small amount of unreferenced
//! padding for a layout that plays well with the page cache when files
//! are `pread`-ed or memory-mapped.
//!
//! # Sinks
//!
//! Any type implementing [`std::io::Write`] is also a [`Sink`] via a
//! blanket impl, so you can write to a `Vec<u8>`, a `File`, a
//! `BufWriter`, or any other writer without adapters.
//!
//! # Errors
//!
//! All fallible operations return [`WriteError`]. Once an error occurs
//! mid-document the writer is *poisoned*: subsequent operations fail
//! fast with [`WriteError::Poisoned`] rather than producing a malformed
//! file.
pub use ;
pub use TrailerSnapshot;
pub use ;
pub use WriteError;
pub use ;
pub use Writer;
/// Convenience alias for `std::result::Result<T, WriteError>`.
pub type Result<T> = Result;