zng_ext_config/
settings.rs

1//! Settings are the config the user can directly edit, this module implements a basic settings data model.
2//!
3//! The settings editor widget is not implemented here, this module bridges config implementers with settings UI implementers.
4
5use core::fmt;
6use std::{any::TypeId, cmp::Ordering, mem, ops, sync::Arc};
7
8use zng_app_context::app_local;
9use zng_state_map::{OwnedStateMap, StateId, StateMapMut, StateMapRef, StateValue};
10use zng_txt::Txt;
11use zng_var::{AnyVar, AnyVarHookArgs, BoxAnyVarValue, IntoVar, Var, const_var, impl_from_and_into_var, var};
12
13use crate::{CONFIG, Config, ConfigKey, ConfigValue, FallbackConfigReset};
14
15/// Settings metadata service.
16pub struct SETTINGS;
17
18impl SETTINGS {
19    /// Register a closure that provides settings metadata.
20    ///
21    /// The closure can be called multiple times.
22    pub fn register(&self, f: impl Fn(&mut SettingsBuilder) + Send + Sync + 'static) {
23        SETTINGS_SV.write().sources.push(Box::new(f))
24    }
25
26    /// Register a closure that provides category metadata.
27    ///
28    /// The closure can be called multiple times.
29    pub fn register_categories(&self, f: impl Fn(&mut CategoriesBuilder) + Send + Sync + 'static) {
30        SETTINGS_SV.write().sources_cat.push(Box::new(f))
31    }
32
33    /// Select and sort settings matched by `filter`.
34    ///
35    /// This calls all registered closures that are not excluded by `filter`.
36    pub fn get(&self, mut filter: impl FnMut(&ConfigKey, &CategoryId) -> bool, sort: bool) -> Vec<(Category, Vec<Setting>)> {
37        self.get_impl(&mut filter, sort)
38    }
39
40    fn get_impl(&self, filter: &mut dyn FnMut(&ConfigKey, &CategoryId) -> bool, sort: bool) -> Vec<(Category, Vec<Setting>)> {
41        let sv = SETTINGS_SV.read();
42
43        let mut settings = SettingsBuilder { settings: vec![], filter };
44        for source in sv.sources.iter() {
45            source(&mut settings);
46        }
47        let settings = settings.settings;
48
49        let mut categories = CategoriesBuilder {
50            categories: vec![],
51            filter: &mut |cat| settings.iter().any(|s| &s.category == cat),
52        };
53        for source in sv.sources_cat.iter() {
54            source(&mut categories);
55        }
56        let categories = categories.categories;
57
58        let mut result: Vec<_> = categories.into_iter().map(|c| (c, vec![])).collect();
59        for s in settings {
60            if let Some(i) = result.iter().position(|(c, _)| c.id == s.category) {
61                result[i].1.push(s);
62            } else {
63                tracing::warn!("missing category metadata for {}", s.category);
64                result.push((
65                    Category {
66                        id: s.category.clone(),
67                        order: u16::MAX,
68                        name: const_var(s.category.0.clone()),
69                        meta: Arc::new(OwnedStateMap::new()),
70                    },
71                    vec![s],
72                ));
73            }
74        }
75
76        if sort {
77            self.sort(&mut result);
78        }
79        result
80    }
81
82    /// Gets if there are any setting matched by `filter`.
83    pub fn any(&self, mut filter: impl FnMut(&ConfigKey, &CategoryId) -> bool) -> bool {
84        self.any_impl(&mut filter)
85    }
86    fn any_impl(&self, filter: &mut dyn FnMut(&ConfigKey, &CategoryId) -> bool) -> bool {
87        let sv = SETTINGS_SV.read();
88
89        let mut any = false;
90
91        for source in sv.sources.iter() {
92            source(&mut SettingsBuilder {
93                settings: vec![],
94                filter: &mut |k, i| {
95                    if filter(k, i) {
96                        any = true;
97                    }
98                    false
99                },
100            });
101            if any {
102                break;
103            }
104        }
105
106        any
107    }
108
109    /// Count how many settings match the `filter`.
110    pub fn count(&self, mut filter: impl FnMut(&ConfigKey, &CategoryId) -> bool) -> usize {
111        self.count_impl(&mut filter)
112    }
113    fn count_impl(&self, filter: &mut dyn FnMut(&ConfigKey, &CategoryId) -> bool) -> usize {
114        let sv = SETTINGS_SV.read();
115
116        let mut count = 0;
117
118        for source in sv.sources.iter() {
119            source(&mut SettingsBuilder {
120                settings: vec![],
121                filter: &mut |k, i| {
122                    if filter(k, i) {
123                        count += 1;
124                    }
125                    false
126                },
127            });
128        }
129
130        count
131    }
132
133    /// Select and sort categories matched by `filter`.
134    ///
135    /// If `include_empty` is `true` includes categories that have no settings.
136    pub fn categories(&self, mut filter: impl FnMut(&CategoryId) -> bool, include_empty: bool, sort: bool) -> Vec<Category> {
137        self.categories_impl(&mut filter, include_empty, sort)
138    }
139    fn categories_impl(&self, filter: &mut dyn FnMut(&CategoryId) -> bool, include_empty: bool, sort: bool) -> Vec<Category> {
140        let sv = SETTINGS_SV.read();
141
142        let mut categories = CategoriesBuilder {
143            categories: vec![],
144            filter,
145        };
146        for source in sv.sources_cat.iter() {
147            source(&mut categories);
148        }
149        let mut result = categories.categories;
150
151        if !include_empty {
152            let mut non_empty = vec![];
153            for source in sv.sources.iter() {
154                source(&mut SettingsBuilder {
155                    settings: vec![],
156                    filter: &mut |_, cat| {
157                        if !non_empty.contains(cat) {
158                            non_empty.push(cat.clone());
159                        }
160                        false
161                    },
162                });
163            }
164
165            result.retain(|c| {
166                if let Some(i) = non_empty.iter().position(|id| &c.id == id) {
167                    non_empty.swap_remove(i);
168                    true
169                } else {
170                    false
171                }
172            });
173
174            for missing in non_empty {
175                tracing::warn!("missing category metadata for {}", missing);
176                result.push(Category::unknown(missing));
177            }
178        }
179
180        if sort {
181            self.sort_categories(&mut result)
182        }
183
184        result
185    }
186
187    /// Sort `settings`.
188    pub fn sort_settings(&self, settings: &mut [Setting]) {
189        settings.sort_by(|a, b| {
190            let c = a.order.cmp(&b.order);
191            if matches!(c, Ordering::Equal) {
192                return a.name.with(|a| b.name.with(|b| a.cmp(b)));
193            }
194            c
195        });
196    }
197
198    /// Sort `categories`.
199    pub fn sort_categories(&self, categories: &mut [Category]) {
200        categories.sort_by(|a, b| {
201            let c = a.order.cmp(&b.order);
202            if matches!(c, Ordering::Equal) {
203                return a.name.with(|a| b.name.with(|b| a.cmp(b)));
204            }
205            c
206        });
207    }
208
209    /// Sort categories and settings.
210    pub fn sort(&self, settings: &mut [(Category, Vec<Setting>)]) {
211        settings.sort_by(|a, b| {
212            let c = a.0.order.cmp(&b.0.order);
213            if matches!(c, Ordering::Equal) {
214                return a.0.name.with(|a| b.0.name.with(|b| a.cmp(b)));
215            }
216            c
217        });
218        for (_, s) in settings {
219            self.sort_settings(s);
220        }
221    }
222}
223
224/// Unique ID of a [`Category`].
225#[derive(PartialEq, Eq, Clone, Debug, Hash, Default, serde::Serialize, serde::Deserialize)]
226#[serde(transparent)]
227pub struct CategoryId(pub Txt);
228impl_from_and_into_var! {
229    fn from(id: Txt) -> CategoryId {
230        CategoryId(id)
231    }
232    fn from(id: String) -> CategoryId {
233        CategoryId(id.into())
234    }
235    fn from(id: &'static str) -> CategoryId {
236        CategoryId(id.into())
237    }
238}
239impl ops::Deref for CategoryId {
240    type Target = Txt;
241
242    fn deref(&self) -> &Self::Target {
243        &self.0
244    }
245}
246impl fmt::Display for CategoryId {
247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248        fmt::Display::fmt(&self.0, f)
249    }
250}
251
252/// Settings category.
253#[derive(Clone)]
254pub struct Category {
255    id: CategoryId,
256    order: u16,
257    name: Var<Txt>,
258    meta: Arc<OwnedStateMap<Category>>,
259}
260impl Category {
261    /// Unique ID.
262    pub fn id(&self) -> &CategoryId {
263        &self.id
264    }
265
266    /// Position of the category in a list of categories.
267    ///
268    /// Lower numbers are listed first, two categories with the same order are sorted by display name.
269    pub fn order(&self) -> u16 {
270        self.order
271    }
272
273    /// Display name.
274    pub fn name(&self) -> &Var<Txt> {
275        &self.name
276    }
277
278    /// Custom category metadata.
279    pub fn meta(&self) -> StateMapRef<'_, Category> {
280        self.meta.borrow()
281    }
282
283    /// Category from an ID only, no other metadata.
284    pub fn unknown(missing: CategoryId) -> Self {
285        Self {
286            id: missing.clone(),
287            order: u16::MAX,
288            name: const_var(missing.0),
289            meta: Arc::default(),
290        }
291    }
292}
293impl PartialEq for Category {
294    fn eq(&self, other: &Self) -> bool {
295        self.id == other.id
296    }
297}
298impl Eq for Category {}
299impl fmt::Debug for Category {
300    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301        f.debug_struct("Category").field("id", &self.id).finish_non_exhaustive()
302    }
303}
304
305#[cfg(test)]
306fn _setting_in_var(s: Setting) {
307    let _x = const_var(s).get();
308}
309
310/// Setting entry.
311pub struct Setting {
312    key: ConfigKey,
313    order: u16,
314    name: Var<Txt>,
315    description: Var<Txt>,
316    category: CategoryId,
317    meta: Arc<OwnedStateMap<Setting>>,
318    value: AnyVar,
319    value_type: TypeId,
320    reset: Arc<dyn SettingReset>,
321}
322impl Clone for Setting {
323    fn clone(&self) -> Self {
324        Self {
325            key: self.key.clone(),
326            order: self.order,
327            name: self.name.clone(),
328            description: self.description.clone(),
329            category: self.category.clone(),
330            meta: self.meta.clone(),
331            value: self.value.clone(),
332            value_type: self.value_type,
333            reset: self.reset.clone(),
334        }
335    }
336}
337impl Setting {
338    /// The config edited by this setting.
339    pub fn key(&self) -> &ConfigKey {
340        &self.key
341    }
342
343    /// Position of the setting in a list of settings.
344    ///
345    /// Lower numbers are listed first, two settings with the same order are sorted by display name.
346    pub fn order(&self) -> u16 {
347        self.order
348    }
349
350    /// Display name.
351    pub fn name(&self) -> &Var<Txt> {
352        &self.name
353    }
354    /// Short help text.
355    pub fn description(&self) -> &Var<Txt> {
356        &self.description
357    }
358    /// Settings category.
359    pub fn category(&self) -> &CategoryId {
360        &self.category
361    }
362
363    /// Custom setting metadata.
364    pub fn meta(&self) -> StateMapRef<'_, Setting> {
365        self.meta.borrow()
366    }
367
368    /// If the `value` is set to an actual config variable.
369    ///
370    /// Setting builders can skip setting the value, this can indicate the config should be edited directly.
371    pub fn value_is_set(&self) -> bool {
372        self.value_type != TypeId::of::<SettingValueNotSet>()
373    }
374
375    /// Config value.
376    pub fn value(&self) -> &AnyVar {
377        &self.value
378    }
379
380    /// Config value type.
381    pub fn value_type(&self) -> TypeId {
382        self.value_type
383    }
384
385    /// Config value, strongly typed.
386    pub fn value_downcast<T: ConfigValue>(&self) -> Option<Var<T>> {
387        if self.value_type == std::any::TypeId::of::<T>() {
388            let v = self.value.clone().downcast::<T>().unwrap_or_else(|_| panic!());
389            Some(v)
390        } else {
391            None
392        }
393    }
394
395    /// Gets a variable that indicates the current setting value is not the default.
396    pub fn can_reset(&self) -> Var<bool> {
397        self.reset.can_reset(&self.key, &self.value)
398    }
399
400    /// Reset the setting value.
401    pub fn reset(&self) {
402        self.reset.reset(&self.key, &self.value);
403    }
404
405    /// Gets if the setting should be included in the search and how likely it is to be an exact match (0 is exact).
406    ///
407    /// If `search` starts with `@key:` matches key case sensitive, otherwise matches name or description in lower case. Note
408    /// that non-key search is expected to already be lowercase.
409    pub fn search_index(&self, search: &str) -> Option<usize> {
410        if let Some(key) = search.strip_prefix("@key:") {
411            return if self.key.contains(key) {
412                Some(self.key.len() - search.len())
413            } else {
414                None
415            };
416        }
417
418        let r = self.name.with(|s| {
419            let s = s.to_lowercase();
420            if s.contains(search) { Some(s.len() - search.len()) } else { None }
421        });
422        if r.is_some() {
423            return r;
424        }
425
426        self.description.with(|s| {
427            let s = s.to_lowercase();
428            if s.contains(search) {
429                Some(s.len() - search.len() + usize::MAX / 2)
430            } else {
431                None
432            }
433        })
434    }
435}
436impl PartialEq for Setting {
437    fn eq(&self, other: &Self) -> bool {
438        self.key == other.key
439    }
440}
441impl Eq for Setting {}
442impl fmt::Debug for Setting {
443    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
444        f.debug_struct("Setting").field("key", &self.key).finish_non_exhaustive()
445    }
446}
447
448app_local! {
449    static SETTINGS_SV: SettingsService = SettingsService {
450        sources: vec![],
451        sources_cat: vec![],
452    };
453}
454struct SettingsService {
455    sources: Vec<Box<dyn Fn(&mut SettingsBuilder) + Send + Sync + 'static>>,
456    sources_cat: Vec<Box<dyn Fn(&mut CategoriesBuilder) + Send + Sync + 'static>>,
457}
458
459/// Settings builder.
460pub struct SettingsBuilder<'a> {
461    settings: Vec<Setting>,
462    filter: &'a mut dyn FnMut(&ConfigKey, &CategoryId) -> bool,
463}
464impl SettingsBuilder<'_> {
465    /// Calls `builder` for the key and category if it is not filtered by the view query.
466    ///
467    /// If the setting is already present the builder overrides only the metadata set.
468    pub fn entry(
469        &mut self,
470        config_key: impl Into<ConfigKey>,
471        category_id: impl Into<CategoryId>,
472        builder: impl for<'a, 'b> FnOnce(&'a mut SettingBuilder<'b>) -> &'a mut SettingBuilder<'b>,
473    ) -> &mut Self {
474        if let Some(mut e) = self.entry_impl(config_key.into(), category_id.into()) {
475            builder(&mut e);
476        }
477        self
478    }
479    fn entry_impl(&mut self, config_key: ConfigKey, category_id: CategoryId) -> Option<SettingBuilder<'_>> {
480        if (self.filter)(&config_key, &category_id) {
481            if let Some(i) = self.settings.iter().position(|s| s.key == config_key) {
482                let existing = self.settings.swap_remove(i);
483                Some(SettingBuilder {
484                    settings: &mut self.settings,
485                    config_key,
486                    category_id,
487                    order: existing.order,
488                    name: Some(existing.name),
489                    description: Some(existing.description),
490                    meta: Arc::try_unwrap(existing.meta).unwrap(),
491                    value: None,
492                    reset: None,
493                })
494            } else {
495                Some(SettingBuilder {
496                    settings: &mut self.settings,
497                    config_key,
498                    category_id,
499                    order: u16::MAX,
500                    name: None,
501                    description: None,
502                    meta: OwnedStateMap::new(),
503                    value: None,
504                    reset: None,
505                })
506            }
507        } else {
508            None
509        }
510    }
511}
512
513/// Setting entry builder.
514pub struct SettingBuilder<'a> {
515    settings: &'a mut Vec<Setting>,
516    config_key: ConfigKey,
517    category_id: CategoryId,
518    order: u16,
519    name: Option<Var<Txt>>,
520    description: Option<Var<Txt>>,
521    meta: OwnedStateMap<Setting>,
522    value: Option<(AnyVar, TypeId)>,
523    reset: Option<Arc<dyn SettingReset>>,
524}
525impl SettingBuilder<'_> {
526    /// The config edited by this setting.
527    pub fn key(&self) -> &ConfigKey {
528        &self.config_key
529    }
530    /// Settings category.
531    pub fn category(&self) -> &CategoryId {
532        &self.category_id
533    }
534
535    /// Set the setting order number.
536    ///
537    /// Lower numbers are listed first, two categories with the same order are sorted by display name.
538    pub fn order(&mut self, order: u16) -> &mut Self {
539        self.order = order;
540        self
541    }
542
543    /// Set the setting name.
544    pub fn name(&mut self, name: impl IntoVar<Txt>) -> &mut Self {
545        self.name = Some(name.into_var().read_only());
546        self
547    }
548
549    /// Set the setting short help text.
550    pub fn description(&mut self, description: impl IntoVar<Txt>) -> &mut Self {
551        self.description = Some(description.into_var().read_only());
552        self
553    }
554
555    /// Set the custom metadata value.
556    pub fn set<T: StateValue>(&mut self, id: impl Into<StateId<T>>, value: impl Into<T>) -> &mut Self {
557        self.meta.borrow_mut().set(id, value);
558        self
559    }
560
561    /// Set the custom metadata flag.
562    pub fn flag(&mut self, id: impl Into<StateId<()>>) -> &mut Self {
563        self.meta.borrow_mut().flag(id);
564        self
565    }
566
567    /// Custom setting metadata.
568    pub fn meta(&mut self) -> StateMapMut<'_, Setting> {
569        self.meta.borrow_mut()
570    }
571
572    /// Get the value variable for editing from [`CONFIG`]. The `default` value is used when getting the variable.
573    pub fn value<T: ConfigValue>(&mut self, default: T) -> &mut Self {
574        self.cfg_value(&mut CONFIG, default)
575    }
576
577    /// Get the value variable for editing from `cfg`. The `default` value is used when getting the variable.
578    pub fn cfg_value<T: ConfigValue>(&mut self, cfg: &mut impl Config, default: T) -> &mut Self {
579        let value = cfg.get(self.config_key.clone(), default, false);
580        self.value = Some((value.into(), TypeId::of::<T>()));
581        self
582    }
583
584    /// Use a [`FallbackConfigReset`] to reset the settings.
585    ///
586    /// This is the preferred way of implementing reset as it keeps the user config file clean,
587    /// but it does require a config setup with two files.
588    ///
589    /// The `strip_key_prefix` is removed from config keys before passing to `resetter`, this is
590    /// required if the config is setup using a switch over multiple files.
591    pub fn reset(&mut self, resetter: Box<dyn FallbackConfigReset>, strip_key_prefix: impl Into<Txt>) -> &mut Self {
592        self.reset = Some(Arc::new(FallbackReset {
593            resetter,
594            strip_key_prefix: strip_key_prefix.into(),
595        }));
596        self
597    }
598
599    /// Use a `default` value to reset the settings.
600    ///
601    /// The default value is set on the config to reset.
602    pub fn default<T: ConfigValue>(&mut self, default: T) -> &mut Self {
603        let reset = BoxAnyVarValue::new(default);
604        self.reset = Some(Arc::new(reset));
605        self
606    }
607}
608impl Drop for SettingBuilder<'_> {
609    fn drop(&mut self) {
610        let (cfg, cfg_type) = self.value.take().unwrap_or_else(|| {
611            tracing::debug!("no value provided for {} settings", self.config_key);
612            (const_var(SettingValueNotSet).into(), TypeId::of::<SettingValueNotSet>())
613        });
614        self.settings.push(Setting {
615            key: mem::take(&mut self.config_key),
616            order: self.order,
617            name: self.name.take().unwrap_or_else(|| var(Txt::from_static(""))),
618            description: self.description.take().unwrap_or_else(|| var(Txt::from_static(""))),
619            category: mem::take(&mut self.category_id),
620            meta: Arc::new(mem::take(&mut self.meta)),
621            value: cfg,
622            value_type: cfg_type,
623            reset: self.reset.take().unwrap_or_else(|| Arc::new(SettingValueNotSet)),
624        })
625    }
626}
627
628#[derive(Clone, PartialEq, Debug)]
629struct SettingValueNotSet;
630
631/// Setting categories builder.
632pub struct CategoriesBuilder<'f> {
633    categories: Vec<Category>,
634    filter: &'f mut dyn FnMut(&CategoryId) -> bool,
635}
636impl CategoriesBuilder<'_> {
637    /// Calls `builder` for the id if it is not filtered by the view query.
638    ///
639    /// If the category is already present the builder overrides only the metadata set.
640    pub fn entry(
641        &mut self,
642        category_id: impl Into<CategoryId>,
643        builder: impl for<'a, 'b> FnOnce(&'a mut CategoryBuilder<'b>) -> &'a mut CategoryBuilder<'b>,
644    ) -> &mut Self {
645        if let Some(mut e) = self.entry_impl(category_id.into()) {
646            builder(&mut e);
647        }
648        self
649    }
650    fn entry_impl(&mut self, category_id: CategoryId) -> Option<CategoryBuilder<'_>> {
651        if (self.filter)(&category_id) {
652            if let Some(i) = self.categories.iter().position(|s| s.id == category_id) {
653                let existing = self.categories.swap_remove(i);
654                Some(CategoryBuilder {
655                    categories: &mut self.categories,
656                    category_id,
657                    order: existing.order,
658                    name: Some(existing.name),
659                    meta: Arc::try_unwrap(existing.meta).unwrap(),
660                })
661            } else {
662                Some(CategoryBuilder {
663                    categories: &mut self.categories,
664                    category_id,
665                    order: u16::MAX,
666                    name: None,
667                    meta: OwnedStateMap::new(),
668                })
669            }
670        } else {
671            None
672        }
673    }
674}
675
676/// Category entry builder.
677pub struct CategoryBuilder<'a> {
678    categories: &'a mut Vec<Category>,
679    category_id: CategoryId,
680    order: u16,
681    name: Option<Var<Txt>>,
682    meta: OwnedStateMap<Category>,
683}
684impl CategoryBuilder<'_> {
685    /// Unique ID.
686    pub fn id(&self) -> &CategoryId {
687        &self.category_id
688    }
689
690    /// Set the position of the category in a list of categories.
691    ///
692    /// Lower numbers are listed first, two categories with the same order are sorted by display name.
693    pub fn order(&mut self, order: u16) -> &mut Self {
694        self.order = order;
695        self
696    }
697
698    /// Set the category name.
699    pub fn name(&mut self, name: impl IntoVar<Txt>) -> &mut Self {
700        self.name = Some(name.into_var().read_only());
701        self
702    }
703
704    /// Set the custom metadata value.
705    pub fn set<T: StateValue>(&mut self, id: impl Into<StateId<T>>, value: impl Into<T>) -> &mut Self {
706        self.meta.borrow_mut().set(id, value);
707        self
708    }
709
710    /// Set the custom metadata flag.
711    pub fn flag(&mut self, id: impl Into<StateId<()>>) -> &mut Self {
712        self.meta.borrow_mut().flag(id);
713        self
714    }
715
716    /// Custom category metadata.
717    pub fn meta(&mut self) -> StateMapMut<'_, Category> {
718        self.meta.borrow_mut()
719    }
720}
721impl Drop for CategoryBuilder<'_> {
722    fn drop(&mut self) {
723        self.categories.push(Category {
724            id: mem::take(&mut self.category_id),
725            order: self.order,
726            name: self.name.take().unwrap_or_else(|| var(Txt::from_static(""))),
727            meta: Arc::new(mem::take(&mut self.meta)),
728        })
729    }
730}
731trait SettingReset: Send + Sync + 'static {
732    fn can_reset(&self, key: &ConfigKey, value: &AnyVar) -> Var<bool>;
733    fn reset(&self, key: &ConfigKey, value: &AnyVar);
734}
735
736struct FallbackReset {
737    resetter: Box<dyn FallbackConfigReset>,
738    strip_key_prefix: Txt,
739}
740
741impl SettingReset for FallbackReset {
742    fn can_reset(&self, key: &ConfigKey, _: &AnyVar) -> Var<bool> {
743        match key.strip_prefix(self.strip_key_prefix.as_str()) {
744            Some(k) => self.resetter.can_reset(ConfigKey::from_str(k)),
745            None => self.resetter.can_reset(key.clone()),
746        }
747    }
748
749    fn reset(&self, key: &ConfigKey, _: &AnyVar) {
750        match key.strip_prefix(self.strip_key_prefix.as_str()) {
751            Some(k) => self.resetter.reset(&ConfigKey::from_str(k)),
752            None => self.resetter.reset(key),
753        }
754    }
755}
756impl SettingReset for BoxAnyVarValue {
757    fn can_reset(&self, _: &ConfigKey, value: &AnyVar) -> Var<bool> {
758        let initial = value.with(|v| v.eq_any(&**self));
759        let map = var(initial);
760
761        let map_in = map.clone();
762        let dft = (*self).clone_boxed();
763        value
764            .hook(move |args: &AnyVarHookArgs| {
765                map_in.set(args.value().eq_any(&*dft));
766                true
767            })
768            .perm();
769
770        map.clone()
771    }
772
773    fn reset(&self, _: &ConfigKey, value: &AnyVar) {
774        value.set((*self).clone_boxed());
775    }
776}
777impl SettingReset for SettingValueNotSet {
778    fn can_reset(&self, _: &ConfigKey, _: &AnyVar) -> Var<bool> {
779        const_var(false)
780    }
781    fn reset(&self, _: &ConfigKey, _: &AnyVar) {}
782}