Laminate
Data, shaped layer by layer.
lam·i·nate /ˈlaməˌnāt/ verb
To bond layers of material together, each adding strength and structure to the whole. In software: to progressively shape raw, unstructured data into typed, validated values — layer by layer, at whatever depth your application requires.
The missing data layer for Rust. Progressive type coercion, automatic format detection, and fault-tolerant deserialization — built on serde, not against it.
MIT OR Apache-2.0 · Rust 1.85+ · 3 core dependencies
Install
[dependencies]
laminate = { version = "0.4", features = ["full"] }
Real-world data is messy. Laminate handles it.
use laminate::FlexValue;
let data = FlexValue::from_json(
r#"{"port": "8080", "debug": "true"}"#
)?;
let port: u16 = data.extract("port")?; // "8080" -> 8080
let debug: bool = data.extract("debug")?; // "true" -> true
FlexValue::from_llm_response pulls a JSON payload out of fenced or prose-wrapped model output before parsing; the derive now shapes string-valued enums with a #[laminate(unknown)] open fallback; and provider Usage carries OpenAI/Anthropic cache tokens.
“I would love to see this explored in a different library specifically geared toward fault-tolerant partially successful deserialization.”
— serde maintainer, issue #464 (2017)
When serde's maintainer closed that request, he noted it belonged in a different library. Laminate is built to be that library — it doesn't replace serde, it builds on top of it, adding the progressive coercion and graceful degradation serde deliberately doesn't provide.
What's in the box
Progressive Coercion
Four levels of strictness — from exact type matching to best-effort conversion. You choose how forgiving your pipeline should be.
Learn more →Automatic Type Detection
guess_type() identifies 20 types from raw strings — integers, dates, currencies, emails, UUIDs, IBANs, credit cards, and more — with confidence scores.
Graduated Diagnostics
Every coercion reports what happened, the risk level (Info/Warning/Risky), and how to tighten it. Audit your data pipeline without breaking it.
Learn more →Domain Packs
Built-in parsers for dates (18 formats), currencies (19 symbols), medical lab values (36 analytes), identifiers (12 types with checksums), units, and geographic coordinates.
Learn more →Provider Normalization
Parse and normalize responses from Anthropic, OpenAI, and Ollama into a unified structure. Stream SSE events incrementally.
Learn more →Derive Macro
#[derive(Laminate)] with seven field attributes (coerce, default, overflow, rename, parse_json_string, flatten, skip), string-valued enums with a #[laminate(unknown)] fallback, and a ToolDefinition for typed LLM tool-calls.
Operational Modes
Lenient, Absorbing, or Strict — type-level modes that set coercion, unknown-field, and missing-field behavior at once, checked at compile time. Pick one at runtime with DynamicMode.
Schema + Audit
Infer a schema from a sample, attach constraints, then audit new data and get back exactly where it violates — type mismatches, missing fields, unexpected nulls, and more.
Learn more →Sources + Tooling
Read rows from Postgres, SQLite, MySQL, and JSON/JSONL files with laminate-sql, or profile and validate from the terminal with laminate-cli (infer / audit / inspect).