1use anyhow::{Context, Result};
4use serde::{Deserialize, Serialize};
5use std::fs;
6use std::path::Path;
7use yaml_rust_davvid::YamlEmitter;
8
9pub fn to_yaml<T: Serialize>(data: &T) -> Result<String> {
11 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 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
26fn 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 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 convert_serde_to_yaml_rust(&tagged.value)
62 }
63 }
64}
65
66pub 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
71pub 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
79pub 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}