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

}

Success

Person {
  name"Alice",
  age30,
  emailOption::Some("alice@example.com"),
}

YAML Output

---
name: Alice
age: 30
email: alice@example.com

Nested Structs

Struct containing nested struct and vector.

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

}

#[derive(Facet)] struct Address { street: String,

<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",
  addressAddress {
    street"123 Main St",
    city"Springfield",
  },
  employeesVec<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: content

Target Type

Success

[Message; 3] [
  Message::Text("Hello, world!"),
  Message::Image {
    url"https://example.com/cat.jpg",
    width800,
  },
  Message::Ping,
]

YAML Output

---
null

Internally 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 {
    code404,
    message"Not found",
  },
]

YAML Output

---
null

Adjacently 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 {
    x100,
    y200,
  },
  Event::KeyPress(A),
  Event::Resize,
]

YAML Output

---
null

Untagged 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

---
null

Maps 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: 1

Maps 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: two

Tuple 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": 30

Multiline 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.

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

}

#[derive(Facet)] struct DatabaseConfig { url: String,

<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>

}

#[derive(Facet)] struct ServerConfig { host: String,

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

}

#[derive(Facet)] struct TlsConfig { cert_path: String,

<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 {
  debugtrue,
  serverServerConfig {
    host"localhost",
    port8080,
    tlsOption::Some(TlsConfig {
      cert_path"/etc/ssl/cert.pem",
      key_path"/etc/ssl/key.pem",
    }),
  },
  databaseDatabaseConfig {
    url"postgres://localhost/mydb",
    pool_size10,
    timeout_secs30,
  },
  featuresVec<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;">&lt;</span><span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">&gt;,</span>

}

Success

Config {
  debugtrue,
  max_connections100,
  endpointsVec<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 {
  debugtrue,
  max_connections100,
  endpointsVec<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: indent
Target 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: @invalid
Target 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: test
Target 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.com
Target 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: 123
Target 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 {
  id42,
  name"123",
}

Missing Required Field

YAML is missing a required field that has no default.

YAML Input

host: localhost
Target 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: 999999999999
Target 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

Unknown
Target Type
#[derive(Facet)]
#[repr(u8)]
enum Status {
    Active,
    Inactive,
    Pending,
}
// YAML has "Unknown" which is not a valid variant

Error

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: hello
Target Type
#[derive(Facet)]
#[repr(u8)]
enum MessageError {
    Text(String),
    Number(i32),
}
// Externally tagged expects:
//   Text: "hello"
// But YAML has:
//   type: Text
//   content: hello

Error

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: ping
Target Type
#[derive(Facet)]
#[repr(C)]
#[facet(tag = "type")]
enum Request {
    Ping { id: String },
    Echo { id: String, message: String },
}
// YAML is missing the "type" tag field

Error

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: second
Target 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",
  value42,
}

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: 42
Target 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"~",
  count42,
}

Error with Unicode Content

Error reporting handles unicode correctly.

YAML Input

emoji: "🎉🚀"
count: nope
Target 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/db
Target 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: 35
Target 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    ╰────