| Crates.io | facet-kdl-legacy |
| lib.rs | facet-kdl-legacy |
| version | 0.36.0 |
| created_at | 2025-12-29 20:38:35.831192+00 |
| updated_at | 2025-12-29 20:38:35.831192+00 |
| description | Legacy KDL (KDL Document Language) serialization and deserialization for Facet types - use facet-kdl instead |
| homepage | https://facet.rs |
| repository | https://github.com/facet-rs/facet |
| max_upload_size | |
| id | 2011306 |
| size | 489,859 |
KDL serialization and deserialization for Facet types.
Add facet-kdl alongside your Facet types and derive Facet:
use facet::Facet;
use facet_kdl_legacy as kdl;
#[derive(Facet, Debug, PartialEq)]
struct Config {
#[facet(kdl::child)]
server: Server,
}
#[derive(Facet, Debug, PartialEq)]
struct Server {
#[facet(kdl::argument)]
host: String,
#[facet(kdl::property)]
port: u16,
}
fn main() -> Result<(), facet_kdl_legacy::KdlError> {
let cfg: Config = facet_kdl_legacy::from_str(r#"server "localhost" port=8080"#)?;
assert_eq!(cfg.server.port, 8080);
let text = facet_kdl_legacy::to_string(&cfg)?;
assert_eq!(text, "server \"localhost\" port=8080\n");
Ok(())
}
#[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 with miette::SourceSpan data.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::Facet;
use facet_kdl_legacy as kdl;
#[derive(Facet, Debug)]
struct Config {
#[facet(kdl::children, default)]
dependencies: Vec<Dependency>,
#[facet(kdl::children, default)]
samples: Vec<Sample>,
}
#[derive(Facet, Debug)]
struct Dependency {
#[facet(kdl::argument)]
name: String,
#[facet(kdl::property)]
version: String,
}
#[derive(Facet, Debug)]
struct Sample {
#[facet(kdl::argument)]
path: String,
}
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:
dependency nodes → dependencies field (singular matches plural)sample nodes → samples fieldSupported pluralization patterns:
s: item → itemsies ending: dependency → dependencieses ending: box → boxesNote: Use #[facet(default)] on children fields to allow them to be empty when no matching nodes are present.
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::Facet;
use facet_kdl_legacy as kdl;
// For: server "localhost" port=8080
#[derive(Facet)]
struct Server {
#[facet(kdl::argument)] // captures "localhost"
host: String,
#[facet(kdl::property)] // captures port=8080
port: u16,
}
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::Facet;
use facet_kdl_legacy as kdl;
#[derive(Facet)]
struct Config {
#[facet(kdl::child)]
name: Name,
#[facet(kdl::child)]
version: Version,
#[facet(kdl::child)]
debug: Debug,
}
#[derive(Facet)]
struct Name {
#[facet(kdl::argument)]
value: String,
}
#[derive(Facet)]
struct Version {
#[facet(kdl::argument)]
value: String,
}
#[derive(Facet)]
struct Debug {
#[facet(kdl::argument)]
value: bool,
}
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.
default/std: enables std for dependencies.alloc: no_std builds with alloc only.Errors use miette spans where possible, so diagnostics can point back to the offending KDL source.
Thanks to all individual sponsors:
...along with corporate sponsors:
...without whom this work could not exist.
The facet logo was drawn by Misiasart.
Licensed under either of:
at your option.