stylo_static_prefs/
lib.rs1use std::collections::HashMap;
6use std::sync::{LazyLock, RwLock};
7
8#[macro_export]
11macro_rules! default_value {
12 ("dom.select.customizable_select.enabled") => {
13 false
14 };
15 ("dom.viewTransitions.cross-document.enabled") => {
16 false
17 };
18 ("layout.columns.enabled") => {
19 false
20 };
21 ("layout.container-queries.enabled") => {
22 false
23 };
24 ("layout.css.anchor-positioning.enabled") => {
25 false
26 };
27 ("layout.css.appearance-base.enabled") => {
28 false
29 };
30 ("layout.css.at-scope.enabled") => {
31 false
32 };
33 ("layout.css.attr.enabled") => {
34 false
35 };
36 ("layout.css.basic-shape-shape.enabled") => {
37 false
38 };
39 ("layout.css.color-mix-multi-color.enabled") => {
40 true
41 };
42 ("layout.css.content.alt-text.enabled") => {
43 false
44 };
45 ("layout.css.contrast-color.enabled") => {
46 true
47 };
48 ("layout.css.custom-media.enabled") => {
49 false
50 };
51 ("layout.css.fit-content-function.enabled") => {
52 true
53 };
54 ("layout.css.font-palette.enabled") => {
55 false
56 };
57 ("layout.css.font-tech.enabled") => {
58 false
59 };
60 ("layout.css.font-variations.enabled") => {
61 true
62 };
63 ("layout.css.gradient-color-interpolation-method.enabled") => {
64 true
65 };
66 ("layout.css.light-dark.images.enabled") => {
67 false
68 };
69 ("layout.css.margin-rules.enabled") => {
70 false
71 };
72 ("layout.css.marker.restricted") => {
73 true
74 };
75 ("layout.css.motion-path-url.enabled") => {
76 false
77 };
78 ("layout.css.outline-offset.snapping") => {
79 1
80 };
81 ("layout.css.properties-and-values.enabled") => {
82 true
83 };
84 ("layout.css.relative-color-syntax.enabled") => {
85 true
86 };
87 ("layout.css.revert-rule.enabled") => {
88 true
89 };
90 ("layout.css.scroll-driven-animations.enabled") => {
91 false
92 };
93 ("layout.css.scroll-state.enabled") => {
94 false
95 };
96 ("layout.css.starting-style-at-rules.enabled") => {
97 false
98 };
99 ("layout.css.stretch-size-keyword.enabled") => {
100 true
101 };
102 ("layout.css.style-queries.enabled") => {
103 false
104 };
105 ("layout.css.stylo-local-work-queue.in-main-thread") => {
106 32
107 };
108 ("layout.css.stylo-local-work-queue.in-worker") => {
109 0
110 };
111 ("layout.css.stylo-work-unit-size") => {
112 16
113 };
114 ("layout.css.system-ui.enabled") => {
115 true
116 };
117 ("layout.css.webkit-fill-available.all-size-properties.enabled") => {
118 true
119 };
120 ("layout.css.webkit-fill-available.enabled") => {
121 true
122 };
123 ("layout.grid.enabled") => {
124 false
125 };
126 ("layout.threads") => {
127 -1
130 };
131 ("layout.unimplemented") => {
132 false
133 };
134 ("layout.variable_fonts.enabled") => {
135 false
136 };
137 ("layout.writing-mode.enabled") => {
138 false
139 };
140}
141
142#[macro_export]
145macro_rules! pref {
146 ($string:tt) => {
147 $crate::Preference::get($string, $crate::default_value!($string))
148 };
149}
150
151#[macro_export]
153macro_rules! set_pref {
154 ($string:tt, $($value:expr)+) => {
155 let value = $($value)+;
156 let _ = $crate::default_value!($string) == value;
158 $crate::Preference::set($string, value)
159 };
160}
161
162static PREFS: LazyLock<Preferences> = LazyLock::new(Preferences::default);
163
164#[derive(Debug, Default)]
165struct Preferences {
166 bool_prefs: RwLock<HashMap<String, bool>>,
167 i32_prefs: RwLock<HashMap<String, i32>>,
168}
169
170impl Preferences {
171 pub fn get_bool(&self, key: &str, default: bool) -> bool {
172 let prefs = self.bool_prefs.read().expect("RwLock is poisoned");
173 *prefs.get(key).unwrap_or(&default)
174 }
175
176 pub fn get_i32(&self, key: &str, default: i32) -> i32 {
177 let prefs = self.i32_prefs.read().expect("RwLock is poisoned");
178 *prefs.get(key).unwrap_or(&default)
179 }
180
181 pub fn set_bool(&self, key: &str, value: bool) {
182 let mut prefs = self.bool_prefs.write().expect("RwLock is poisoned");
183
184 if let Some(pref) = prefs.get_mut(key) {
186 *pref = value;
187 } else {
188 prefs.insert(key.to_owned(), value);
189 }
190 }
191
192 pub fn set_i32(&self, key: &str, value: i32) {
193 let mut prefs = self.i32_prefs.write().expect("RwLock is poisoned");
194
195 if let Some(pref) = prefs.get_mut(key) {
197 *pref = value;
198 } else {
199 prefs.insert(key.to_owned(), value);
200 }
201 }
202}
203
204pub trait Preference: Sized {
205 fn get(key: &str, default: Self) -> Self;
209
210 fn set(key: &str, value: Self);
214}
215
216impl Preference for bool {
217 fn get(key: &str, default: Self) -> Self {
218 PREFS.get_bool(key, default)
219 }
220 fn set(key: &str, value: Self) {
221 PREFS.set_bool(key, value)
222 }
223}
224
225impl Preference for i32 {
226 fn get(key: &str, default: Self) -> Self {
227 PREFS.get_i32(key, default)
228 }
229 fn set(key: &str, value: Self) {
230 PREFS.set_i32(key, value)
231 }
232}
233
234#[test]
235fn test() {
236 let prefs = Preferences::default();
237
238 assert_eq!(prefs.get_bool("foo", false), false);
240 assert_eq!(prefs.get_bool("foo", true), true);
241 assert_eq!(prefs.get_i32("bar", 0), 0);
242 assert_eq!(prefs.get_i32("bar", 1), 1);
243 assert_eq!(prefs.get_i32("bar", 2), 2);
244
245 prefs.set_bool("foo", true);
247 prefs.set_i32("bar", 1);
248 assert_eq!(prefs.get_bool("foo", false), true);
249 assert_eq!(prefs.get_bool("foo", true), true);
250 assert_eq!(prefs.get_i32("bar", 0), 1);
251 assert_eq!(prefs.get_i32("bar", 1), 1);
252 assert_eq!(prefs.get_i32("bar", 2), 1);
253 prefs.set_bool("foo", false);
254 prefs.set_i32("bar", 2);
255 assert_eq!(prefs.get_bool("foo", false), false);
256 assert_eq!(prefs.get_bool("foo", true), false);
257 assert_eq!(prefs.get_i32("bar", 0), 2);
258 assert_eq!(prefs.get_i32("bar", 1), 2);
259 assert_eq!(prefs.get_i32("bar", 2), 2);
260
261 prefs.set_i32("foo", 3);
263 prefs.set_bool("bar", true);
264 assert_eq!(prefs.get_i32("foo", 0), 3);
265 assert_eq!(prefs.get_bool("foo", false), false);
266 assert_eq!(prefs.get_bool("bar", false), true);
267 assert_eq!(prefs.get_i32("bar", 0), 2);
268}