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