From Value

facet-value provides a dynamic Value type and conversion to/from any Facet type. Use it for format-agnostic data manipulation, testing, or bridging between different serialization formats.

Happy Path

Simple Struct

Deserialize a Value map into a struct with basic fields.

Value Input

{
  name"Alice",
  age30,
  email"alice@example.com",
}
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"),
}

Nested Structs

Nested structs are deserialized recursively.

Value Input

{
  person{
    name"Bob",
    age42,
    emailnull,
  },
  address{
    street"123 Main St",
    city"Springfield",
    zip"12345",
  },
  department"Engineering",
}
Target Type
#[derive(Facet)]
struct Employee {
    person: Person,
<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;">department</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</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>

<span style="color:#7aa2f7;">zip</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>

}

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

Employee {
  personPerson {
    name"Bob",
    age42,
    emailOption::None,
  },
  addressAddress {
    street"123 Main St",
    city"Springfield",
    zip"12345",
  },
  department"Engineering",
}

Unit Enum Variant

A string value deserializes into a unit variant.

Value Input

"Active"
Target Type
#[derive(Facet)]
#[repr(u8)]
enum Status {
    Active,
Inactive<span style="color:#a9b1d6;">,</span>

Pending<span style="color:#a9b1d6;">,</span>

}

Success

Status::Active

Tuple Enum Variant

Externally tagged enum: {"Variant": content}.

Value Input

{
  Text"Hello world!",
}
Target Type
#[derive(Facet)]
#[repr(u8)]
enum Message {
    Text(String),
Number<span style="color:#a9b1d6;">(</span><span style="color:#2ac3de;">i32</span><span style="color:#a9b1d6;">),</span>

Data <span style="color:#a9b1d6;">{</span>
    <span style="color:#7aa2f7;">id</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u64</span><span style="color:#a9b1d6;">,</span>

    <span style="color:#7aa2f7;">payload</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
<span style="color:#a9b1d6;">},</span>

}

Success

Message::Text("Hello world!")

Struct Enum Variant

Struct variants deserialize with named fields.

Value Input

{
  Data{
    id42,
    payload"secret data",
  },
}
Target Type
#[derive(Facet)]
#[repr(u8)]
enum Message {
    Text(String),
Number<span style="color:#a9b1d6;">(</span><span style="color:#2ac3de;">i32</span><span style="color:#a9b1d6;">),</span>

Data <span style="color:#a9b1d6;">{</span>
    <span style="color:#7aa2f7;">id</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">u64</span><span style="color:#a9b1d6;">,</span>

    <span style="color:#7aa2f7;">payload</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">String</span><span style="color:#a9b1d6;">,</span>
<span style="color:#a9b1d6;">},</span>

}

Success

Message::Data {
  id42,
  payload"secret data",
}

Vec Deserialization

Arrays deserialize into Vec<T>.

Value Input

[
  1,
  2,
  3,
  4,
  5,
]
Target Type

Success

Vec<i32> [1, 2, 3, 4, 5]

Fixed-Size Array

Arrays with exact length deserialize into [T; N].

Value Input

[
  "a",
  "b",
  "c",
]
Target Type

Success

[String; 3] ["a", "b", "c"]

HashMap

Objects deserialize into HashMap<String, T>.

Value Input

{
  x10,
  y20,
  z30,
}
Target Type

Success

HashMap<String, i32> [
  "x" => 10,
  "y" => 20,
  "z" => 30,
]

Nested Collections

null values become None in Option<T>.

Value Input

[
  1,
  null,
  3,
  null,
  5,
]
Target Type

Success

Vec<Option> [Option::Some(1), Option::None, Option::Some(3), Option::None, Option::Some(5)]

Default Field Values

Fields marked with #[facet(default)] use Default::default() when missing.

Value Input

{
  name"minimal",
}
Target Type
#[derive(Facet)]
struct Config {
    name: String,
<span style="color:#7aa2f7;">enabled</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">bool</span><span style="color:#a9b1d6;">,</span>

<span style="color:#7aa2f7;">max_retries</span><span style="color:#a9b1d6;">:</span> <span style="color:#2ac3de;">Option</span><span style="color:#a9b1d6;">&lt;</span><span style="color:#2ac3de;">u32</span><span style="color:#a9b1d6;">&gt;,</span>

}

Success

Config {
  name"minimal",
  enabledfalse,
  max_retriesOption::None,
}

Errors

Error: Type Mismatch

Trying to deserialize a string as an integer.

Error

  × reflection error: Operation failed on shape i32: Failed to parse string value

Error:    × input.json    ╭────  1 │ "not a number"    · ───────┬──────    ·        ╰── this value    ╰────

Error: Number Out of Range

Value 1000 is too large for u8 (max 255).

Error

  × number out of range: 1000 out of range for u8

Error:    × input.json    ╭────  1 │ 1000    · ──┬─    ·   ╰── this value: 1000 out of range for u8    ╰────

Error: Wrong Array Length

Array has 4 elements but target type expects exactly 3.

Error

  × unsupported: fixed array has 3 elements but got 4

Error:    × input.json    ╭─[1:1]  1 │  [  2 │      1,  3 │      2,  4 │      3,  5 │      4  6 │  ]    · ─── this value    ╰────

Error: Invalid Enum Variant

"Unknown" is not a valid variant of Status.

Error

  × reflection error: Operation failed on shape Status: No variant found with the given name

Error:    × input.json    ╭────  1 │ "Unknown"    · ────┬────    ·     ╰── this value    ╰────

Error:    × target.rs    ╭─[1:24]  1 │  #[derive(Facet)]  2 │    #[repr(u8)]  3 │    enum Status {  4 │        Active,  5 │        Inactive,  6 │        Pending,  7 │  }    · ─── target type    ╰────

Error: Expected Object, Got Array

Cannot deserialize an array as a struct.

Error

  × type mismatch: expected object, got Array

Error:    × input.json    ╭─[1:1]  1 │  [  2 │      1,  3 │      2,  4 │      3  5 │  ]    · ─── got Array    ╰────

Error:    × target.rs    ╭─[1:24]  1 │  #[derive(Facet)]  2 │    struct Person {  3 │        name: String,  4 │        age: u32,  5 │        email: Option<String>,  6 │  }    · ─── expected object    ╰────