facet-kdl
facet-kdl
KDL serialization and deserialization for Facet types.
Quick start
Add facet-kdl alongside your Facet types and derive Facet:
use Facet;
use facet_kdl as kdl;
Common patterns
#[facet(kdl::child)]for a single required child node,#[facet(kdl::children)]for lists/maps/sets of children.#[facet(kdl::property)]maps node properties (key/value pairs) to fields.#[facet(kdl::arguments)]/#[facet(kdl::argument)]read positional arguments on a node.#[facet(flatten)]merges nested structs/enums; the solver uses property/child presence to choose variants.Spanned<T>is supported: properties/arguments can be captured withmiette::SourceSpandata.
Multiple children fields
When a struct has a single #[facet(kdl::children)] field, all child nodes are collected into that field.
When a struct has multiple #[facet(kdl::children)] fields, nodes are routed based on matching
the node name to the singular form of the field name:
use Facet;
use facet_kdl as kdl;
With this KDL:
dependency "serde" version="1.0"
sample "test.txt"
dependency "tokio" version="1.0"
sample "example.txt"
The nodes are routed based on name matching:
dependencynodes →dependenciesfield (singular matches plural)samplenodes →samplesfield
Supported pluralization patterns:
- Simple
s:item→items iesending:dependency→dependenciesesending:box→boxes
Note: Use #[facet(default)] on children fields to allow them to be empty when no matching nodes are present.
KDL syntax: arguments vs properties
A common source of confusion is the difference between arguments and properties in KDL:
// Arguments are positional values after the node name
server "localhost" 8080
// Properties are key=value pairs
server host="localhost" port=8080
// You can mix both - arguments come first, then properties
server "localhost" port=8080
This matters for your struct definitions:
use Facet;
use facet_kdl as kdl;
// For: server "localhost" port=8080
Child nodes with arguments
A particularly common KDL pattern uses child nodes with arguments:
config {
name "my-app"
version "1.0.0"
debug true
}
Here, name "my-app" is a child node named name with an argument "my-app".
This is not a property (which would be name="my-app").
To deserialize this pattern, each child node needs its own struct with a kdl::argument field:
use Facet;
use facet_kdl as kdl;
If you're getting "no matching argument field for value" errors, check whether your KDL
uses name "value" (child node with argument) vs name="value" (property) syntax.
Feature flags
default/std: enablesstdfor dependencies.alloc:no_stdbuilds withalloconly.
Error reporting
Errors use miette spans where possible, so diagnostics can point back to the offending KDL source.
License
MIT OR Apache-2.0, at your option.
Sponsors
Thanks to all individual sponsors:
...along with corporate sponsors:
...without whom this work could not exist.
Special thanks
The facet logo was drawn by Misiasart.
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.