1use crate::bridge::satisfier;
2use crate::bridge::satisfier::SolverConfig;
3
4use super::expr::Expr;
5use super::satisfier::SolveError;
6use super::transaction::Transaction;
7use super::types::*;
8use super::Bridge;
9use colored::{Color, Colorize};
10use itertools::Itertools;
11use std::borrow::Cow;
12use std::ffi::{CStr, CString};
13use std::fmt;
14use thiserror::Error;
15
16macro_rules! ensure {
17 ($condition: expr, $error: expr) => {
18 if !$condition {
19 return Err($error);
20 }
21 };
22}
23
24#[derive(Error, Debug, Clone)]
25pub enum SymbolGetError {
26 #[error("unknown symbol type")]
27 UnknownType,
28
29 #[error("cannot be parsed as an integer")]
30 InvalidInt,
31 #[error("cannot be parsed as a hex integer")]
32 InvalidHex,
33}
34
35#[derive(Error, Debug, Clone)]
36pub enum SymbolSetError {
37 #[error("unknown symbol type")]
38 UnknownType,
39 #[error("is const")]
40 IsConst,
41 #[error("cannot be set directly, assign child instead")]
42 IsChoice,
43
44 #[error("cannot be parsed as an integer")]
45 InvalidInt,
46 #[error("cannot be parsed as a hex integer")]
47 InvalidHex,
48 #[error("valid tristates are: n, m, y")]
49 InvalidTristate,
50 #[error("valid booleans are: n, y")]
51 InvalidBoolean,
52
53 #[error("could not automatically solve symbol dependencies")]
54 SatisfyFailed { error: SolveError },
55 #[error("cannot set a higher value than {max}, the symbol has unmet dependencies")]
56 UnmetDependencies {
57 min: Tristate,
58 max: Tristate,
59 deps: Vec<String>,
60 satisfying_configuration: Result<Vec<(String, Tristate)>, SolveError>,
61 },
62 #[error("cannot set a lower value than {min}, the symbol is required by other symbols")]
63 RequiredByOther {
64 min: Tristate,
65 max: Tristate,
66 rev_deps: Vec<String>,
67 },
68 #[error("this symbol cannot be set manually")]
69 CannotSetManually,
70 #[error("cannot set directly, instead satisfy any of the reverse dependencies")]
71 MustBeSelected { rev_deps: Vec<String> },
72 #[error("symbol's minimum visibility is higher than its maximum visibility [min={min}, max={max}]")]
73 InvalidVisibility { min: Tristate, max: Tristate },
74 #[error("module support is not enabled (try setting MODULES=y beforehand)")]
75 ModulesNotEnabled,
76 #[error("value must be in range [{min} ({min:#x}), {max} ({max:#x})]")]
77 OutOfRange { min: u64, max: u64 },
78 #[error("incompatible value type")]
79 InvalidValue,
80 #[error("value was rejected by kernel for an unknown reason")]
81 AssignmentFailed,
82}
83
84#[derive(Clone, Copy, Debug)]
85pub struct Symbol<'a> {
86 pub(super) c_symbol: *mut CSymbol,
87 pub bridge: &'a Bridge,
88}
89
90impl<'a> Symbol<'a> {
91 pub fn name(&self) -> Option<Cow<'_, str>> {
92 unsafe { (*self.c_symbol).name() }
93 }
94
95 pub fn name_owned(&self) -> Option<String> {
96 unsafe { (*self.c_symbol).name() }.map(|s| s.to_string())
97 }
98
99 pub fn recalculate(&self) {
100 (self.bridge.vtable.c_sym_calc_value)(self.c_symbol);
101 }
102
103 pub fn set_value(&mut self, value: SymbolValue) -> Result<(), SymbolSetError> {
104 ensure!(!self.is_const(), SymbolSetError::IsConst);
105 ensure!(!self.is_choice(), SymbolSetError::IsChoice);
106 ensure!(self.prompt_count() > 0, SymbolSetError::CannotSetManually);
107
108 let set_tristate = |value: Tristate| -> Result<(), SymbolSetError> {
109 let min = unsafe { (*self.c_symbol).reverse_dependencies.tri };
110 let max = self.visible();
111 if value > max {
112 let deps = self
113 .visibility_expression_bare()
114 .unwrap()
115 .ok_or(SymbolSetError::MustBeSelected {
116 rev_deps: self
117 .reverse_dependencies()
118 .unwrap()
119 .or_clauses()
120 .into_iter()
121 .map(|x| x.display(self.bridge).to_string())
122 .collect_vec(),
123 })?
124 .and_clauses()
125 .into_iter()
126 .map(|x| x.display(self.bridge).to_string())
127 .collect_vec();
128
129 let satisfying_configuration = self.satisfy(SolverConfig {
130 recursive: true,
131 desired_value: value,
132 ..SolverConfig::default()
133 });
134 return Err(SymbolSetError::UnmetDependencies {
135 min,
136 max,
137 deps,
138 satisfying_configuration,
139 });
140 }
141 if value < min {
142 return Err(SymbolSetError::RequiredByOther {
143 min,
144 max,
145 rev_deps: self
146 .reverse_dependencies()
147 .unwrap()
148 .or_clauses()
149 .into_iter()
150 .map(|x| x.display(self.bridge).to_string())
151 .collect_vec(),
152 });
153 }
154 ensure!(max >= min, SymbolSetError::InvalidVisibility { min, max });
155 ensure!(
156 !(value == Tristate::Mod
157 && self.bridge.symbol("MODULES").unwrap().get_tristate_value() == Tristate::No),
158 SymbolSetError::ModulesNotEnabled
159 );
160 ensure!(
161 (self.bridge.vtable.c_sym_set_tristate_value)(self.c_symbol, value),
162 SymbolSetError::AssignmentFailed
163 );
164 Ok(())
165 };
166
167 match (self.symbol_type(), value) {
168 (SymbolType::Unknown, SymbolValue::Auto(_)) => return Err(SymbolSetError::UnknownType),
169 (SymbolType::Boolean, SymbolValue::Auto(value)) => {
170 ensure!(matches!(value.as_str(), "y" | "n"), SymbolSetError::InvalidBoolean);
172 self.set_value(SymbolValue::Boolean(
173 value.parse::<Tristate>().unwrap() == Tristate::Yes,
174 ))?
175 }
176 (SymbolType::Tristate, SymbolValue::Auto(value)) => {
177 let value = value.parse::<Tristate>().map_err(|_| SymbolSetError::InvalidTristate)?;
179 self.set_value(SymbolValue::Tristate(value))?
180 }
181 (SymbolType::Int, SymbolValue::Auto(value)) => {
182 let value = value.parse::<u64>().map_err(|_| SymbolSetError::InvalidInt)?;
184 self.set_value(SymbolValue::Int(value))?
185 }
186 (SymbolType::Hex, SymbolValue::Auto(value)) => {
187 ensure!(&value[..2] == "0x", SymbolSetError::InvalidHex);
189 let value = u64::from_str_radix(&value[2..], 16).map_err(|_| SymbolSetError::InvalidHex)?;
190 self.set_value(SymbolValue::Hex(value))?
191 }
192 (SymbolType::String, SymbolValue::Auto(value)) => self.set_value(SymbolValue::String(value))?,
193 (SymbolType::Boolean | SymbolType::Tristate, SymbolValue::Boolean(value)) => set_tristate(value.into())?,
194 (SymbolType::Boolean, SymbolValue::Tristate(value)) if value != Tristate::Mod => set_tristate(value)?,
195 (SymbolType::Tristate, SymbolValue::Tristate(value)) => set_tristate(value)?,
196 (SymbolType::Int, SymbolValue::Int(value)) => {
197 let min = (self.bridge.vtable.c_sym_int_get_min)(self.c_symbol);
198 let max = (self.bridge.vtable.c_sym_int_get_max)(self.c_symbol);
199 ensure!(
200 (min == 0 && max == 0) || (value >= min && value <= max),
201 SymbolSetError::OutOfRange { min, max }
202 );
203 let cstr = CString::new(value.to_string()).unwrap();
204 ensure!(
205 (self.bridge.vtable.c_sym_set_string_value)(self.c_symbol, cstr.as_ptr()),
206 SymbolSetError::AssignmentFailed
207 );
208 }
209 (SymbolType::Hex, SymbolValue::Hex(value)) => {
210 let min = (self.bridge.vtable.c_sym_int_get_min)(self.c_symbol);
211 let max = (self.bridge.vtable.c_sym_int_get_max)(self.c_symbol);
212 ensure!(
213 (min == 0 && max == 0) || (value >= min && value <= max),
214 SymbolSetError::OutOfRange { min, max }
215 );
216 let cstr = CString::new(format!("{:#x}", value)).unwrap();
217 ensure!(
218 (self.bridge.vtable.c_sym_set_string_value)(self.c_symbol, cstr.as_ptr()),
219 SymbolSetError::AssignmentFailed
220 );
221 }
222 (SymbolType::String, SymbolValue::String(value)) => {
223 let cstr = CString::new(value).unwrap();
224 ensure!(
225 (self.bridge.vtable.c_sym_set_string_value)(self.c_symbol, cstr.as_ptr()),
226 SymbolSetError::AssignmentFailed
227 );
228 }
229 (SymbolType::Int, SymbolValue::Number(value)) => return self.set_value(SymbolValue::Int(value)),
230 (SymbolType::Hex, SymbolValue::Number(value)) => return self.set_value(SymbolValue::Hex(value)),
231 (_, _) => return Err(SymbolSetError::InvalidValue),
232 };
233
234 self.bridge.recalculate_all_symbols();
235 Ok(())
236 }
237
238 pub fn set_value_tracked(
244 &mut self,
245 value: SymbolValue,
246 file: String,
247 line: u32,
248 traceback: Option<String>,
249 ) -> Result<(), SymbolSetError> {
250 let current_value = self.get_value().unwrap();
251 let ret = self.set_value(value.clone());
252 self.bridge.history.borrow_mut().push(Transaction {
253 symbol: self.name().unwrap().to_string(),
254 file,
255 line,
256 traceback,
257 value,
258 value_before: current_value,
259 value_after: self.get_value().unwrap(),
260 error: ret.clone().err(),
261 });
262 ret
263 }
264
265 pub fn get_value(&self) -> Result<SymbolValue, SymbolGetError> {
266 match self.symbol_type() {
267 SymbolType::Unknown => Err(SymbolGetError::UnknownType),
268 SymbolType::Boolean => Ok(SymbolValue::Boolean(self.get_tristate_value() == Tristate::Yes)),
269 SymbolType::Tristate => Ok(SymbolValue::Tristate(self.get_tristate_value())),
270 SymbolType::Int => Ok(SymbolValue::Int(
271 self.get_string_value()
272 .parse::<u64>()
273 .map_err(|_| SymbolGetError::InvalidInt)?,
274 )),
275 SymbolType::Hex => Ok(SymbolValue::Hex(
276 u64::from_str_radix(&self.get_string_value()[2..], 16).map_err(|_| SymbolGetError::InvalidHex)?,
277 )),
278 SymbolType::String => Ok(SymbolValue::String(self.get_string_value())),
279 }
280 }
281
282 pub fn symbol_type(&self) -> SymbolType {
283 unsafe { &*self.c_symbol }.symbol_type()
284 }
285
286 pub fn is_const(&self) -> bool {
287 unsafe { &*self.c_symbol }.is_const()
288 }
289
290 pub fn is_choice(&self) -> bool {
291 unsafe { &*self.c_symbol }.is_choice()
292 }
293
294 pub fn prompt_count(&self) -> usize {
295 (self.bridge.vtable.c_sym_prompt_count)(self.c_symbol)
296 }
297
298 pub fn visible(&self) -> Tristate {
299 self.recalculate();
300 unsafe { &*self.c_symbol }.visible
301 }
302
303 pub fn choices(&self) -> anyhow::Result<Vec<*mut CSymbol>> {
304 anyhow::ensure!(
305 self.is_choice(),
306 "The symbol must be a choice symbol to call .choices()"
307 );
308 let count = (self.bridge.vtable.c_get_choice_symbols)(self.c_symbol, std::ptr::null_mut() as *mut *mut CSymbol);
309 let mut symbols = Vec::with_capacity(count);
310 (self.bridge.vtable.c_get_choice_symbols)(self.c_symbol, symbols.as_mut_ptr() as *mut *mut CSymbol);
311 unsafe { symbols.set_len(count) };
312 Ok(symbols)
313 }
314
315 pub fn get_tristate_value(&self) -> Tristate {
316 unsafe { &*self.c_symbol }.get_tristate_value()
317 }
318
319 pub fn visibility_expression_bare(&self) -> Result<Option<Expr>, ExprConvertError> {
320 unsafe { &mut *(self.bridge.vtable.c_sym_direct_deps_with_prompts)(self.c_symbol) }.expr()
321 }
322
323 pub fn visibility_expression(&self) -> Result<Expr, ExprConvertError> {
324 Ok(self.visibility_expression_bare()?.unwrap_or(Expr::Const(true)))
325 }
326
327 pub fn reverse_dependencies_bare(&self) -> Result<Option<Expr>, ExprConvertError> {
328 unsafe { &(*self.c_symbol).reverse_dependencies }.expr()
329 }
330
331 pub fn reverse_dependencies(&self) -> Result<Expr, ExprConvertError> {
332 Ok(unsafe { &(*self.c_symbol).reverse_dependencies }
333 .expr()?
334 .unwrap_or(Expr::Const(false)))
335 }
336
337 pub fn get_string_value(&self) -> String {
338 return unsafe { CStr::from_ptr((self.bridge.vtable.c_sym_get_string_value)(self.c_symbol)) }
339 .to_str()
340 .unwrap()
341 .to_owned();
342 }
343
344 pub fn satisfy(&self, config: SolverConfig) -> Result<Vec<(String, Tristate)>, SolveError> {
345 satisfier::satisfy(self.bridge, self.name_owned().ok_or(SolveError::InvalidSymbol)?, config)
346 }
347
348 pub fn satisfy_track_error(
349 &mut self,
350 value: SymbolValue,
351 file: String,
352 line: u32,
353 traceback: Option<String>,
354 config: SolverConfig,
355 ) -> Result<Vec<(String, Tristate)>, SolveError> {
356 let ret = self.satisfy(config);
357 if ret.is_ok() {
358 return ret;
359 }
360
361 let current_value = self.get_value().unwrap();
362 self.bridge.history.borrow_mut().push(Transaction {
363 symbol: self.name().unwrap().to_string(),
364 file,
365 line,
366 traceback,
367 value,
368 value_before: current_value.clone(),
369 value_after: current_value,
370 error: Some(SymbolSetError::SatisfyFailed {
371 error: ret.clone().unwrap_err(),
372 }),
373 });
374 ret
375 }
376}
377
378impl<'a> fmt::Display for Symbol<'a> {
379 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380 if let Some(name) = self.name() {
381 let (name_color, value_indicator) = match self.get_value() {
382 Ok(SymbolValue::Boolean(value)) => (
383 match value {
384 false => Color::Red,
385 true => Color::Green,
386 },
387 format!("={}", Tristate::from(value)),
388 ),
389 Ok(SymbolValue::Tristate(value)) => (value.color(), format!("={}", value)),
390 Ok(SymbolValue::Int(value)) => (Color::White, format!("={}", value)),
391 Ok(SymbolValue::Hex(value)) => (Color::White, format!("={:x}", value)),
392 Ok(SymbolValue::String(value)) => (Color::White, format!("=\"{}\"", value)),
393 _ => (Color::BrightRed, "=?".to_string()),
394 };
395 write!(f, "{}{}", name.color(name_color), value_indicator.dimmed())
396 } else if self.is_choice() {
397 let choices = self.choices().unwrap().into_iter().map(|s| self.bridge.wrap_symbol(s));
398 write!(f, "<choice>[{}]", choices.format(", "))
399 } else {
400 write!(f, "<??>")
401 }
402 }
403}