1use crate::model::RawMachine;
5use crate::validate::Contract;
6use serde::Deserialize;
7
8#[derive(Debug, Clone, Default)]
10pub struct LoadError {
11 pub path: String,
12 pub message: String,
13}
14
15impl std::fmt::Display for LoadError {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 if self.path.is_empty() {
18 write!(f, "{}", self.message)
19 } else {
20 write!(f, "{}: {}", self.path, self.message)
21 }
22 }
23}
24
25pub fn load_machines(src: &str) -> Result<Vec<RawMachine>, Vec<LoadError>> {
27 let de = serde_yaml::Deserializer::from_str(src);
28 let mut out = Vec::new();
29 let mut errs = Vec::new();
30 let mut doc_index = 0;
31 for doc in de {
32 match RawMachine::deserialize(doc) {
33 Ok(m) => out.push(m),
34 Err(e) => {
35 let pos = e.location().map(|l| l.line()).unwrap_or(0);
36 let path = if out.is_empty() {
37 format!("doc[{}]", doc_index)
38 } else {
39 format!("doc[{}]", doc_index)
40 };
41 errs.push(LoadError {
42 path: format!("{path}:line {pos}"),
43 message: format!("{e}"),
44 });
45 }
46 }
47 doc_index += 1;
48 }
49 if !errs.is_empty() {
50 return Err(errs);
51 }
52 if out.is_empty() {
53 return Err(vec![LoadError {
54 path: "machine".to_string(),
55 message: "no machine definitions found".to_string(),
56 }]);
57 }
58 Ok(out)
59}
60
61pub fn load_machine_from_value(value: serde_json::Value) -> Result<RawMachine, LoadError> {
68 serde_json::from_value(value).map_err(|e| LoadError {
69 path: "machine".to_string(),
70 message: format!("{e}"),
71 })
72}
73
74pub fn load_machines_from_values(
79 values: Vec<serde_json::Value>,
80) -> Result<Vec<RawMachine>, Vec<LoadError>> {
81 let mut out = Vec::new();
82 let mut errs = Vec::new();
83 for (i, value) in values.into_iter().enumerate() {
84 match serde_json::from_value::<RawMachine>(value) {
85 Ok(m) => out.push(m),
86 Err(e) => errs.push(LoadError {
87 path: format!("doc[{i}]"),
88 message: format!("{e}"),
89 }),
90 }
91 }
92 if !errs.is_empty() {
93 return Err(errs);
94 }
95 if out.is_empty() {
96 return Err(vec![LoadError {
97 path: "machine".to_string(),
98 message: "no machine definitions found".to_string(),
99 }]);
100 }
101 Ok(out)
102}
103
104pub fn load_contract(src: &str) -> Result<Contract, LoadError> {
106 let de = serde_yaml::Deserializer::from_str(src);
107 Contract::deserialize(de).map_err(|e| LoadError {
108 path: "contract".to_string(),
109 message: format!("{e}"),
110 })
111}
112
113pub fn load_contracts(srcs: &[(&str, &str)]) -> Result<Vec<Contract>, LoadError> {
114 let mut out = Vec::new();
115 for (_name, src) in srcs {
116 out.push(load_contract(src)?);
117 }
118 Ok(out)
119}