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;">&lt;</span><span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">&gt;,</span>

}

Success

PersonDoc {
  personPerson {
    name"Alice",
    age30,
    emailOption::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 {
  serverServer {
    name"web-01",
    host"localhost",
    port8080,
  },
}

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 {
  companyCompany {
    name"Acme Corp",
    addressAddress {
      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 {
  memberVec<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;">&lt;</span><span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">&gt;,</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;">&lt;</span><span style="color:#2ac3de;">TlsConfig</span><span style="color:#a9b1d6;">&gt;,</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 {
  configConfig {
    debugtrue,
    max_connections100,
    timeout_ms5000,
  },
}

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 {
    #[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;">&lt;</span><span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">&gt;,</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=8080
Target 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=5000000000
Target 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;">&lt;</span><span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">&gt;,</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=8080
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::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=true
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:    × 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    ╰────