Skip to main content

formualizer_eval/
locale.rs

1/// Locale contract for the engine.
2///
3/// Milestone 0 intentionally uses an invariant locale:
4///
5/// - Numeric parsing is ASCII/invariant only (`.` decimal separator; no thousands separators).
6/// - Strings are case-folded with ASCII-only rules (`to_ascii_lowercase`).
7///
8/// This means locale-dependent inputs like `"1.234,56"` are *not* interpreted as numbers.
9/// Callers should surface `#VALUE!` for locale-dependent numeric coercions (e.g. `VALUE()`)
10/// rather than silently producing a wrong number.
11#[derive(Copy, Clone, Debug, Eq, PartialEq)]
12pub struct Locale;
13
14impl Locale {
15    pub const fn invariant() -> Self {
16        Locale
17    }
18
19    /// Parse a number using invariant rules (ASCII, dot decimal separator).
20    pub fn parse_number_invariant(&self, s: &str) -> Option<f64> {
21        s.trim().parse::<f64>().ok()
22    }
23
24    /// Case folding for comparisons; invariant = ASCII lower.
25    pub fn fold_case_invariant(&self, s: &str) -> String {
26        s.to_ascii_lowercase()
27    }
28}