KDL
facet-kdl provides serialization and deserialization for KDL, a document language with a focus on human readability. Use attributes like kdl::property, kdl::argument, and kdl::child to control how your types map to KDL's node-based structure.
Basic Node with Properties
Simple struct with #[facet(kdl::property)] fields becomes KDL properties.
KDL Input
person name="Alice" age=30 email="alice@example.com"
Target Type
#[derive(Facet)]
struct PersonDoc {
#[facet(kdl::child)]
person: Person,
}
#[derive(Facet)]
struct Person {
#[facet(kdl::property)]
name: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">age</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u32</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">email</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">Option</span><span style="color:#a9b1d6;"><</span><span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">>,</span>
}
Success
PersonDoc {
person: Person {
name: "Alice",
age: 30,
email: Option::Some("alice@example.com"),
},
}Node with Argument
#[facet(kdl::argument)] field becomes a positional argument after the node name.
Result: server "web-01" host="localhost" port=8080
KDL Input
server "web-01" host="localhost" port=8080
Target Type
#[derive(Facet)]
struct ServerDoc {
#[facet(kdl::child)]
server: Server,
}
#[derive(Facet)]
struct Server {
#[facet(kdl::argument)]
name: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">host</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">port</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u16</span><span style="color:#a9b1d6;">,</span>
}
Success
ServerDoc {
server: Server {
name: "web-01",
host: "localhost",
port: 8080,
},
}Nested Nodes (Children)
#[facet(kdl::child)] fields become nested child nodes in braces.
The address struct becomes a child node of company.
KDL Input
company name="Acme Corp" {
address street="123 Main St" city="Springfield"
}
Target Type
#[derive(Facet)]
struct CompanyDoc {
#[facet(kdl::child)]
company: Company,
}
#[derive(Facet)]
struct Company {
#[facet(kdl::property)]
name: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">child</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">address</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">Address</span><span style="color:#a9b1d6;">,</span>
}
#[derive(Facet)]
struct Address {
#[facet(kdl::property)]
street: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">city</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
}
Success
CompanyDoc {
company: Company {
name: "Acme Corp",
address: Address {
street: "123 Main St",
city: "Springfield",
},
},
}Vec as Repeated Children
#[facet(kdl::children)] on a Vec field creates repeated child nodes.
Each Member becomes a separate member node.
KDL Input
member "Bob" role="Engineer"
member "Carol" role="Designer"
member "Dave" role="Manager"
Target Type
#[derive(Facet)]
struct TeamDoc {
#[facet(kdl::children)]
member: Vec<Member>,
}
#[derive(Facet)]
struct Member {
#[facet(kdl::argument)]
name: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">role</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
}
Success
TeamDoc {
member: Vec<Member> [
Member {
name: "Bob",
role: "Engineer",
},
Member {
name: "Carol",
role: "Designer",
},
Member {
name: "Dave",
role: "Manager",
},
],
}Complex Nested Config
A realistic application config showing:
- Top-level properties (debug, features)
- Child nodes with arguments (server, database)
- Nested children (tls inside server)
- Optional children (tls is Option<TlsConfig>)
KDL Input
server "api-gateway" host="0.0.0.0" port=443 {
tls cert_path="/etc/ssl/cert.pem" key_path="/etc/ssl/key.pem"
}
database "primary" url="postgres://localhost/mydb" pool_size=10
Target Type
#[derive(Facet)]
struct AppConfig {
#[facet(kdl::property)]
debug: bool,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">child</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">server</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">ServerConfig</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">child</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">database</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">DatabaseConfig</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">features</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">Vec</span><span style="color:#a9b1d6;"><</span><span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">>,</span>
}
#[derive(Facet)]
struct DatabaseConfig {
#[facet(kdl::argument)]
name: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">url</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">pool_size</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u32</span><span style="color:#a9b1d6;">,</span>
}
#[derive(Facet)]
struct ServerConfig {
#[facet(kdl::argument)]
name: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">host</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">port</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u16</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">child</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">tls</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">Option</span><span style="color:#a9b1d6;"><</span><span style="color:#2ac3de;">TlsConfig</span><span style="color:#a9b1d6;">>,</span>
}
#[derive(Facet)]
struct TlsConfig {
#[facet(kdl::property)]
cert_path: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">key_path</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
}
Error
kdl::invalid_document_shape
× invalid shape Undefined — needed struct with child/children fields
Roundtrip: Rust → KDL → Rust
Demonstrates serialization followed by deserialization.
The value survives the roundtrip intact.
KDL Input
config debug=#true max_connections=100 timeout_ms=5000
Target Type
#[derive(Facet)]
struct ConfigDoc {
#[facet(kdl::child)]
config: Config,
}
#[derive(Facet)]
struct Config {
#[facet(kdl::property)]
debug: bool,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">max_connections</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u32</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">timeout_ms</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u32</span><span style="color:#a9b1d6;">,</span>
}
Success
ConfigDoc {
config: Config {
debug: true,
max_connections: 100,
timeout_ms: 5000,
},
}Ambiguous Flattened Enum
Both TypeA and TypeB variants have identical fields (value, priority).
The solver cannot determine which variant to use.
KDL Input
resource "test" value="hello" priority=10Target Type
#[derive(Facet)]
struct AmbiguousConfig {
#[facet(kdl::child)]
resource: AmbiguousResource,
}
#[derive(Facet)]
struct AmbiguousResource {
#[facet(kdl::argument)]
name: String,
<span style="color:#7aa2f7;">kind</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">AmbiguousKind</span><span style="color:#a9b1d6;">,</span>
}
#[derive(Facet)]
#[repr(u8)]
enum AmbiguousKind {
TypeA(CommonFields),
TypeB<span style="color:#a9b1d6;">(</span><span style="color:#2ac3de;">CommonFields</span><span style="color:#a9b1d6;">),</span>
}
#[derive(Facet)]
struct CommonFields {
#[facet(kdl::property)]
value: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">priority</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u32</span><span style="color:#a9b1d6;">,</span>
}
Error
kdl::solver
× Ambiguous: multiple resolutions match: ["AmbiguousKind::TypeA", "AmbiguousKind::TypeB"]
help: multiple variants match: AmbiguousKind::TypeA, AmbiguousKind::TypeB
use a KDL type annotation to specify the variant, e.g.: (VariantName)node-name ...
NoMatch with Per-Candidate Failures
Provide field names that don't exactly match any variant.
The solver shows WHY each candidate failed with 'did you mean?' suggestions.
KDL Input
backend "cache" hst="localhost" conn_str="pg"Target Type
#[derive(Facet)]
struct NoMatchConfig {
#[facet(kdl::child)]
backend: NoMatchBackend,
}
#[derive(Facet)]
struct NoMatchBackend {
#[facet(kdl::argument)]
name: String,
<span style="color:#7aa2f7;">kind</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">NoMatchKind</span><span style="color:#a9b1d6;">,</span>
}
#[derive(Facet)]
#[repr(u8)]
enum NoMatchKind {
Sqlite(SqliteBackend),
Postgres<span style="color:#a9b1d6;">(</span><span style="color:#2ac3de;">PostgresBackend</span><span style="color:#a9b1d6;">),</span>
Redis<span style="color:#a9b1d6;">(</span><span style="color:#2ac3de;">RedisBackend</span><span style="color:#a9b1d6;">),</span>
}
#[derive(Facet)]
struct RedisBackend {
#[facet(kdl::property)]
host: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">port</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u16</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">password</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">Option</span><span style="color:#a9b1d6;"><</span><span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">>,</span>
}
#[derive(Facet)]
struct PostgresBackend {
#[facet(kdl::property)]
connection_string: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">pool_size</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u32</span><span style="color:#a9b1d6;">,</span>
}
#[derive(Facet)]
struct SqliteBackend {
#[facet(kdl::property)]
database_path: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">journal_mode</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
}
Error
kdl::solver
× No matching configuration for fields ["conn_str", "hst", "name"]
│
│ No variant matched:
│ - NoMatchKind::Redis: missing fields ["host", "port"], unknown fields ["conn_str", "hst"]
│ - NoMatchKind::Postgres: missing fields ["connection_string", "pool_size"], unknown fields ["conn_str", "hst"]
│ - NoMatchKind::Sqlite: missing fields ["database_path", "journal_mode"], unknown fields ["conn_str", "hst"]
│
│ Unknown fields: ["conn_str", "hst"]
│ Did you mean 'connection_string' instead of 'conn_str'?
│ Did you mean 'host' instead of 'hst'?
╭────
1 │ backend "cache" hst="localhost" conn_str="pg"
· ─┬─ ────┬───
· │ ╰── did you mean `connection_string`?
· ╰── did you mean `host`?
╰────
help: did you mean NoMatchKind::Redis?
all variants checked:
- NoMatchKind::Redis: missing host, port, unexpected conn_str, hst
- NoMatchKind::Postgres: missing connection_string, pool_size, unexpected conn_str, hst
- NoMatchKind::Sqlite: missing database_path, journal_mode, unexpected conn_str, hst
conn_str -> connection_string (did you mean connection_string?)
hst -> host (did you mean host?)
Unknown Fields with 'Did You Mean?' Suggestions
Misspell field names and see the solver suggest corrections!
Uses Jaro-Winkler similarity to find close matches.
KDL Input
server "web" hostnam="localhost" prot=8080Target Type
#[derive(Facet)]
struct TypoConfig {
#[facet(kdl::child)]
server: TypoServer,
}
#[derive(Facet)]
struct TypoServer {
#[facet(kdl::argument)]
name: String,
<span style="color:#7aa2f7;">kind</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">TypoKind</span><span style="color:#a9b1d6;">,</span>
}
#[derive(Facet)]
#[repr(u8)]
enum TypoKind {
Web(WebServer),
Api<span style="color:#a9b1d6;">(</span><span style="color:#2ac3de;">ApiServer</span><span style="color:#a9b1d6;">),</span>
}
#[derive(Facet)]
struct ApiServer {
#[facet(kdl::property)]
endpoint: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">timeout_ms</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u32</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">retry_count</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u8</span><span style="color:#a9b1d6;">,</span>
}
#[derive(Facet)]
struct WebServer {
#[facet(kdl::property)]
hostname: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">port</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u16</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">ssl_enabled</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">bool</span><span style="color:#a9b1d6;">,</span>
}
Error
kdl::solver
× No matching configuration for fields ["hostnam", "name", "prot"]
│
│ No variant matched:
│ - TypoKind::Web: missing fields ["hostname", "port", "ssl_enabled"], unknown fields ["hostnam", "prot"]
│ - TypoKind::Api: missing fields ["endpoint", "retry_count", "timeout_ms"], unknown fields ["hostnam", "prot"]
│
│ Unknown fields: ["hostnam", "prot"]
│ Did you mean 'hostname' instead of 'hostnam'?
│ Did you mean 'port' instead of 'prot'?
╭────
1 │ server "web" hostnam="localhost" prot=8080
· ───┬─── ──┬─
· │ ╰── did you mean `port`?
· ╰── did you mean `hostname`?
╰────
help: did you mean TypoKind::Web?
all variants checked:
- TypoKind::Web: missing hostname, port, ssl_enabled, unexpected hostnam, prot
- TypoKind::Api: missing endpoint, retry_count, timeout_ms, unexpected hostnam, prot
hostnam -> hostname (did you mean hostname?)
prot -> port (did you mean port?)
Value Overflow Detection
When a value doesn't fit ANY candidate type, the solver reports it.
count=5000000000 exceeds both u8 (max 255) and u32 (max ~4 billion).
KDL Input
data count=5000000000Target Type
#[derive(Facet)]
struct ValueConfig {
#[facet(kdl::child)]
data: ValueData,
}
#[derive(Facet)]
struct ValueData {
payload: ValuePayload,
}
#[derive(Facet)]
#[repr(u8)]
enum ValuePayload {
Small(SmallValue),
Large<span style="color:#a9b1d6;">(</span><span style="color:#2ac3de;">LargeValue</span><span style="color:#a9b1d6;">),</span>
}
#[derive(Facet)]
struct LargeValue {
#[facet(kdl::property)]
count: u32,
}
#[derive(Facet)]
struct SmallValue {
#[facet(kdl::property)]
count: u8,
}
Error
kdl::invalid_value
× invalid value for shape: value Integer(5000000000) doesn't fit any candidate type for field 'count'
Multi-Line Config with Typos
A more realistic multi-line configuration file with several typos.
Shows how the solver sorts candidates by closeness to the input.
KDL Input
database "production" \
hots="db.example.com" \
prot=3306 \
usernme="admin" \
pasword="secret123"
Target Type
#[derive(Facet)]
struct MultiLineConfig {
#[facet(kdl::child)]
database: MultiLineDatabase,
}
#[derive(Facet)]
struct MultiLineDatabase {
#[facet(kdl::argument)]
name: String,
<span style="color:#7aa2f7;">kind</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">MultiLineDbKind</span><span style="color:#a9b1d6;">,</span>
}
#[derive(Facet)]
#[repr(u8)]
enum MultiLineDbKind {
MySql(MySqlConfig),
Postgres<span style="color:#a9b1d6;">(</span><span style="color:#2ac3de;">PgConfig</span><span style="color:#a9b1d6;">),</span>
Mongo<span style="color:#a9b1d6;">(</span><span style="color:#2ac3de;">MongoConfig</span><span style="color:#a9b1d6;">),</span>
}
#[derive(Facet)]
struct MongoConfig {
#[facet(kdl::property)]
uri: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">replica_set</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">Option</span><span style="color:#a9b1d6;"><</span><span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">>,</span>
}
#[derive(Facet)]
struct PgConfig {
#[facet(kdl::property)]
host: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">port</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u16</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">database</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">ssl_mode</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
}
#[derive(Facet)]
struct MySqlConfig {
#[facet(kdl::property)]
host: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">port</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u16</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">username</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">password</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
}
Error
kdl::solver
× No matching configuration for fields ["hots", "name", "pasword", "prot", "usernme"]
│
│ No variant matched:
│ - MultiLineDbKind::MySql: missing fields ["host", "password", "port", "username"], unknown fields ["hots", "pasword", "prot", "usernme"]
│ - MultiLineDbKind::Postgres: missing fields ["database", "host", "port", "ssl_mode"], unknown fields ["hots", "pasword", "prot", "usernme"]
│ - MultiLineDbKind::Mongo: missing field 'uri', unknown fields ["hots", "pasword", "prot", "usernme"]
│
│ Unknown fields: ["hots", "pasword", "prot", "usernme"]
│ Did you mean 'host' instead of 'hots'?
│ Did you mean 'password' instead of 'pasword'?
│ Did you mean 'port' instead of 'prot'?
│ Did you mean 'username' instead of 'usernme'?
╭─[2:5]
1 │ database "production"
2 │ hots="db.example.com"
· ──┬─
· ╰── did you mean `host`?
3 │ prot=3306
· ──┬─
· ╰── did you mean `port`?
4 │ usernme="admin"
· ───┬───
· ╰── did you mean `username`?
5 │ pasword="secret123"
· ───┬───
· ╰── did you mean `password`?
╰────
help: did you mean MultiLineDbKind::MySql?
all variants checked:
- MultiLineDbKind::MySql: missing host, password, port, username, unexpected hots, pasword, prot, usernme
- MultiLineDbKind::Postgres: missing database, host, port, ssl_mode, unexpected hots, pasword, prot, usernme
- MultiLineDbKind::Mongo: missing uri, unexpected hots, pasword, prot, usernme
hots -> host (did you mean host?)
pasword -> password (did you mean password?)
prot -> port (did you mean port?)
usernme -> username (did you mean username?)
Unknown Field
KDL contains a property that doesn't exist in the target struct.
With #[facet(deny_unknown_fields)], this is an error.
KDL Input
server host="localhost" prot=8080Target Type
#[derive(Facet)]
#[facet(deny_unknown_fields)]
struct SimpleConfig {
#[facet(kdl::child)]
server: SimpleServer,
}
#[derive(Facet)]
#[facet(deny_unknown_fields)]
struct SimpleServer {
#[facet(kdl::property)]
host: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">port</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u16</span><span style="color:#a9b1d6;">,</span>
}
Error
kdl::unknown_property
× unknown property 'prot', expected one of: host, port
╭────
1 │ server host="localhost" prot=8080
· ──┬─
· ╰── unknown property `prot`
╰────
help: expected one of: host, port
Missing Required Field
KDL is missing a required field that has no default.
KDL Input
server host="localhost"Target Type
#[derive(Facet)]
#[facet(deny_unknown_fields)]
struct SimpleConfig {
#[facet(kdl::child)]
server: SimpleServer,
}
#[derive(Facet)]
#[facet(deny_unknown_fields)]
struct SimpleServer {
#[facet(kdl::property)]
host: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">port</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u16</span><span style="color:#a9b1d6;">,</span>
}
Error
kdl::reflect
× Field 'SimpleServer::port' was not initialized. If you need to leave fields partially initialized and come back later, use deferred mode (begin_deferred/finish_deferred)
Syntax Error: Unquoted Boolean
KDL 2.0 requires booleans to be written as #true/#false.
Bare true or false is a syntax error with a helpful message.
KDL Input
server host="localhost" enabled=trueTarget Type
#[derive(Facet)]
#[facet(deny_unknown_fields)]
struct SimpleConfig {
#[facet(kdl::child)]
server: SimpleServer,
}
#[derive(Facet)]
#[facet(deny_unknown_fields)]
struct SimpleServer {
#[facet(kdl::property)]
host: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">port</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u16</span><span style="color:#a9b1d6;">,</span>
}
Error
kdl::parse
× Failed to parse KDL document
Error:
× Expected identifier string
╭────
1 │ server host="localhost" enabled=true
· ──┬─
· ╰── not identifier string
╰────
Syntax Error: Unclosed Brace
Missing closing brace in nested node structure.
The parser provides line/column information for the error.
KDL Input
server host="localhost" port=8080 {
tls cert="/path/to/cert"
Target Type
#[derive(Facet)]
#[facet(deny_unknown_fields)]
struct SimpleConfig {
#[facet(kdl::child)]
server: SimpleServer,
}
#[derive(Facet)]
#[facet(deny_unknown_fields)]
struct SimpleServer {
#[facet(kdl::property)]
host: String,
<span style="color:#e0af68;">#</span><span style="color:#a9b1d6;">[</span><span style="color:#e0af68;">facet</span><span style="color:#a9b1d6;">(</span><span style="color:#e0af68;">kdl</span><span style="color:#a9b1d6;">::</span><span style="color:#e0af68;">property</span><span style="color:#a9b1d6;">)]</span>
<span style="color:#7aa2f7;">port</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u16</span><span style="color:#a9b1d6;">,</span>
}
Error
kdl::parse
× Failed to parse KDL document
Error:
× No closing '}' for child block
╭─[1:35]
1 │ server host="localhost" port=8080 {
· ┬
· ╰── not closed
2 │ tls cert="/path/to/cert"
╰────
Error:
× Closing '}' was not found after nodes
╭─[1:36]
1 │ ╭─▶ server host="localhost" port=8080 {
2 │ ├─▶ tls cert="/path/to/cert"
· ╰──── not closed
╰────