omni_dev/data/
yaml.rs

1//! YAML processing utilities
2
3use anyhow::{Context, Result};
4use serde::{Deserialize, Serialize};
5use std::fs;
6use std::path::Path;
7use yaml_rust_davvid::YamlEmitter;
8
9/// Serialize data structure to YAML string with proper multi-line formatting
10pub fn to_yaml<T: Serialize>(data: &T) -> Result<String> {
11    // First convert to serde_yaml::Value, then to yaml-rust format
12    let serde_value = serde_yaml::to_value(data).context("Failed to serialize to serde value")?;
13    let yaml_rust_value = convert_serde_to_yaml_rust(&serde_value)?;
14
15    // Use yaml-rust emitter with multiline strings enabled
16    let mut output = String::new();
17    let mut emitter = YamlEmitter::new(&mut output);
18    emitter.multiline_strings(true);
19    emitter
20        .dump(&yaml_rust_value)
21        .context("Failed to emit YAML")?;
22
23    Ok(output)
24}
25
26/// Convert serde_yaml::Value to yaml_rust_davvid::Yaml
27fn convert_serde_to_yaml_rust(value: &serde_yaml::Value) -> Result<yaml_rust_davvid::Yaml> {
28    use yaml_rust_davvid::Yaml;
29
30    match value {
31        serde_yaml::Value::Null => Ok(Yaml::Null),
32        serde_yaml::Value::Bool(b) => Ok(Yaml::Boolean(*b)),
33        serde_yaml::Value::Number(n) => {
34            if let Some(i) = n.as_i64() {
35                Ok(Yaml::Integer(i))
36            } else if let Some(f) = n.as_f64() {
37                Ok(Yaml::Real(f.to_string()))
38            } else {
39                Ok(Yaml::String(n.to_string()))
40            }
41        }
42        serde_yaml::Value::String(s) => {
43            // For now, just convert normally - yaml-rust will make formatting decisions
44            Ok(Yaml::String(s.clone()))
45        }
46        serde_yaml::Value::Sequence(seq) => {
47            let yaml_seq: Result<Vec<_>> = seq.iter().map(convert_serde_to_yaml_rust).collect();
48            Ok(Yaml::Array(yaml_seq?))
49        }
50        serde_yaml::Value::Mapping(map) => {
51            let mut yaml_map = yaml_rust_davvid::yaml::Hash::new();
52            for (k, v) in map {
53                let yaml_key = convert_serde_to_yaml_rust(k)?;
54                let yaml_value = convert_serde_to_yaml_rust(v)?;
55                yaml_map.insert(yaml_key, yaml_value);
56            }
57            Ok(Yaml::Hash(yaml_map))
58        }
59        serde_yaml::Value::Tagged(tagged) => {
60            // Handle tagged values by converting the inner value
61            convert_serde_to_yaml_rust(&tagged.value)
62        }
63    }
64}
65
66/// Deserialize YAML string to data structure
67pub fn from_yaml<T: for<'de> Deserialize<'de>>(yaml: &str) -> Result<T> {
68    serde_yaml::from_str(yaml).context("Failed to deserialize YAML")
69}
70
71/// Read and parse YAML file
72pub fn read_yaml_file<T: for<'de> Deserialize<'de>, P: AsRef<Path>>(path: P) -> Result<T> {
73    let content = fs::read_to_string(&path)
74        .with_context(|| format!("Failed to read file: {}", path.as_ref().display()))?;
75
76    from_yaml(&content)
77}
78
79/// Write data structure to YAML file
80pub fn write_yaml_file<T: Serialize, P: AsRef<Path>>(data: &T, path: P) -> Result<()> {
81    let yaml_content = to_yaml(data)?;
82
83    fs::write(&path, yaml_content)
84        .with_context(|| format!("Failed to write file: {}", path.as_ref().display()))?;
85
86    Ok(())
87}