Expand description
§tmyc — Personal YAML for serde
A YAML 1.2 best-effort parser and emmitter with the goals of:
- Filling the gap after archival of
serde-yaml - Best effort compliance to support common docker-compose, kubernetes resource and configuration files
- Trustworthy, least-dependencies implementation to avoid the trust issues surrounding other similarly motivated replacement crates dismissed for suspicious, inexplicable dependencies and code
§Quick start
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Service {
name: String,
port: u16,
}
let yaml = "name: web\nport: 8080\n";
let svc: Service = tmyc::from_str(yaml).unwrap();
assert_eq!(svc, Service { name: "web".into(), port: 8080 });
let back = tmyc::to_string(&svc).unwrap();
assert_eq!(back, yaml);§Entry points
| Function | Purpose |
|---|---|
from_str | Deserialize a single document into T: DeserializeOwned. |
from_value | Deserialize from a pre-parsed Value, supporting zero-copy borrows. |
to_string | Serialize T: Serialize to a YAML string. |
to_value | Serialize T: Serialize to a Value (for inspection or post-processing). |
Parser | Manual parsing API. Use Parser::parse_all for multi-document streams. |
§Why DeserializeOwned for from_str?
from_str builds an intermediate Value that lives only for the call.
If your target type held borrowed &str fields they’d reference a Value
that’s already been dropped — unsound. The serde::de::DeserializeOwned
bound rules out borrowed fields at compile time.
To get the zero-copy payoff (struct fields that are &str slices of the
input), keep a Value alive yourself and use from_value:
use serde::Deserialize;
#[derive(Deserialize)]
struct Borrowed<'a> { name: &'a str }
let src = "name: hello\n";
let value = tmyc::Parser::new(src).parse().unwrap();
let b: Borrowed<'_> = tmyc::from_value(&value).unwrap();
assert_eq!(b.name, "hello");§Multi-document streams
Files written by tools like kubectl get all -o yaml contain multiple
documents separated by ---. Use Parser::parse_all:
let stream = "\
---
kind: Pod
---
kind: Service
";
let docs = tmyc::Parser::new(stream).parse_all().unwrap();
assert_eq!(docs.len(), 2);§YAML feature coverage
Per YAML 1.2:
- Block and flow scalars (literal
|, folded>, plain, single/double quoted) - Block and flow containers (sequences and mappings)
- Standard tags (
!!str,!!int,!!float,!!bool,!!null) with coercion - Custom tags preserved via
Value::Tagged - Anchors (
&name) and aliases (*name), document-scoped per spec - Multi-document streams (
---/...) - UTF-8 BOM and leading directives (
%YAML/%TAG) tolerated
Beyond strict YAML 1.2:
- Merge keys (
<<: *base) resolved automatically — heavy in docker-compose.
Not implemented (rare in target ecosystems):
- Explicit complex keys (
? key: value) - Strict
%YAMLversion enforcement %TAGhandle substitution
§Design principles
- Spec-correct parser, pragmatic emitter. Roundtrip-equal in data, not necessarily byte-identical in presentation.
- Zero-copy via
Cow<'a, str>. Plain and unescaped quoted scalars are borrowed slices of the input; allocation only when escapes or folds force it. - Lossless scalar resolution. Plain
42→Int/UInt(42); quoted"42"staysString("42").
Structs§
Enums§
- Value
- A parsed YAML node, lifetime-bound to the original source string.
Functions§
- from_
str - Parse a YAML string and deserialize the single document into
T. - from_
value - Deserialize from a pre-parsed
Value. - to_
string - Serialize
Tto a YAML string. - to_
value - Serialize a value to a
Value.