autokernel/bridge/
symbol.rs

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                // Allowed "y" "n"
171                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                // Allowed "y" "m" "n"
178                let value = value.parse::<Tristate>().map_err(|_| SymbolSetError::InvalidTristate)?;
179                self.set_value(SymbolValue::Tristate(value))?
180            }
181            (SymbolType::Int, SymbolValue::Auto(value)) => {
182                // Allowed: Any u64 integer
183                let value = value.parse::<u64>().map_err(|_| SymbolSetError::InvalidInt)?;
184                self.set_value(SymbolValue::Int(value))?
185            }
186            (SymbolType::Hex, SymbolValue::Auto(value)) => {
187                // Allowed: Any u64 integer
188                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    /// Sets the symbol parameters, tracking the transaction.
239    /// parameters:
240    /// - value: The symbol value
241    /// - from: The location (file) it was set from
242    /// - traceback: optional
243    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}