settings_schema/
lib.rs

1use std::{
2    collections::{HashMap, HashSet},
3    fmt::{self, Display, Formatter},
4    ops::{Deref, RangeInclusive},
5    time::Duration,
6};
7
8pub use settings_schema_derive::SettingsSchema;
9
10// For the derive macro
11pub use serde::{Deserialize, Serialize};
12pub use serde_json::to_value as to_json_value;
13
14#[derive(Serialize, Deserialize, Clone, Copy, Debug)]
15pub struct Percentage(f32);
16
17impl Percentage {
18    pub fn new(value: u8) -> Self {
19        Self(value as f32 / 100.0)
20    }
21
22    pub fn new_normalized(value: f32) -> Self {
23        Self(value)
24    }
25}
26
27impl From<u8> for Percentage {
28    fn from(value: u8) -> Self {
29        Self(value as f32)
30    }
31}
32
33impl From<f32> for Percentage {
34    fn from(value: f32) -> Self {
35        Self(value)
36    }
37}
38
39impl Deref for Percentage {
40    type Target = f32;
41
42    fn deref(&self) -> &f32 {
43        &self.0
44    }
45}
46
47impl Display for Percentage {
48    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
49        write!(f, "{}%", (self.0 * 100.0) as u8)
50    }
51}
52
53/// The `Switch` is used to represent something that makes sense to specify its state only when it's enabled.
54/// This should be used differently than `Option(al)`, that represent a value that can be omitted.
55#[derive(Serialize, Deserialize, Clone, Copy, Debug)]
56pub enum Switch<T> {
57    Enabled(T),
58    Disabled,
59}
60
61impl<T> Switch<T> {
62    pub fn as_option(&self) -> Option<&T> {
63        match self {
64            Self::Enabled(t) => Some(t),
65            Self::Disabled => None,
66        }
67    }
68
69    pub fn into_option(self) -> Option<T> {
70        match self {
71            Self::Enabled(t) => Some(t),
72            Self::Disabled => None,
73        }
74    }
75}
76
77/// Type used to specify the default value for type `Option`.  
78/// It allows specifying the set state and its content when it is set.
79#[derive(Serialize, Deserialize, Clone, Debug)]
80pub struct OptionalDefault<C> {
81    pub set: bool,
82    pub content: C,
83}
84
85/// Type used to specify the default value for type `Switch`.  
86/// It allows setting the enabled state and its content when set to enabled.
87#[derive(Serialize, Deserialize, Clone, Debug)]
88pub struct SwitchDefault<C> {
89    pub enabled: bool,
90    pub content: C,
91}
92
93/// Type used to specify the default value for type `Vec`.  
94/// It allows setting the default for the vector (all elements) and the default value for new elements.
95#[derive(Serialize, Deserialize, Clone, Debug)]
96pub struct VectorDefault<T> {
97    pub element: T,
98    pub content: Vec<T>,
99}
100
101/// Type used to specify the default value for type `Vec<(String, X)>`.  
102/// It allows setting the default for the dictionary (all entries) and the default key and value for new entries.
103#[derive(Serialize, Deserialize, Clone, Debug)]
104pub struct DictionaryDefault<T> {
105    pub key: String,
106    pub value: T,
107    pub content: Vec<(String, T)>,
108}
109
110/// GUI type associated to a numeric node.
111#[derive(Serialize, Deserialize, Clone, Debug)]
112pub enum NumericGuiType {
113    Slider {
114        range: RangeInclusive<f64>,
115        step: Option<f64>,
116        logarithmic: bool,
117    },
118    TextBox,
119}
120
121#[derive(Serialize, Deserialize, Clone, Copy, Debug)]
122pub enum NumberType {
123    UnsignedInteger,
124    SignedInteger,
125    Float,
126}
127
128/// GUI type associated to the choice node.
129#[derive(Serialize, Deserialize, Clone, Copy, Debug)]
130pub enum ChoiceControlType {
131    Dropdown,
132    ButtonGroup,
133}
134
135#[derive(Serialize, Deserialize, Clone, Debug)]
136pub struct SchemaEntry<T> {
137    pub name: String,
138    pub strings: HashMap<String, String>,
139    pub flags: HashSet<String>,
140    pub content: T,
141}
142
143/// Schema base type returned by `<YourStructOrEnum>::schema()`, generated by the macro
144/// `#[derive(SettingsSchema)]`. It can be used as is (for Rust based GUIs) or it can be serialized
145/// to JSON for creating GUIs in other languages.
146#[non_exhaustive]
147#[derive(Serialize, Deserialize, Clone, Debug)]
148pub enum SchemaNode {
149    Section(Vec<SchemaEntry<SchemaNode>>),
150    Choice {
151        default: String,
152        variants: Vec<SchemaEntry<Option<SchemaNode>>>,
153        gui: Option<ChoiceControlType>,
154    },
155    Optional {
156        default_set: bool,
157        content: Box<SchemaNode>,
158    },
159    Switch {
160        default_enabled: bool,
161        content: Box<SchemaNode>,
162    },
163    Boolean {
164        default: bool,
165    },
166    Number {
167        default: f64,
168        ty: NumberType,
169        gui: NumericGuiType,
170        suffix: Option<String>,
171    },
172    Range {
173        default: [f64; 2],
174        ty: NumberType,
175        gui: NumericGuiType,
176        suffix: Option<String>,
177    },
178    Percentage {
179        default_normalized: f32,
180        range_normalized: Option<RangeInclusive<f32>>,
181    },
182    Duration {
183        default: Duration,
184        range: RangeInclusive<Duration>,
185        logarithmic: bool,
186    },
187    Text {
188        default: String,
189    },
190    Array(Vec<SchemaNode>),
191    Vector {
192        default_element: Box<SchemaNode>,
193        default: serde_json::Value,
194    },
195    Dictionary {
196        default_key: String,
197        default_value: Box<SchemaNode>,
198        default: serde_json::Value,
199    },
200}