Skip to main content

typhoon/settings/
override_map.rs

1//! Override map types for type-safe settings storage.
2
3#[cfg(test)]
4#[path = "../../tests/settings/override_map.rs"]
5mod tests;
6
7use std::collections::HashMap;
8use std::ops::Add;
9
10/// A typed setting key that carries its value type at compile time.
11/// This ensures type-safe access to settings - you can only get/set
12/// values of the correct type for each key.
13pub struct Key<T> {
14    pub name: &'static str,
15    pub default: T,
16}
17
18impl<T> Key<T> {
19    pub const fn new(name: &'static str, default: T) -> Self {
20        Self {
21            name,
22            default,
23        }
24    }
25}
26
27/// Trait for types that can be stored in Settings.
28/// Provides conversion to/from the internal SettingValue representation.
29pub trait SettingType: Copy {
30    fn from_value(v: SettingValue) -> Self;
31    fn to_value(self) -> SettingValue;
32    fn try_parse(s: &str) -> Option<Self>;
33}
34
35impl SettingType for i64 {
36    #[inline]
37    fn from_value(v: SettingValue) -> Self {
38        match v {
39            SettingValue::Signed(x) => x,
40            _ => unreachable!("expected signed setting"),
41        }
42    }
43
44    #[inline]
45    fn to_value(self) -> SettingValue {
46        SettingValue::Signed(self)
47    }
48
49    #[inline]
50    fn try_parse(s: &str) -> Option<Self> {
51        s.parse().ok()
52    }
53}
54
55impl SettingType for u64 {
56    #[inline]
57    fn from_value(v: SettingValue) -> Self {
58        match v {
59            SettingValue::Unsigned(x) => x,
60            _ => unreachable!("expected unsigned setting"),
61        }
62    }
63
64    #[inline]
65    fn to_value(self) -> SettingValue {
66        SettingValue::Unsigned(self)
67    }
68
69    #[inline]
70    fn try_parse(s: &str) -> Option<Self> {
71        s.parse().ok()
72    }
73}
74
75impl SettingType for f64 {
76    #[inline]
77    fn from_value(v: SettingValue) -> Self {
78        match v {
79            SettingValue::Float(x) => x,
80            _ => unreachable!("expected float setting"),
81        }
82    }
83
84    #[inline]
85    fn to_value(self) -> SettingValue {
86        SettingValue::Float(self)
87    }
88
89    #[inline]
90    fn try_parse(s: &str) -> Option<Self> {
91        s.parse().ok()
92    }
93}
94
95/// Internal representation of a setting value.
96#[derive(Copy, Clone, Debug)]
97pub enum SettingValue {
98    Signed(i64),
99    Unsigned(u64),
100    Float(f64),
101}
102
103impl Add for SettingValue {
104    type Output = Self;
105
106    #[inline]
107    fn add(self, rhs: Self) -> Self::Output {
108        match (self, rhs) {
109            (SettingValue::Signed(a), SettingValue::Signed(b)) => SettingValue::Signed(a + b),
110            (SettingValue::Unsigned(a), SettingValue::Unsigned(b)) => SettingValue::Unsigned(a + b),
111            (SettingValue::Float(a), SettingValue::Float(b)) => SettingValue::Float(a + b),
112            (SettingValue::Signed(a), SettingValue::Unsigned(b)) => SettingValue::Float(a as f64 + b as f64),
113            (SettingValue::Unsigned(a), SettingValue::Signed(b)) => SettingValue::Float(a as f64 + b as f64),
114            (SettingValue::Signed(a), SettingValue::Float(b)) | (SettingValue::Float(b), SettingValue::Signed(a)) => SettingValue::Float(a as f64 + b),
115            (SettingValue::Unsigned(a), SettingValue::Float(b)) | (SettingValue::Float(b), SettingValue::Unsigned(a)) => SettingValue::Float(a as f64 + b),
116        }
117    }
118}
119
120/// Map of setting name to override value.
121pub type OverrideMap = HashMap<&'static str, SettingValue>;