Skip to main content

agent_sim/config/
recipe.rs

1use crate::config::error::ConfigError;
2use serde::Deserialize;
3use std::collections::BTreeMap;
4
5#[derive(Debug, Clone, Deserialize, Default)]
6pub struct DefaultsConfig {
7    pub json: Option<bool>,
8    pub speed: Option<f64>,
9    pub load: Option<LoadDefaults>,
10}
11
12#[derive(Debug, Clone, Deserialize, Default)]
13pub struct LoadDefaults {
14    pub lib: Option<String>,
15    #[serde(default)]
16    pub flash: Vec<FlashBlockDef>,
17}
18
19#[derive(Debug, Clone, Deserialize, Default)]
20pub struct FileConfig {
21    pub defaults: Option<DefaultsConfig>,
22    #[serde(default)]
23    pub device: BTreeMap<String, DeviceDef>,
24    #[serde(default)]
25    pub recipe: BTreeMap<String, RecipeDef>,
26    #[serde(default)]
27    pub env: BTreeMap<String, EnvDef>,
28}
29
30#[derive(Debug, Clone, Deserialize)]
31pub struct DeviceDef {
32    pub lib: String,
33    #[serde(default)]
34    pub flash: Vec<FlashBlockDef>,
35}
36
37#[derive(Debug, Clone, Deserialize)]
38pub struct RecipeDef {
39    pub description: Option<String>,
40    #[serde(default)]
41    pub env: Vec<String>,
42    #[serde(default)]
43    pub instances: Vec<String>,
44    pub instance: Option<String>,
45    pub steps: Vec<RecipeStep>,
46}
47
48#[derive(Debug, Clone, Deserialize)]
49#[serde(untagged)]
50pub enum PrintSpec {
51    All(String),
52    Signals(Vec<String>),
53}
54
55#[derive(Debug, Clone, Deserialize)]
56pub struct ForSpec {
57    pub signal: String,
58    pub from: f64,
59    pub to: f64,
60    pub by: f64,
61    pub each: Vec<RecipeStep>,
62}
63
64#[derive(Debug, Clone, Deserialize)]
65#[serde(untagged)]
66pub enum StepSpec {
67    Duration(String),
68    Detailed {
69        duration: String,
70        instance: Option<String>,
71    },
72}
73
74#[derive(Debug, Clone, Deserialize)]
75pub struct AssertSpec {
76    pub signal: String,
77    pub instance: Option<String>,
78    pub eq: Option<toml::Value>,
79    pub gt: Option<f64>,
80    pub lt: Option<f64>,
81    pub gte: Option<f64>,
82    pub lte: Option<f64>,
83    pub approx: Option<f64>,
84    pub tolerance: Option<f64>,
85}
86
87#[derive(Debug, Clone, Deserialize)]
88pub struct EnvDef {
89    #[serde(default)]
90    pub instances: Vec<EnvInstance>,
91    #[serde(default)]
92    pub can: BTreeMap<String, EnvCanBus>,
93    #[serde(default)]
94    pub shared: BTreeMap<String, EnvSharedChannel>,
95}
96
97#[derive(Debug, Clone, Deserialize)]
98#[serde(deny_unknown_fields)]
99pub struct EnvInstance {
100    pub name: String,
101    pub lib: Option<String>,
102    pub device: Option<String>,
103}
104
105#[derive(Debug, Clone, Deserialize)]
106#[serde(deny_unknown_fields)]
107pub struct FlashFileBlockDef {
108    pub file: String,
109    pub format: Option<String>,
110    pub base: Option<String>,
111}
112
113#[derive(Debug, Clone, Deserialize)]
114#[serde(untagged)]
115pub enum FlashBlockDef {
116    File(FlashFileBlockDef),
117    InlineU32 { u32: u32, addr: String },
118    InlineI32 { i32: i32, addr: String },
119    InlineF32 { f32: f32, addr: String },
120    InlineBool { bool: bool, addr: String },
121}
122
123#[derive(Debug, Clone, Deserialize)]
124pub struct EnvCanBus {
125    #[serde(default)]
126    pub members: Vec<String>,
127    pub vcan: String,
128    pub dbc: Option<String>,
129}
130
131#[derive(Debug, Clone, Deserialize)]
132pub struct EnvSharedChannel {
133    #[serde(default)]
134    pub members: Vec<String>,
135    pub writer: String,
136}
137
138#[derive(Debug, Clone, Deserialize)]
139#[serde(deny_unknown_fields)]
140pub struct ResetSpec {}
141
142#[derive(Debug, Clone, Deserialize)]
143#[serde(untagged)]
144pub enum RecipeStep {
145    Set {
146        set: BTreeMap<String, toml::Value>,
147        instance: Option<String>,
148    },
149    Step {
150        step: StepSpec,
151        instance: Option<String>,
152    },
153    Print {
154        print: PrintSpec,
155        instance: Option<String>,
156    },
157    Speed {
158        speed: f64,
159        instance: Option<String>,
160    },
161    Reset {
162        reset: ResetSpec,
163        instance: Option<String>,
164    },
165    Sleep {
166        sleep: u64,
167    },
168    For {
169        r#for: ForSpec,
170        instance: Option<String>,
171    },
172    Assert {
173        assert: AssertSpec,
174    },
175}
176
177pub fn parse_config(content: &str) -> Result<FileConfig, ConfigError> {
178    toml::from_str(content).map_err(|e| ConfigError::Parse(e.to_string()))
179}
180
181pub fn toml_value_to_cli_string(value: &toml::Value) -> Result<String, ConfigError> {
182    let rendered = match value {
183        toml::Value::String(v) => v.clone(),
184        toml::Value::Integer(v) => v.to_string(),
185        toml::Value::Float(v) => v.to_string(),
186        toml::Value::Boolean(v) => v.to_string(),
187        _ => {
188            return Err(ConfigError::InvalidRecipeStep(
189                "unsupported set value type".to_string(),
190            ));
191        }
192    };
193    Ok(rendered)
194}