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
//! # Ktav — a plain configuration format
//!
//! JSON5-shaped, but with no quotes, no commas, and dotted keys for nesting.
//! A document is an implicit top-level object. Native `serde` integration:
//! any type implementing `Serialize` / `Deserialize` (including
//! `#[derive]`-generated ones) round-trips through Ktav out of the box.
//!
//! ## Syntax
//!
//! ```text
//! # comment — any line starting with '#'
//! key: value — scalar; `key` may be a dotted path (a.b.c: 10)
//! key:: value — scalar; value is ALWAYS a literal string
//! key: { ... } — multi-line object; `}` closes on its own line
//! key: [ ... ] — multi-line array; `]` closes on its own line
//! key: {} / key: [] — empty compound, inline
//! :: value — (inside an array) literal-string item
//! ```
//!
//! ## Structured errors
//!
//! The parser returns [`Error::Structured`] for every parse failure since
//! `0.1.5`. Each [`ErrorKind`] variant carries a 1-based `line` and a
//! byte-offset [`Span`] you can slice the original input with.
//!
//! ```
//! use ktav::{parse, Error, ErrorKind};
//!
//! let src = "port:8080\n";
//! match parse(src) {
//! Ok(_) => unreachable!(),
//! Err(Error::Structured(ErrorKind::MissingSeparatorSpace { line, span, .. })) => {
//! assert_eq!(line, 1);
//! // The span covers the offending body chunk glued to the marker.
//! assert_eq!(span.slice(src), Some("8080"));
//! }
//! Err(other) => panic!("unexpected error: {other:?}"),
//! }
//! ```
//!
//! ## Example
//!
//! See [`tests/doc_example.rs`](../tests/doc_example.rs) for the executed
//! version of this snippet — it exercises the full parse → struct → render
//! → parse round-trip:
//!
//! ```rust,ignore
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
//! struct Upstream {
//! host: String,
//! port: u16,
//! }
//!
//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
//! struct Config {
//! port: u16,
//! upstreams: Vec<Upstream>,
//! }
//!
//! let text = "\
//! port: 8080
//!
//! upstreams: [
//! {
//! host: a.example
//! port: 1080
//! }
//! {
//! host: b.example
//! port: 1080
//! }
//! ]
//! ";
//! let cfg: Config = ktav::from_str(text).unwrap();
//! assert_eq!(cfg.port, 8080);
//! assert_eq!(cfg.upstreams.len(), 2);
//!
//! let back = ktav::to_string(&cfg).unwrap();
//! let round: Config = ktav::from_str(&back).unwrap();
//! assert_eq!(cfg, round);
//! ```
pub use ;
pub use ;
pub use ;
use fs;
use Path;
use DeserializeOwned;
use Serialize;
/// Parse a Ktav document from a string into a raw [`Value`]. Useful when
/// you want to inspect or manipulate the document generically. For
/// deserializing into a user type, prefer [`from_str`].
/// Parse a Ktav document from a string and deserialize it into `T`. Uses
/// the zero-copy event path: the parser tokenizes the document into a
/// flat `Vec<Event>` (object keys and single-line scalars are borrowed
/// directly from `s`), and serde walks that vec linearly without ever
/// materialising a tree. Compound nesting is bracketed by
/// `BeginObject`/`EndObject` events instead of nested allocations.
/// Parse a Ktav document from a file path and deserialize it into `T`.
/// Serialize `value` as a Ktav document string. Uses the direct text
/// serializer — no `Value` intermediate.
Sized + Serialize>
/// Serialize `value` as a Ktav document and write it to `path`.
Sized + Serialize, P: >