YAML
facet-yaml provides YAML serialization and deserialization for any type that implements Facet. It supports all YAML features including anchors, aliases, multiline strings, and produces clear error diagnostics with source locations.
Basic Struct
Simple struct with optional field serialized to YAML. }Target Type
#[derive(Facet)]
struct Person {
name: String,
<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:#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
Person {
name: "Alice",
age: 30,
email: Option::Some("alice@example.com"),
}YAML Output
---
name: Alice
age: 30
email: alice@example.comNested Structs
Struct containing nested struct and vector. } #[derive(Facet)]
struct Address {
street: String, }Target Type
#[derive(Facet)]
struct Company {
name: String,
<span style="color:#7aa2f7;">address</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">Address</span><span style="color:#a9b1d6;">,</span>
<span style="color:#7aa2f7;">employees</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>
<span style="color:#7aa2f7;">city</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
Success
Company {
name: "Acme Corp",
address: Address {
street: "123 Main St",
city: "Springfield",
},
employees: Vec<String> ["Bob", "Carol", "Dave"],
}YAML Output
---
name: Acme Corp
address:
street: 123 Main St
city: Springfield
employees:
- Bob
- Carol
- Dave
Externally Tagged Enum (default)
Default enum serialization with external tagging: Variant: contentTarget Type
Success
[Message; 3] [
Message::Text("Hello, world!"),
Message::Image {
url: "https://example.com/cat.jpg",
width: 800,
},
Message::Ping,
]YAML Output
---
nullInternally Tagged Enum
Enum with internal tagging using #[facet(tag = "type")] - variant name becomes a field.Target Type
Success
[ApiResponse; 2] [
ApiResponse::Success {
data: "Operation completed",
},
ApiResponse::Error {
code: 404,
message: "Not found",
},
]YAML Output
---
nullAdjacently Tagged Enum
Enum with adjacent tagging using #[facet(tag = "t", content = "c")] - variant name and content are separate fields.Target Type
Success
[Event; 3] [
Event::Click {
x: 100,
y: 200,
},
Event::KeyPress(A),
Event::Resize,
]YAML Output
---
nullUntagged Enum
Enum with #[facet(untagged)] - no tagging, relies on YAML structure to determine variant.Target Type
Success
[StringOrNumber; 2] [StringOrNumber::Str("hello"), StringOrNumber::Num(42)]YAML Output
---
nullMaps with String Keys
HashMap with string keys serializes to YAML mapping.Target Type
Success
HashMap<String, i32> [
"two" => 2,
"one" => 1,
]YAML Output
---
two: 2
one: 1Maps with Integer Keys
HashMap with integer keys - YAML supports non-string keys natively.Target Type
Success
HashMap<i32, String> [
1 => "one",
2 => "two",
]YAML Output
---
1: one
2: twoTuple Struct
Tuple struct serializes as YAML sequence.Target Type
#[derive(Facet)]
struct Point(i32, i32, i32);
Success
Point(
10,
20,
30,
)YAML Output
---
"0": 10
"1": 20
"2": 30Multiline Strings
YAML's excellent support for multiline strings with proper formatting. }Target Type
#[derive(Facet)]
struct Document {
title: String,
<span style="color:#7aa2f7;">content</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
Success
Document {
title: "My Document",
content: "This is a longer piece of text
that spans multiple lines
and demonstrates YAML's string handling.",
}YAML Output
---
title: My Document
content: "This is a longer piece of text\nthat spans multiple lines\nand demonstrates YAML's string handling."Complex Nested Configuration
Complex nested structure demonstrating YAML's readability for configuration files. } #[derive(Facet)]
struct DatabaseConfig {
url: String, } #[derive(Facet)]
struct ServerConfig {
host: String, } #[derive(Facet)]
struct TlsConfig {
cert_path: String, }Target Type
#[derive(Facet)]
struct AppConfig {
debug: bool,
<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:#7aa2f7;">database</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">DatabaseConfig</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>
<span style="color:#7aa2f7;">pool_size</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u32</span><span style="color:#a9b1d6;">,</span>
<span style="color:#7aa2f7;">timeout_secs</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u32</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:#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>
<span style="color:#7aa2f7;">key_path</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
Success
AppConfig {
debug: true,
server: ServerConfig {
host: "localhost",
port: 8080,
tls: Option::Some(TlsConfig {
cert_path: "/etc/ssl/cert.pem",
key_path: "/etc/ssl/key.pem",
}),
},
database: DatabaseConfig {
url: "postgres://localhost/mydb",
pool_size: 10,
timeout_secs: 30,
},
features: Vec<String> ["auth", "logging", "metrics"],
}YAML Output
---
debug: true
server:
host: localhost
port: 8080
tls:
cert_path: /etc/ssl/cert.pem
key_path: /etc/ssl/key.pem
database:
url: "postgres://localhost/mydb"
pool_size: 10
timeout_secs: 30
features:
- auth
- logging
- metrics
Roundtrip Serialization
Original data serialized to YAML and successfully deserialized back to Rust. }Target Type
#[derive(Facet)]
struct Config {
debug: bool,
<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:#7aa2f7;">endpoints</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>
Success
Config {
debug: true,
max_connections: 100,
endpoints: Vec<String> ["https://api1.example.com", "https://api2.example.com"],
}YAML Output
---
debug: true
max_connections: 100
endpoints:
- "https://api1.example.com"
- "https://api2.example.com"
Success
Config {
debug: true,
max_connections: 100,
endpoints: Vec<String> ["https://api1.example.com", "https://api2.example.com"],
}Syntax Error: Bad Indentation
YAML indentation is inconsistent or invalid.
YAML Input
name: test
nested: value
wrong: indentTarget Type
#[derive(Facet)]
struct Config {
name: String,
}Error
yaml::parse
× YAML parse error: mapping values are not allowed in this context at byte 19 line 2 column 9
Syntax Error: Invalid Character
YAML contains an invalid character in an unexpected location.
YAML Input
name: @invalidTarget Type
#[derive(Facet)]
struct Config {
name: String,
}Error
yaml::parse
× YAML parse error: unexpected character: `@' at byte 6 line 1 column 7
Syntax Error: Unclosed Quote
String value has an opening quote but no closing quote.
YAML Input
message: "hello world
name: testTarget Type
#[derive(Facet)]
struct Config {
message: String,
<span style="color:#7aa2f7;">name</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
}
Error
yaml::parse
× YAML parse error: invalid indentation in quoted scalar at byte 9 line 1 column 10
Unknown Field
YAML contains a field that doesn't exist in the target struct.
The error shows the unknown field and lists valid alternatives.
YAML Input
username: alice
emial: alice@example.comTarget Type
#[derive(Facet)]
#[facet(deny_unknown_fields)]
struct User {
username: String,
<span style="color:#7aa2f7;">email</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
}
Error
yaml::unknown_field
× unknown field `emial`, expected one of: ["username", "email"]
╭─[input.yaml:2:1]
1 │ username: alice
2 │ emial: alice@example.com
· ──┬──
· ╰── unknown field `emial`
╰────
Type Mismatch: String for Integer
YAML value is a string where an integer was expected.
YAML Input
id: 42
count: "not a number"Target Type
#[derive(Facet)]
struct Item {
id: u64,
<span style="color:#7aa2f7;">count</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">i32</span><span style="color:#a9b1d6;">,</span>
}
Error
yaml::invalid_value
× invalid value: cannot parse `not a number` as signed integer
╭─[input.yaml:2:8]
1 │ id: 42
2 │ count: "not a number"
· ───────┬──────
· ╰── cannot parse `not a number` as signed integer
╰────
Type Mismatch: Integer for String
YAML value is an integer where a string was expected (may succeed with coercion).
YAML Input
id: 42
name: 123Target Type
#[derive(Facet)]
struct Item {
id: u64,
<span style="color:#7aa2f7;">name</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
}
Success
Item {
id: 42,
name: "123",
}Missing Required Field
YAML is missing a required field that has no default.
YAML Input
host: localhostTarget Type
#[derive(Facet)]
struct ServerConfig {
host: String,
port: u16, // Required but missing from YAML
}Error
yaml::reflect
× reflection error: Field 'ServerConfig::port' was not initialized. If you need to leave fields partially initialized and come back later, use deferred mode (begin_deferred/finish_deferred)
Number Out of Range
YAML number is too large for the target integer type.
YAML Input
count: 999999999999Target Type
#[derive(Facet)]
struct Counter {
count: u32, // Max value is 4,294,967,295
}Error
yaml::number_out_of_range
× number `999999999999` out of range for u32
╭─[input.yaml:1:8]
1 │ count: 999999999999
· ──────┬─────
· ╰── out of range for u32
╰────
Expected Sequence, Got Scalar
YAML has a scalar where a sequence was expected.
YAML Input
items: "not a sequence"Target Type
#[derive(Facet)]
struct Container {
items: Vec<i32>, // Expected sequence, got string
}Error
yaml::unexpected_event
× unexpected YAML event: got Scalar { value: "not a sequence", style: DoubleQuoted, anchor: 0 }, expected sequence start
╭─[input.yaml:1:8]
1 │ items: "not a sequence"
· ────────┬───────
· ╰── unexpected Scalar { value: "not a sequence", style: DoubleQuoted, anchor: 0 }
╰────
Expected Mapping, Got Scalar
YAML has a scalar where a mapping was expected.
YAML Input
config: "not a mapping"Target Type
#[derive(Facet)]
struct Nested {
value: i32,
}
#[derive(Facet)]
struct Outer {
config: Nested, // Expected mapping, got string
}
Error
yaml::unexpected_event
× unexpected YAML event: got Scalar { value: "not a mapping", style: DoubleQuoted, anchor: 0 }, expected mapping start
╭─[input.yaml:1:9]
1 │ config: "not a mapping"
· ───────┬───────
· ╰── unexpected Scalar { value: "not a mapping", style: DoubleQuoted, anchor: 0 }
╰────
Unknown Enum Variant
YAML specifies a variant name that doesn't exist.
YAML Input
UnknownTarget Type
#[derive(Facet)]
#[repr(u8)]
enum Status {
Active,
Inactive,
Pending,
}
// YAML has "Unknown" which is not a valid variantError
yaml::unexpected_event
× unexpected YAML event: got Scalar { value: "Unknown", style: Plain, anchor: 0 }, expected mapping (externally tagged enum)
╭─[input.yaml:1:1]
1 │ Unknown
· ───┬───
· ╰── unexpected Scalar { value: "Unknown", style: Plain, anchor: 0 }
╰────
Enum Wrong Format
Externally tagged enum expects {Variant: content} but got wrong format.
YAML Input
type: Text
content: helloTarget Type
#[derive(Facet)]
#[repr(u8)]
enum MessageError {
Text(String),
Number(i32),
}
// Externally tagged expects:
// Text: "hello"
// But YAML has:
// type: Text
// content: helloError
yaml::reflect
× reflection error: Operation failed on shape MessageError: No variant found with the given name
Internally Tagged Enum: Missing Tag Field
Internally tagged enum requires the tag field to be present.
YAML Input
id: "123"
method: pingTarget Type
#[derive(Facet)]
#[repr(C)]
#[facet(tag = "type")]
enum Request {
Ping { id: String },
Echo { id: String, message: String },
}
// YAML is missing the "type" tag fieldError
yaml::reflect
× reflection error: Operation failed on shape Request: No variant found with the given name
Duplicate Key
YAML mapping contains the same key more than once.
YAML Input
name: first
value: 42
name: secondTarget Type
#[derive(Facet)]
struct Config {
name: String,
<span style="color:#7aa2f7;">value</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">i32</span><span style="color:#a9b1d6;">,</span>
}
Success
Config {
name: "second",
value: 42,
}Anchors and Aliases
YAML anchors and aliases for value reuse.
YAML Input
defaults: &defaults
timeout: 30
retries: 3
production:
<<: *defaults
host: prod.example.com
staging:
<<: *defaults
host: staging.example.com
Target Type
#[derive(Facet)]
struct AllConfigs {
defaults: ServerConfig,
<span style="color:#7aa2f7;">production</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">ServerConfig</span><span style="color:#a9b1d6;">,</span>
<span style="color:#7aa2f7;">staging</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">ServerConfig</span><span style="color:#a9b1d6;">,</span>
}
#[derive(Facet)]
struct ServerConfig {
timeout: u32,
<span style="color:#7aa2f7;">retries</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u32</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>
}
Error
yaml::reflect
× reflection error: Field 'ServerConfig::host' was not initialized. If you need to leave fields partially initialized and come back later, use deferred mode (begin_deferred/finish_deferred)
Multiline String Styles
YAML supports various multiline string styles.
YAML Input
literal: |
This is a literal block.
Newlines are preserved.
folded: >
This is a folded block.
Lines get folded into
a single paragraph.
Target Type
#[derive(Facet)]
struct TextContent {
literal: String,
<span style="color:#7aa2f7;">folded</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
}
Success
TextContent {
literal: "This is a literal block.
Newlines are preserved.
",
folded: "This is a folded block. Lines get folded into a single paragraph.
",
}Empty Input
No YAML content at all.
YAML Input
Target Type
Error
yaml::unexpected_event
× unexpected YAML event: got StreamEnd, expected scalar
╭─[input.yaml:1:1]
╰────
Null for Required Field
YAML has explicit null where a value is required.
YAML Input
name: ~
count: 42Target Type
#[derive(Facet)]
struct Item {
name: String,
<span style="color:#7aa2f7;">count</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">i32</span><span style="color:#a9b1d6;">,</span>
}
Success
Item {
name: "~",
count: 42,
}Error with Unicode Content
Error reporting handles unicode correctly.
YAML Input
emoji: "🎉🚀"
count: nopeTarget Type
#[derive(Facet)]
struct EmojiData {
emoji: String,
<span style="color:#7aa2f7;">count</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">i32</span><span style="color:#a9b1d6;">,</span>
}
Error
yaml::invalid_value
× invalid value: cannot parse `nope` as signed integer
╭─[input.yaml:2:2]
1 │ emoji: "🎉🚀"
2 │ count: nope
· ──┬─
· ╰── cannot parse `nope` as signed integer
╰────
Error in Nested Structure
Error location is correctly identified in deeply nested YAML.
YAML Input
server:
host: localhost
ports:
http: 8080
https: "not a number"
database:
url: postgres://localhost/dbTarget Type
#[derive(Facet)]
struct AppConfig {
server: Server,
}
#[derive(Facet)]
struct Server {
host: String,
<span style="color:#7aa2f7;">ports</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">Ports</span><span style="color:#a9b1d6;">,</span>
<span style="color:#7aa2f7;">database</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">Database</span><span style="color:#a9b1d6;">,</span>
}
#[derive(Facet)]
struct Database {
url: String,
}
#[derive(Facet)]
struct Ports {
http: u16,
<span style="color:#7aa2f7;">https</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u16</span><span style="color:#a9b1d6;">,</span>
}
Error
yaml::invalid_value
× invalid value: cannot parse `not a number` as unsigned integer
╭─[input.yaml:5:12]
4 │ http: 8080
5 │ https: "not a number"
· ───────┬──────
· ╰── cannot parse `not a number` as unsigned integer
6 │ database:
╰────
Error in Sequence Item
Error in one item of a sequence is reported with context.
YAML Input
users:
- name: Alice
age: 30
- name: Bob
age: "twenty-five"
- name: Charlie
age: 35Target Type
#[derive(Facet)]
struct UserList {
users: Vec<User>,
}
#[derive(Facet)]
struct User {
name: String,
<span style="color:#7aa2f7;">age</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u32</span><span style="color:#a9b1d6;">,</span>
}
Error
yaml::invalid_value
× invalid value: cannot parse `twenty-five` as unsigned integer
╭─[input.yaml:5:10]
4 │ - name: Bob
5 │ age: "twenty-five"
· ──────┬──────
· ╰── cannot parse `twenty-five` as unsigned integer
6 │ - name: Charlie
╰────