1use 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
15pub struct SETTINGS;
17
18impl SETTINGS {
19 pub fn register(&self, f: impl Fn(&mut SettingsBuilder) + Send + Sync + 'static) {
23 SETTINGS_SV.write().sources.push(Box::new(f))
24 }
25
26 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 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 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 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 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 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 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 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#[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#[derive(Clone)]
254pub struct Category {
255 id: CategoryId,
256 order: u16,
257 name: Var<Txt>,
258 meta: Arc<OwnedStateMap<Category>>,
259}
260impl Category {
261 pub fn id(&self) -> &CategoryId {
263 &self.id
264 }
265
266 pub fn order(&self) -> u16 {
270 self.order
271 }
272
273 pub fn name(&self) -> &Var<Txt> {
275 &self.name
276 }
277
278 pub fn meta(&self) -> StateMapRef<'_, Category> {
280 self.meta.borrow()
281 }
282
283 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
310pub 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 pub fn key(&self) -> &ConfigKey {
340 &self.key
341 }
342
343 pub fn order(&self) -> u16 {
347 self.order
348 }
349
350 pub fn name(&self) -> &Var<Txt> {
352 &self.name
353 }
354 pub fn description(&self) -> &Var<Txt> {
356 &self.description
357 }
358 pub fn category(&self) -> &CategoryId {
360 &self.category
361 }
362
363 pub fn meta(&self) -> StateMapRef<'_, Setting> {
365 self.meta.borrow()
366 }
367
368 pub fn value_is_set(&self) -> bool {
372 self.value_type != TypeId::of::<SettingValueNotSet>()
373 }
374
375 pub fn value(&self) -> &AnyVar {
377 &self.value
378 }
379
380 pub fn value_type(&self) -> TypeId {
382 self.value_type
383 }
384
385 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 pub fn can_reset(&self) -> Var<bool> {
397 self.reset.can_reset(&self.key, &self.value)
398 }
399
400 pub fn reset(&self) {
402 self.reset.reset(&self.key, &self.value);
403 }
404
405 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
459pub struct SettingsBuilder<'a> {
461 settings: Vec<Setting>,
462 filter: &'a mut dyn FnMut(&ConfigKey, &CategoryId) -> bool,
463}
464impl SettingsBuilder<'_> {
465 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
513pub 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 pub fn key(&self) -> &ConfigKey {
528 &self.config_key
529 }
530 pub fn category(&self) -> &CategoryId {
532 &self.category_id
533 }
534
535 pub fn order(&mut self, order: u16) -> &mut Self {
539 self.order = order;
540 self
541 }
542
543 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 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 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 pub fn flag(&mut self, id: impl Into<StateId<()>>) -> &mut Self {
563 self.meta.borrow_mut().flag(id);
564 self
565 }
566
567 pub fn meta(&mut self) -> StateMapMut<'_, Setting> {
569 self.meta.borrow_mut()
570 }
571
572 pub fn value<T: ConfigValue>(&mut self, default: T) -> &mut Self {
574 self.cfg_value(&mut CONFIG, default)
575 }
576
577 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 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 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
631pub struct CategoriesBuilder<'f> {
633 categories: Vec<Category>,
634 filter: &'f mut dyn FnMut(&CategoryId) -> bool,
635}
636impl CategoriesBuilder<'_> {
637 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
676pub 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 pub fn id(&self) -> &CategoryId {
687 &self.category_id
688 }
689
690 pub fn order(&mut self, order: u16) -> &mut Self {
694 self.order = order;
695 self
696 }
697
698 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 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 pub fn flag(&mut self, id: impl Into<StateId<()>>) -> &mut Self {
712 self.meta.borrow_mut().flag(id);
713 self
714 }
715
716 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}