Read YAML file where some field can have arbitrary values



examples/yaml/deserialize-yaml-where-some-keys-are-arbitrary/data.yaml
---
title: Sample file
jobs:
  test:
    runs-on: ubuntu
  build:
    runs-on: windows

# Defined fields: title, jobs, runs-on
# Values selected from a well defined list: ubuntu, windows
# User supplied values: test, build, "Sample file"

examples/yaml/deserialize-yaml-where-some-keys-are-arbitrary/src/main.rs
use std::collections::HashMap;

use serde::{Deserialize, Serialize};

#[allow(non_camel_case_types)]
#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum Platform {
    linux,
    ubuntu,
    windows,
    macos,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
struct Job {
    #[serde(rename = "runs-on")]
    runs_on: Platform,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
struct Config {
    title: String,
    jobs: HashMap<String, Job>,
}

fn main() {
    let filename = "data.yaml";

    read_any_yaml(filename);
    read_struct_yaml(filename);
}

fn read_any_yaml(filename: &str) {
    let content = std::fs::read_to_string(filename).expect("File not found");
    let data: serde_yml::Value = serde_yml::from_str(&content).expect("YAML parsing error");
    println!("{:#?}", &data);
    println!("--------");

    let title = match data.get("title") {
        Some(val) => val.as_str().unwrap(),
        None => panic!("Field text does not exist"),
    };
    println!("title: {title}");

    let jobs = match data.get("jobs") {
        Some(val) => val.as_mapping().unwrap(),
        None => panic!("Field jobs does not exist"),
    };
    println!("{:#?}", &jobs);
    for (key, value) in jobs.iter() {
        println!("key: {:?}  value: {:?}", key, value);
    }
    println!("--------");
}

fn read_struct_yaml(filename: &str) {
    let content = std::fs::read_to_string(filename).expect("File not found");
    let data: Config = serde_yml::from_str(&content).expect("YAML parsing error");
    println!("data = {:?}", data);
    println!("title: {}", data.title);
    println!("{:?}", data.jobs.keys());
    for (key, value) in data.jobs.iter() {
        println!("key: {:?} {:?}", key, value);
    }
    assert_eq!(data.title, "Sample file");
    assert_eq!(data.jobs["test"].runs_on, Platform::ubuntu);
    assert_eq!(data.jobs["build"].runs_on, Platform::windows);
}