Read a YAML file into typed Rust data with serde: nested structs, a map, an optional section, a default and an enum. oneyaml is a serde data format like serde_json, so the same #[serde(...)] attributes apply.
cargo add [email protected] serde -F serde/deriveThe file:
# service.yaml name: web image: nginx:1.27 env: LOG_LEVEL: info PORT: "8080" healthcheck: path: /healthz intervalSeconds: 10 restart: on-failure
The program:
use serde::Deserialize; use std::collections::BTreeMap; #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] struct Service { name: String, image: String, #[serde(default = "one")] replica_count: u32, env: BTreeMap<String, String>, healthcheck: Option<Healthcheck>, restart: Restart, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] struct Healthcheck { path: String, interval_seconds: u32, } #[derive(Debug, Deserialize)] #[serde(rename_all = "kebab-case")] enum Restart { Always, OnFailure, Never, } fn one() -> u32 { 1 } fn main() -> Result<(), Box<dyn std::error::Error>> { let src = std::fs::read_to_string("service.yaml")?; let svc: Service = oneyaml::from_str(&src)?; println!("{} runs {} x{}", svc.name, svc.image, svc.replica_count); println!("env: {:?}", svc.env); if let Some(h) = &svc.healthcheck { println!("health check: {} every {}s", h.path, h.interval_seconds); } match svc.restart { Restart::Always => println!("restart: always"), Restart::OnFailure => println!("restart: on failure"), Restart::Never => println!("restart: never"), } Ok(()) }
web runs nginx:1.27 x1 env: {"LOG_LEVEL": "info", "PORT": "8080"} health check: /healthz every 10s restart: on failure
Good to know
replicaCountisn’t in the file, so#[serde(default = "one")]fills it. Without a default, a missing field is an error that names it.PORT: "8080"is quoted, so it reads as a string into theBTreeMap<String, String>. Unquoted,8080is an integer, and reading it into aStringis a type error. oneyaml doesn’t convert scalars behind your back.- The YAML 1.2 Core schema is the default: plain
yes,no,onandoffare strings, and0755is 755. To read a file written for YAML 1.1, see YAML 1.1 booleans. from_sliceandfrom_readerread bytes and anyio::Read. Each has a_withform that takesSettings.
When the shape isn’t known ahead of time, read a Value instead: read YAML without a schema. A field of the wrong type is reported with its line, column and path: errors with line and column.