Expand description
§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
# 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};
// The first line anchors the document as an Object; the malformed
// `port:8080` on line 2 then errors with a `MissingSeparatorSpace`
// (a first-line `port:8080` would now be a top-level Array
// bare-scalar item — spec § 5.0.1).
let src = "anchor: ok\nport:8080\n";
match parse(src) {
Ok(_) => unreachable!(),
Err(Error::Structured(ErrorKind::MissingSeparatorSpace { line, span, .. })) => {
assert_eq!(line, 2);
// 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 for the executed
version of this snippet — it exercises the full parse → struct → render
→ parse round-trip:
ⓘ
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);Re-exports§
pub use error::CompoundKind;pub use error::ConflictKind;pub use error::Error;pub use error::ErrorKind;pub use error::Result;pub use error::Span;pub use thin::parse_events;pub use thin::ParseEvent;pub use value::ObjectMap;pub use value::Value;
Modules§
- de
serde::Deserializerconsuming acrate::Valueinto anyT: Deserialize.- error
- Error types.
- parser
- Line-oriented Ktav parser. See
crate::parsefor the public entry point. - render
- Render a
crate::Valueas a Ktav text document. - ser
- Serialization: two paths.
- thin
- Zero-copy event-stream parser.
- value
- Dynamic representation of a Ktav document.
Functions§
- from_
file - Parse a Ktav document from a file path and deserialize it into
T. - 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 flatVec<Event>(object keys and single-line scalars are borrowed directly froms), and serde walks that vec linearly without ever materialising a tree. Compound nesting is bracketed byBeginObject/EndObjectevents instead of nested allocations. - parse
- 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, preferfrom_str. - to_file
- Serialize
valueas a Ktav document and write it topath. - to_
string - Serialize
valueas a Ktav document string. Uses the direct text serializer — noValueintermediate. - to_
string_ force_ strings - Render a
Valuewith every scalar coerced to a String — typed integers (:i), typed floats (:f), booleans, and null are flattened to their textual form and emitted via the raw- marker::. Compounds (Object / Array) preserve their structure; only leaf scalars are coerced. The output round-trips back through the parser as the same set of String scalars.