facet-kdl showcase
Basic Node with Properties
Simple struct with #[facet(property)] fields becomes KDL properties.
KDL Input
person
Target Type
#[derive(Facet)] struct PersonDoc { person: Person, } #[derive(Facet)] struct Person { name: String, age: u32, email: Option<String>, }
Error
kdl::reflect
× Value 'Person' was not initialized
Node with Argument
#[facet(argument)] field becomes a positional argument after the node name.
Result: server "web-01" host="localhost" port=8080
KDL Input
server
Target Type
#[derive(Facet)] struct ServerDoc { server: Server, } #[derive(Facet)] struct Server { name: String, host: String, port: u16, }
Error
kdl::reflect
× Value 'Server' was not initialized
Nested Nodes (Children)
#[facet(child)] fields become nested child nodes in braces.
The address struct becomes a child node of company.
KDL Input
company { address }
Target Type
#[derive(Facet)] struct CompanyDoc { company: Company, } #[derive(Facet)] struct Company { name: String, address: Address, } #[derive(Facet)] struct Address { street: String, city: String, }
Error
kdl::reflect
× Value 'Address' was not initialized
Vec as Repeated Children
#[facet(children)] on a Vec field creates repeated child nodes.
Each Member becomes a separate member node.
KDL Input
Target Type
#[derive(Facet)] struct TeamDoc { member: Vec<Member>, } #[derive(Facet)] struct Member { name: String, role: String, }
Error
kdl::invalid_document_shape
× invalid shape Undefined — needed struct with child/children fields
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 { tls } database
Target Type
#[derive(Facet)] struct AppConfig { debug: bool, server: ServerConfig, database: DatabaseConfig, features: Vec<String>, } #[derive(Facet)] struct DatabaseConfig { name: String, url: String, pool_size: u32, } #[derive(Facet)] struct ServerConfig { name: String, host: String, port: u16, tls: Option<TlsConfig>, } #[derive(Facet)] struct TlsConfig { cert_path: String, key_path: String, }
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
Target Type
#[derive(Facet)] struct ConfigDoc { config: Config, } #[derive(Facet)] struct Config { debug: bool, max_connections: u32, timeout_ms: u32, }
Error
kdl::reflect
× Value 'Config' was not initialized
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=10
Target Type
#[derive(Facet)] struct AmbiguousConfig { resource: AmbiguousResource, } #[derive(Facet)] struct AmbiguousResource { name: String, kind: AmbiguousKind, } #[derive(Facet)] #[repr(u8)] enum AmbiguousKind { TypeA(CommonFields), TypeB(CommonFields), } #[derive(Facet)] struct CommonFields { value: String, priority: u32, }
Error
kdl::solver
× No matching configuration for fields ["priority", "value"]
│
│ No variant matched:
│ - AmbiguousKind::TypeA: missing field 'name'
│ - AmbiguousKind::TypeB: missing field 'name'
help: no variant matched:
- AmbiguousKind::TypeA: missing name
- AmbiguousKind::TypeB: missing 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 { backend: NoMatchBackend, } #[derive(Facet)] struct NoMatchBackend { name: String, kind: NoMatchKind, } #[derive(Facet)] #[repr(u8)] enum NoMatchKind { Sqlite(SqliteBackend), Postgres(PostgresBackend), Redis(RedisBackend), } #[derive(Facet)] struct RedisBackend { host: String, port: u16, password: Option<String>, } #[derive(Facet)] struct PostgresBackend { connection_string: String, pool_size: u32, } #[derive(Facet)] struct SqliteBackend { database_path: String, journal_mode: String, }
Error
kdl::solver
× No matching configuration for fields ["conn_str", "hst"]
│
│ No variant matched:
│ - NoMatchKind::Redis: missing fields ["host", "name", "port"], unknown fields ["conn_str", "hst"]
│ - NoMatchKind::Postgres: missing fields ["connection_string", "name", "pool_size"], unknown fields ["conn_str", "hst"]
│ - NoMatchKind::Sqlite: missing fields ["database_path", "journal_mode", "name"], 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, name, port, unexpected conn_str, hst
- NoMatchKind::Postgres: missing connection_string, name, pool_size, unexpected conn_str, hst
- NoMatchKind::Sqlite: missing database_path, journal_mode, name, 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=8080
Target Type
#[derive(Facet)] struct TypoConfig { server: TypoServer, } #[derive(Facet)] struct TypoServer { name: String, kind: TypoKind, } #[derive(Facet)] #[repr(u8)] enum TypoKind { Web(WebServer), Api(ApiServer), } #[derive(Facet)] struct ApiServer { endpoint: String, timeout_ms: u32, retry_count: u8, } #[derive(Facet)] struct WebServer { hostname: String, port: u16, ssl_enabled: bool, }
Error
kdl::solver
× No matching configuration for fields ["hostnam", "prot"]
│
│ No variant matched:
│ - TypoKind::Web: missing fields ["hostname", "name", "port", "ssl_enabled"], unknown fields ["hostnam", "prot"]
│ - TypoKind::Api: missing fields ["endpoint", "name", "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, name, port, ssl_enabled, unexpected hostnam, prot
- TypoKind::Api: missing endpoint, name, 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=5000000000
Target Type
#[derive(Facet)] struct ValueConfig { data: ValueData, } #[derive(Facet)] struct ValueData { payload: ValuePayload, } #[derive(Facet)] #[repr(u8)] enum ValuePayload { Small(SmallValue), Large(LargeValue), } #[derive(Facet)] struct LargeValue { count: u32, } #[derive(Facet)] struct SmallValue { 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 { database: MultiLineDatabase, } #[derive(Facet)] struct MultiLineDatabase { name: String, kind: MultiLineDbKind, } #[derive(Facet)] #[repr(u8)] enum MultiLineDbKind { MySql(MySqlConfig), Postgres(PgConfig), Mongo(MongoConfig), } #[derive(Facet)] struct MongoConfig { uri: String, replica_set: Option<String>, } #[derive(Facet)] struct PgConfig { host: String, port: u16, database: String, ssl_mode: String, } #[derive(Facet)] struct MySqlConfig { host: String, port: u16, username: String, password: String, }
Error
kdl::solver
× No matching configuration for fields ["hots", "pasword", "prot", "usernme"]
│
│ No variant matched:
│ - MultiLineDbKind::MySql: missing fields ["host", "name", "password", "port", "username"], unknown fields ["hots", "pasword", "prot", "usernme"]
│ - MultiLineDbKind::Postgres: missing fields ["database", "host", "name", "port", "ssl_mode"], unknown fields ["hots", "pasword", "prot", "usernme"]
│ - MultiLineDbKind::Mongo: missing fields ["name", "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, name, password, port, username, unexpected hots, pasword, prot, usernme
- MultiLineDbKind::Postgres: missing database, host, name, port, ssl_mode, unexpected hots, pasword, prot, usernme
- MultiLineDbKind::Mongo: missing name, 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=8080
Target Type
#[derive(Facet)] #[facet(deny_unknown_fields)] struct SimpleConfig { server: SimpleServer, } #[derive(Facet)] #[facet(deny_unknown_fields)] struct SimpleServer { host: String, port: u16, }
Error
kdl::unknown_property
× unknown property 'host', expected one of:
╭────
1 │ server host="localhost" prot=8080
· ──┬─
· ╰── unknown property host
╰────
help: expected one of:
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 { server: SimpleServer, } #[derive(Facet)] #[facet(deny_unknown_fields)] struct SimpleServer { host: String, port: u16, }
Error
kdl::unknown_property
× unknown property 'host', expected one of:
╭────
1 │ server host="localhost"
· ──┬─
· ╰── unknown property host
╰────
help: expected one of: