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_contract(src: &str) -> Result<Contract, LoadError> {
63 let de = serde_yaml::Deserializer::from_str(src);
64 Contract::deserialize(de).map_err(|e| LoadError {
65 path: "contract".to_string(),
66 message: format!("{e}"),
67 })
68}
69
70pub fn load_contracts(srcs: &[(&str, &str)]) -> Result<Vec<Contract>, LoadError> {
71 let mut out = Vec::new();
72 for (_name, src) in srcs {
73 out.push(load_contract(src)?);
74 }
75 Ok(out)
76}