1use joule_common::Span;
7
8#[derive(Debug, Clone, PartialEq)]
26pub struct EnergyBudget {
27 pub max_joules: Option<f64>,
29 pub max_watts: Option<f64>,
31 pub max_temp_delta: Option<f64>,
33 pub span: Span,
35}
36
37impl EnergyBudget {
38 pub const fn new(span: Span) -> Self {
40 Self {
41 max_joules: None,
42 max_watts: None,
43 max_temp_delta: None,
44 span,
45 }
46 }
47
48 pub const fn with_max_joules(joules: f64, span: Span) -> Self {
50 Self {
51 max_joules: Some(joules),
52 max_watts: None,
53 max_temp_delta: None,
54 span,
55 }
56 }
57
58 pub const fn has_constraints(&self) -> bool {
60 self.max_joules.is_some() || self.max_watts.is_some() || self.max_temp_delta.is_some()
61 }
62
63 pub const fn set_max_joules(&mut self, joules: f64) {
65 self.max_joules = Some(joules);
66 }
67
68 pub const fn set_max_watts(&mut self, watts: f64) {
70 self.max_watts = Some(watts);
71 }
72
73 pub const fn set_max_temp_delta(&mut self, delta: f64) {
75 self.max_temp_delta = Some(delta);
76 }
77}
78
79impl Default for EnergyBudget {
80 fn default() -> Self {
81 Self {
82 max_joules: None,
83 max_watts: None,
84 max_temp_delta: None,
85 span: Span::dummy(),
86 }
87 }
88}
89
90#[derive(Debug, Clone, PartialEq)]
94pub struct Attribute {
95 pub name: crate::Path,
97 pub args: AttributeArgs,
99 pub span: Span,
101}
102
103#[derive(Debug, Clone, PartialEq, Default)]
105pub enum AttributeArgs {
106 #[default]
108 Empty,
109 Parenthesized(Vec<AttributeArg>),
111}
112
113#[derive(Debug, Clone, PartialEq)]
115pub struct AttributeArg {
116 pub key: crate::Ident,
118 pub value: AttributeValue,
120 pub span: Span,
122}
123
124#[derive(Debug, Clone, PartialEq)]
126pub enum AttributeValue {
127 Float(f64),
129 Int(u64),
131 String(String),
133 Bool(bool),
135 Ident(crate::Ident),
137}
138
139impl AttributeValue {
140 pub const fn as_f64(&self) -> Option<f64> {
142 match self {
143 Self::Float(f) => Some(*f),
144 Self::Int(i) => Some(*i as f64),
145 _ => None,
146 }
147 }
148
149 pub const fn as_u64(&self) -> Option<u64> {
151 match self {
152 Self::Int(i) => Some(*i),
153 _ => None,
154 }
155 }
156
157 pub const fn as_bool(&self) -> Option<bool> {
159 match self {
160 Self::Bool(b) => Some(*b),
161 _ => None,
162 }
163 }
164
165 pub fn as_string(&self) -> Option<&str> {
167 match self {
168 Self::String(s) => Some(s),
169 _ => None,
170 }
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177 use joule_common::Symbol;
178
179 fn make_ident(name: &str) -> crate::Ident {
180 crate::Ident::new(Symbol::intern(name), Span::dummy())
181 }
182
183 #[test]
184 fn test_energy_budget_default() {
185 let budget = EnergyBudget::default();
186 assert!(budget.max_joules.is_none());
187 assert!(budget.max_watts.is_none());
188 assert!(budget.max_temp_delta.is_none());
189 assert!(!budget.has_constraints());
190 }
191
192 #[test]
193 fn test_energy_budget_with_constraints() {
194 let budget = EnergyBudget::with_max_joules(0.5, Span::dummy());
195 assert_eq!(budget.max_joules, Some(0.5));
196 assert!(budget.has_constraints());
197 }
198
199 #[test]
200 fn test_energy_budget_setters() {
201 let mut budget = EnergyBudget::new(Span::dummy());
202 budget.set_max_joules(1.0);
203 budget.set_max_watts(50.0);
204 budget.set_max_temp_delta(10.0);
205
206 assert_eq!(budget.max_joules, Some(1.0));
207 assert_eq!(budget.max_watts, Some(50.0));
208 assert_eq!(budget.max_temp_delta, Some(10.0));
209 }
210
211 #[test]
212 fn test_attribute_value_conversions() {
213 let float_val = AttributeValue::Float(0.5);
214 assert_eq!(float_val.as_f64(), Some(0.5));
215
216 let int_val = AttributeValue::Int(100);
217 assert_eq!(int_val.as_u64(), Some(100));
218 assert_eq!(int_val.as_f64(), Some(100.0)); let bool_val = AttributeValue::Bool(true);
221 assert_eq!(bool_val.as_bool(), Some(true));
222
223 let string_val = AttributeValue::String("test".to_string());
224 assert_eq!(string_val.as_string(), Some("test"));
225
226 let ident_val = AttributeValue::Ident(make_ident("SomeValue"));
227 assert!(ident_val.as_f64().is_none());
228 }
229
230 #[test]
231 fn test_attribute_args_default() {
232 let args = AttributeArgs::default();
233 assert!(matches!(args, AttributeArgs::Empty));
234 }
235}