1use std::collections::BTreeMap;
59use std::marker::PhantomData;
60use std::sync::atomic::Ordering::SeqCst;
61use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, AtomicUsize};
62use std::sync::{Arc, RwLock};
63use std::time::Duration;
64
65use serde::{Deserialize, Serialize};
66use tracing::error;
67
68#[derive(Clone, Debug)]
77pub struct Config<D: ConfigDefault> {
78 name: &'static str,
79 desc: &'static str,
80 default: D,
81}
82
83impl<D: ConfigDefault> Config<D> {
84 pub const fn new(name: &'static str, default: D, desc: &'static str) -> Self {
99 Config {
100 name,
101 default,
102 desc,
103 }
104 }
105
106 pub fn name(&self) -> &str {
108 self.name
109 }
110
111 pub fn desc(&self) -> &str {
113 self.desc
114 }
115
116 pub fn default(&self) -> &D {
118 &self.default
119 }
120
121 pub fn get(&self, set: &ConfigSet) -> D::ConfigType {
131 D::ConfigType::from_val(self.shared(set).load())
132 }
133
134 pub fn handle(&self, set: &ConfigSet) -> ConfigValHandle<D::ConfigType> {
138 ConfigValHandle {
139 val: self.shared(set).clone(),
140 _type: PhantomData,
141 }
142 }
143
144 fn shared<'a>(&self, set: &'a ConfigSet) -> &'a ConfigValAtomic {
146 &set.configs
147 .get(self.name)
148 .unwrap_or_else(|| panic!("config {} should be registered to set", self.name))
149 .val
150 }
151
152 pub fn parse_val(&self, val: &str) -> Result<ConfigVal, String> {
154 let val = D::ConfigType::parse(val)?;
155 let val = Into::<ConfigVal>::into(val);
156 Ok(val)
157 }
158}
159
160pub trait ConfigType: Into<ConfigVal> + Clone + Sized {
162 fn from_val(val: ConfigVal) -> Self;
166
167 fn parse(s: &str) -> Result<Self, String>;
169}
170
171pub trait ConfigDefault: Clone {
173 type ConfigType: ConfigType;
174
175 fn into_config_type(self) -> Self::ConfigType;
177}
178
179impl<T: ConfigType> ConfigDefault for T {
180 type ConfigType = T;
181
182 fn into_config_type(self) -> T {
183 self
184 }
185}
186
187impl<T: ConfigType> ConfigDefault for fn() -> T {
188 type ConfigType = T;
189
190 fn into_config_type(self) -> T {
191 (self)()
192 }
193}
194
195#[derive(Clone, Default)]
209pub struct ConfigSet {
210 configs: BTreeMap<String, ConfigEntry>,
211}
212
213impl ConfigSet {
214 pub fn add<D: ConfigDefault>(mut self, config: &Config<D>) -> Self {
224 let default = config.default.clone().into_config_type();
225 let default = Into::<ConfigVal>::into(default);
226 let config = ConfigEntry {
227 name: config.name,
228 desc: config.desc,
229 default: default.clone(),
230 val: ConfigValAtomic::from(default),
231 };
232 if let Some(prev) = self.configs.insert(config.name.to_owned(), config) {
233 panic!("{} registered twice", prev.name);
234 }
235 self
236 }
237
238 pub fn entries(&self) -> impl Iterator<Item = &ConfigEntry> {
240 self.configs.values()
241 }
242
243 pub fn entry(&self, name: &str) -> Option<&ConfigEntry> {
245 self.configs.get(name)
246 }
247}
248
249#[derive(Clone, Debug)]
251pub struct ConfigEntry {
252 name: &'static str,
253 desc: &'static str,
254 default: ConfigVal,
255 val: ConfigValAtomic,
256}
257
258impl ConfigEntry {
259 pub fn name(&self) -> &'static str {
261 self.name
262 }
263
264 pub fn desc(&self) -> &'static str {
266 self.desc
267 }
268
269 pub fn default(&self) -> &ConfigVal {
273 &self.default
274 }
275
276 pub fn val(&self) -> ConfigVal {
278 self.val.load()
279 }
280}
281
282#[derive(Debug, Clone)]
288pub struct ConfigValHandle<T> {
289 val: ConfigValAtomic,
290 _type: PhantomData<T>,
291}
292
293impl<T: ConfigType> ConfigValHandle<T> {
294 pub fn get(&self) -> T {
297 T::from_val(self.val.load())
298 }
299
300 pub fn disconnected<X>(value: X) -> Self
303 where
304 X: ConfigDefault<ConfigType = T>,
305 {
306 let config_val: ConfigVal = value.into_config_type().into();
307 Self {
308 val: config_val.into(),
309 _type: Default::default(),
310 }
311 }
312}
313
314#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
317pub enum ConfigVal {
318 Bool(bool),
320 U32(u32),
322 Usize(usize),
324 OptUsize(Option<usize>),
326 F64(f64),
328 String(String),
330 OptString(Option<String>),
332 Duration(Duration),
334 #[serde(with = "serde_json_string")]
336 Json(serde_json::Value),
337}
338
339mod serde_json_string {
342 use serde::de::{Deserialize, Deserializer, Error};
343 use serde::ser::Serializer;
344
345 pub fn serialize<S>(value: &serde_json::Value, serializer: S) -> Result<S::Ok, S::Error>
346 where
347 S: Serializer,
348 {
349 serializer.serialize_str(&value.to_string())
350 }
351
352 pub fn deserialize<'de, D>(deserializer: D) -> Result<serde_json::Value, D::Error>
353 where
354 D: Deserializer<'de>,
355 {
356 let s = String::deserialize(deserializer)?;
357 serde_json::from_str(&s).map_err(D::Error::custom)
358 }
359}
360
361#[derive(Clone, Debug)]
369enum ConfigValAtomic {
370 Bool(Arc<AtomicBool>),
371 U32(Arc<AtomicU32>),
372 Usize(Arc<AtomicUsize>),
373 OptUsize(Arc<RwLock<Option<usize>>>),
374 F64(Arc<AtomicU64>),
376 String(Arc<RwLock<String>>),
377 OptString(Arc<RwLock<Option<String>>>),
378 Duration(Arc<RwLock<Duration>>),
379 Json(Arc<RwLock<serde_json::Value>>),
380}
381
382impl From<ConfigVal> for ConfigValAtomic {
383 fn from(val: ConfigVal) -> ConfigValAtomic {
384 match val {
385 ConfigVal::Bool(x) => ConfigValAtomic::Bool(Arc::new(AtomicBool::new(x))),
386 ConfigVal::U32(x) => ConfigValAtomic::U32(Arc::new(AtomicU32::new(x))),
387 ConfigVal::Usize(x) => ConfigValAtomic::Usize(Arc::new(AtomicUsize::new(x))),
388 ConfigVal::OptUsize(x) => ConfigValAtomic::OptUsize(Arc::new(RwLock::new(x))),
389 ConfigVal::F64(x) => ConfigValAtomic::F64(Arc::new(AtomicU64::new(x.to_bits()))),
390 ConfigVal::String(x) => ConfigValAtomic::String(Arc::new(RwLock::new(x))),
391 ConfigVal::OptString(x) => ConfigValAtomic::OptString(Arc::new(RwLock::new(x))),
392 ConfigVal::Duration(x) => ConfigValAtomic::Duration(Arc::new(RwLock::new(x))),
393 ConfigVal::Json(x) => ConfigValAtomic::Json(Arc::new(RwLock::new(x))),
394 }
395 }
396}
397
398impl ConfigValAtomic {
399 fn load(&self) -> ConfigVal {
400 match self {
401 ConfigValAtomic::Bool(x) => ConfigVal::Bool(x.load(SeqCst)),
402 ConfigValAtomic::U32(x) => ConfigVal::U32(x.load(SeqCst)),
403 ConfigValAtomic::Usize(x) => ConfigVal::Usize(x.load(SeqCst)),
404 ConfigValAtomic::OptUsize(x) => ConfigVal::OptUsize(*x.read().expect("lock poisoned")),
405 ConfigValAtomic::F64(x) => ConfigVal::F64(f64::from_bits(x.load(SeqCst))),
406 ConfigValAtomic::String(x) => {
407 ConfigVal::String(x.read().expect("lock poisoned").clone())
408 }
409 ConfigValAtomic::OptString(x) => {
410 ConfigVal::OptString(x.read().expect("lock poisoned").clone())
411 }
412 ConfigValAtomic::Duration(x) => ConfigVal::Duration(*x.read().expect("lock poisoned")),
413 ConfigValAtomic::Json(x) => ConfigVal::Json(x.read().expect("lock poisoned").clone()),
414 }
415 }
416
417 fn store(&self, val: ConfigVal) {
418 match (self, val) {
419 (ConfigValAtomic::Bool(x), ConfigVal::Bool(val)) => x.store(val, SeqCst),
420 (ConfigValAtomic::U32(x), ConfigVal::U32(val)) => x.store(val, SeqCst),
421 (ConfigValAtomic::Usize(x), ConfigVal::Usize(val)) => x.store(val, SeqCst),
422 (ConfigValAtomic::OptUsize(x), ConfigVal::OptUsize(val)) => {
423 *x.write().expect("lock poisoned") = val
424 }
425 (ConfigValAtomic::F64(x), ConfigVal::F64(val)) => x.store(val.to_bits(), SeqCst),
426 (ConfigValAtomic::String(x), ConfigVal::String(val)) => {
427 *x.write().expect("lock poisoned") = val
428 }
429 (ConfigValAtomic::OptString(x), ConfigVal::OptString(val)) => {
430 *x.write().expect("lock poisoned") = val
431 }
432 (ConfigValAtomic::Duration(x), ConfigVal::Duration(val)) => {
433 *x.write().expect("lock poisoned") = val
434 }
435 (ConfigValAtomic::Json(x), ConfigVal::Json(val)) => {
436 *x.write().expect("lock poisoned") = val
437 }
438 (ConfigValAtomic::Bool(_), val)
439 | (ConfigValAtomic::U32(_), val)
440 | (ConfigValAtomic::Usize(_), val)
441 | (ConfigValAtomic::OptUsize(_), val)
442 | (ConfigValAtomic::F64(_), val)
443 | (ConfigValAtomic::String(_), val)
444 | (ConfigValAtomic::OptString(_), val)
445 | (ConfigValAtomic::Duration(_), val)
446 | (ConfigValAtomic::Json(_), val) => {
447 panic!("attempted to store {val:?} value in {self:?} parameter")
448 }
449 }
450 }
451}
452
453#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
458pub struct ConfigUpdates {
459 pub updates: BTreeMap<String, ConfigVal>,
460}
461
462impl ConfigUpdates {
463 pub fn add<T, U>(&mut self, config: &Config<T>, val: U)
468 where
469 T: ConfigDefault,
470 U: ConfigDefault<ConfigType = T::ConfigType>,
471 {
472 self.add_dynamic(config.name, val.into_config_type().into());
473 }
474
475 pub fn add_dynamic(&mut self, name: &str, val: ConfigVal) {
483 self.updates.insert(name.to_owned(), val);
484 }
485
486 pub fn extend(&mut self, mut other: Self) {
488 self.updates.append(&mut other.updates)
489 }
490
491 pub fn apply(&self, set: &ConfigSet) {
501 for (name, val) in self.updates.iter() {
502 let Some(config) = set.configs.get(name) else {
503 error!("config update {} {:?} not known set: {:?}", name, val, set);
504 continue;
505 };
506 config.val.store(val.clone());
507 }
508 }
509}
510
511mod impls {
512 use std::num::{ParseFloatError, ParseIntError};
513 use std::str::ParseBoolError;
514 use std::time::Duration;
515
516 use crate::{ConfigDefault, ConfigSet, ConfigType, ConfigVal};
517
518 impl ConfigType for bool {
519 fn from_val(val: ConfigVal) -> Self {
520 match val {
521 ConfigVal::Bool(x) => x,
522 x => panic!("expected bool value got {:?}", x),
523 }
524 }
525
526 fn parse(s: &str) -> Result<Self, String> {
527 match s {
528 "on" => return Ok(true),
529 "off" => return Ok(false),
530 _ => {}
531 }
532 s.parse().map_err(|e: ParseBoolError| e.to_string())
533 }
534 }
535
536 impl From<bool> for ConfigVal {
537 fn from(val: bool) -> ConfigVal {
538 ConfigVal::Bool(val)
539 }
540 }
541
542 impl ConfigType for u32 {
543 fn from_val(val: ConfigVal) -> Self {
544 match val {
545 ConfigVal::U32(x) => x,
546 x => panic!("expected u32 value got {:?}", x),
547 }
548 }
549
550 fn parse(s: &str) -> Result<Self, String> {
551 s.parse().map_err(|e: ParseIntError| e.to_string())
552 }
553 }
554
555 impl From<u32> for ConfigVal {
556 fn from(val: u32) -> ConfigVal {
557 ConfigVal::U32(val)
558 }
559 }
560
561 impl ConfigType for usize {
562 fn from_val(val: ConfigVal) -> Self {
563 match val {
564 ConfigVal::Usize(x) => x,
565 x => panic!("expected usize value got {:?}", x),
566 }
567 }
568
569 fn parse(s: &str) -> Result<Self, String> {
570 s.parse().map_err(|e: ParseIntError| e.to_string())
571 }
572 }
573
574 impl From<usize> for ConfigVal {
575 fn from(val: usize) -> ConfigVal {
576 ConfigVal::Usize(val)
577 }
578 }
579
580 impl ConfigType for Option<usize> {
581 fn from_val(val: ConfigVal) -> Self {
582 match val {
583 ConfigVal::OptUsize(x) => x,
584 x => panic!("expected usize value got {:?}", x),
585 }
586 }
587
588 fn parse(s: &str) -> Result<Self, String> {
589 if s.is_empty() {
590 Ok(None)
591 } else {
592 let val = s.parse().map_err(|e: ParseIntError| e.to_string())?;
593 Ok(Some(val))
594 }
595 }
596 }
597
598 impl From<Option<usize>> for ConfigVal {
599 fn from(val: Option<usize>) -> ConfigVal {
600 ConfigVal::OptUsize(val)
601 }
602 }
603
604 impl ConfigType for f64 {
605 fn from_val(val: ConfigVal) -> Self {
606 match val {
607 ConfigVal::F64(x) => x,
608 x => panic!("expected f64 value got {:?}", x),
609 }
610 }
611
612 fn parse(s: &str) -> Result<Self, String> {
613 s.parse().map_err(|e: ParseFloatError| e.to_string())
614 }
615 }
616
617 impl From<f64> for ConfigVal {
618 fn from(val: f64) -> ConfigVal {
619 ConfigVal::F64(val)
620 }
621 }
622
623 impl ConfigType for String {
624 fn from_val(val: ConfigVal) -> Self {
625 match val {
626 ConfigVal::String(x) => x,
627 x => panic!("expected String value got {:?}", x),
628 }
629 }
630
631 fn parse(s: &str) -> Result<Self, String> {
632 Ok(s.to_string())
633 }
634 }
635
636 impl From<String> for ConfigVal {
637 fn from(val: String) -> ConfigVal {
638 ConfigVal::String(val)
639 }
640 }
641
642 impl ConfigDefault for &str {
643 type ConfigType = String;
644
645 fn into_config_type(self) -> String {
646 self.into()
647 }
648 }
649
650 impl ConfigType for Option<String> {
651 fn from_val(val: ConfigVal) -> Self {
652 match val {
653 ConfigVal::OptString(x) => x,
654 x => panic!("expected String value got {:?}", x),
655 }
656 }
657
658 fn parse(s: &str) -> Result<Self, String> {
659 Ok(Some(s.to_string()))
660 }
661 }
662
663 impl From<Option<String>> for ConfigVal {
664 fn from(val: Option<String>) -> ConfigVal {
665 ConfigVal::OptString(val)
666 }
667 }
668
669 impl ConfigDefault for Option<&str> {
670 type ConfigType = Option<String>;
671
672 fn into_config_type(self) -> Option<String> {
673 self.map(|s| s.to_string())
674 }
675 }
676
677 impl ConfigType for Duration {
678 fn from_val(val: ConfigVal) -> Self {
679 match val {
680 ConfigVal::Duration(x) => x,
681 x => panic!("expected Duration value got {:?}", x),
682 }
683 }
684
685 fn parse(s: &str) -> Result<Self, String> {
686 humantime::parse_duration(s).map_err(|e| e.to_string())
687 }
688 }
689
690 impl From<Duration> for ConfigVal {
691 fn from(val: Duration) -> ConfigVal {
692 ConfigVal::Duration(val)
693 }
694 }
695
696 impl ConfigType for serde_json::Value {
697 fn from_val(val: ConfigVal) -> Self {
698 match val {
699 ConfigVal::Json(x) => x,
700 x => panic!("expected JSON value got {:?}", x),
701 }
702 }
703
704 fn parse(s: &str) -> Result<Self, String> {
705 serde_json::from_str(s).map_err(|e| e.to_string())
706 }
707 }
708
709 impl From<serde_json::Value> for ConfigVal {
710 fn from(val: serde_json::Value) -> ConfigVal {
711 ConfigVal::Json(val)
712 }
713 }
714
715 impl std::fmt::Debug for ConfigSet {
716 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
717 let ConfigSet { configs } = self;
718 f.debug_map()
719 .entries(configs.iter().map(|(name, val)| (name, val.val())))
720 .finish()
721 }
722 }
723}
724
725#[cfg(test)]
726mod tests {
727 use super::*;
728
729 use mz_ore::assert_err;
730
731 const BOOL: Config<bool> = Config::new("bool", true, "");
732 const U32: Config<u32> = Config::new("u32", 4, "");
733 const USIZE: Config<usize> = Config::new("usize", 1, "");
734 const OPT_USIZE: Config<Option<usize>> = Config::new("opt_usize", Some(2), "");
735 const F64: Config<f64> = Config::new("f64", 5.0, "");
736 const STRING: Config<&str> = Config::new("string", "a", "");
737 const OPT_STRING: Config<Option<&str>> = Config::new("opt_string", Some("a"), "");
738 const DURATION: Config<Duration> = Config::new("duration", Duration::from_nanos(3), "");
739 const JSON: Config<fn() -> serde_json::Value> =
740 Config::new("json", || serde_json::json!({}), "");
741
742 #[mz_ore::test]
743 fn all_types() {
744 let configs = ConfigSet::default()
745 .add(&BOOL)
746 .add(&USIZE)
747 .add(&U32)
748 .add(&OPT_USIZE)
749 .add(&F64)
750 .add(&STRING)
751 .add(&OPT_STRING)
752 .add(&DURATION)
753 .add(&JSON);
754 assert_eq!(BOOL.get(&configs), true);
755 assert_eq!(U32.get(&configs), 4);
756 assert_eq!(USIZE.get(&configs), 1);
757 assert_eq!(OPT_USIZE.get(&configs), Some(2));
758 assert_eq!(F64.get(&configs), 5.0);
759 assert_eq!(STRING.get(&configs), "a");
760 assert_eq!(OPT_STRING.get(&configs), Some("a".to_string()));
761 assert_eq!(DURATION.get(&configs), Duration::from_nanos(3));
762 assert_eq!(JSON.get(&configs), serde_json::json!({}));
763
764 let mut updates = ConfigUpdates::default();
765 updates.add(&BOOL, false);
766 updates.add(&U32, 7);
767 updates.add(&USIZE, 2);
768 updates.add(&OPT_USIZE, None::<usize>);
769 updates.add(&F64, 8.0);
770 updates.add(&STRING, "b");
771 updates.add(&OPT_STRING, None::<String>);
772 updates.add(&DURATION, Duration::from_nanos(4));
773 updates.add(&JSON, serde_json::json!({"a": 1}));
774 updates.apply(&configs);
775
776 assert_eq!(BOOL.get(&configs), false);
777 assert_eq!(U32.get(&configs), 7);
778 assert_eq!(USIZE.get(&configs), 2);
779 assert_eq!(OPT_USIZE.get(&configs), None);
780 assert_eq!(F64.get(&configs), 8.0);
781 assert_eq!(STRING.get(&configs), "b");
782 assert_eq!(OPT_STRING.get(&configs), None);
783 assert_eq!(DURATION.get(&configs), Duration::from_nanos(4));
784 assert_eq!(JSON.get(&configs), serde_json::json!({"a": 1}));
785 }
786
787 #[mz_ore::test]
788 fn fn_default() {
789 const BOOL_FN_DEFAULT: Config<fn() -> bool> = Config::new("bool", || !true, "");
790 const STRING_FN_DEFAULT: Config<fn() -> String> =
791 Config::new("string", || "x".repeat(3), "");
792
793 const OPT_STRING_FN_DEFAULT: Config<fn() -> Option<String>> =
794 Config::new("opt_string", || Some("x".repeat(3)), "");
795
796 let configs = ConfigSet::default()
797 .add(&BOOL_FN_DEFAULT)
798 .add(&STRING_FN_DEFAULT)
799 .add(&OPT_STRING_FN_DEFAULT);
800 assert_eq!(BOOL_FN_DEFAULT.get(&configs), false);
801 assert_eq!(STRING_FN_DEFAULT.get(&configs), "xxx");
802 assert_eq!(OPT_STRING_FN_DEFAULT.get(&configs), Some("xxx".to_string()));
803 }
804
805 #[mz_ore::test]
806 fn config_set() {
807 let c0 = ConfigSet::default().add(&USIZE);
808 assert_eq!(USIZE.get(&c0), 1);
809 let mut updates = ConfigUpdates::default();
810 updates.add(&USIZE, 2);
811 updates.apply(&c0);
812 assert_eq!(USIZE.get(&c0), 2);
813
814 let c1 = ConfigSet::default().add(&USIZE);
817 assert_eq!(USIZE.get(&c1), 1);
818 let mut updates = ConfigUpdates::default();
819 updates.add(&USIZE, 3);
820 updates.apply(&c1);
821 assert_eq!(USIZE.get(&c1), 3);
822 assert_eq!(USIZE.get(&c0), 2);
823
824 let mut updates = ConfigUpdates::default();
826 for e in c0.entries() {
827 updates.add_dynamic(e.name, e.val());
828 }
829 assert_eq!(USIZE.get(&c1), 3);
830 updates.apply(&c1);
831 assert_eq!(USIZE.get(&c1), 2);
832 }
833
834 #[mz_ore::test]
835 fn config_updates_extend() {
836 let mut u1 = {
842 let c = ConfigSet::default().add(&USIZE).add(&STRING);
843 let mut x = ConfigUpdates::default();
844 for e in c.entries() {
845 x.add_dynamic(e.name(), e.val());
846 }
847 x
848 };
849 let u2 = {
850 let c = ConfigSet::default().add(&USIZE).add(&DURATION);
851 let mut updates = ConfigUpdates::default();
852 updates.add(&USIZE, 2);
853 updates.apply(&c);
854 let mut x = ConfigUpdates::default();
855 for e in c.entries() {
856 x.add_dynamic(e.name(), e.val());
857 }
858 x
859 };
860 assert_eq!(u1.updates.len(), 2);
861 assert_eq!(u2.updates.len(), 2);
862 u1.extend(u2);
863 assert_eq!(u1.updates.len(), 3);
864
865 let c = ConfigSet::default().add(&USIZE);
868 u1.apply(&c);
869 assert_eq!(USIZE.get(&c), 2);
870 }
871
872 #[mz_ore::test]
873 fn config_parse() {
874 assert_eq!(BOOL.parse_val("true"), Ok(ConfigVal::Bool(true)));
875 assert_eq!(BOOL.parse_val("on"), Ok(ConfigVal::Bool(true)));
876 assert_eq!(BOOL.parse_val("false"), Ok(ConfigVal::Bool(false)));
877 assert_eq!(BOOL.parse_val("off"), Ok(ConfigVal::Bool(false)));
878 assert_err!(BOOL.parse_val("42"));
879 assert_err!(BOOL.parse_val("66.6"));
880 assert_err!(BOOL.parse_val("farragut"));
881 assert_err!(BOOL.parse_val(""));
882 assert_err!(BOOL.parse_val("5 s"));
883
884 assert_err!(U32.parse_val("true"));
885 assert_err!(U32.parse_val("false"));
886 assert_eq!(U32.parse_val("42"), Ok(ConfigVal::U32(42)));
887 assert_err!(U32.parse_val("66.6"));
888 assert_err!(U32.parse_val("farragut"));
889 assert_err!(U32.parse_val(""));
890 assert_err!(U32.parse_val("5 s"));
891
892 assert_err!(USIZE.parse_val("true"));
893 assert_err!(USIZE.parse_val("false"));
894 assert_eq!(USIZE.parse_val("42"), Ok(ConfigVal::Usize(42)));
895 assert_err!(USIZE.parse_val("66.6"));
896 assert_err!(USIZE.parse_val("farragut"));
897 assert_err!(USIZE.parse_val(""));
898 assert_err!(USIZE.parse_val("5 s"));
899
900 assert_err!(OPT_USIZE.parse_val("true"));
901 assert_err!(OPT_USIZE.parse_val("false"));
902 assert_eq!(OPT_USIZE.parse_val("42"), Ok(ConfigVal::OptUsize(Some(42))));
903 assert_err!(OPT_USIZE.parse_val("66.6"));
904 assert_err!(OPT_USIZE.parse_val("farragut"));
905 assert_eq!(OPT_USIZE.parse_val(""), Ok(ConfigVal::OptUsize(None)));
906 assert_err!(OPT_USIZE.parse_val("5 s"));
907
908 assert_err!(F64.parse_val("true"));
909 assert_err!(F64.parse_val("false"));
910 assert_eq!(F64.parse_val("42"), Ok(ConfigVal::F64(42.0)));
911 assert_eq!(F64.parse_val("66.6"), Ok(ConfigVal::F64(66.6)));
912 assert_err!(F64.parse_val("farragut"));
913 assert_err!(F64.parse_val(""));
914 assert_err!(F64.parse_val("5 s"));
915
916 assert_eq!(
917 STRING.parse_val("true"),
918 Ok(ConfigVal::String("true".to_string()))
919 );
920 assert_eq!(
921 STRING.parse_val("false"),
922 Ok(ConfigVal::String("false".to_string()))
923 );
924 assert_eq!(
925 STRING.parse_val("66.6"),
926 Ok(ConfigVal::String("66.6".to_string()))
927 );
928 assert_eq!(
929 STRING.parse_val("42"),
930 Ok(ConfigVal::String("42".to_string()))
931 );
932 assert_eq!(
933 STRING.parse_val("farragut"),
934 Ok(ConfigVal::String("farragut".to_string()))
935 );
936 assert_eq!(STRING.parse_val(""), Ok(ConfigVal::String("".to_string())));
937 assert_eq!(
938 STRING.parse_val("5 s"),
939 Ok(ConfigVal::String("5 s".to_string()))
940 );
941
942 assert_eq!(
943 OPT_STRING.parse_val("true"),
944 Ok(ConfigVal::OptString(Some("true".to_string())))
945 );
946 assert_eq!(
947 OPT_STRING.parse_val("false"),
948 Ok(ConfigVal::OptString(Some("false".to_string())))
949 );
950 assert_eq!(
951 OPT_STRING.parse_val("66.6"),
952 Ok(ConfigVal::OptString(Some("66.6".to_string())))
953 );
954 assert_eq!(
955 OPT_STRING.parse_val("42"),
956 Ok(ConfigVal::OptString(Some("42".to_string())))
957 );
958 assert_eq!(
959 OPT_STRING.parse_val("farragut"),
960 Ok(ConfigVal::OptString(Some("farragut".to_string())))
961 );
962 assert_eq!(
963 OPT_STRING.parse_val(""),
964 Ok(ConfigVal::OptString(Some("".to_string())))
965 );
966 assert_eq!(
967 OPT_STRING.parse_val("5 s"),
968 Ok(ConfigVal::OptString(Some("5 s".to_string())))
969 );
970
971 assert_err!(DURATION.parse_val("true"));
972 assert_err!(DURATION.parse_val("false"));
973 assert_err!(DURATION.parse_val("42"));
974 assert_err!(DURATION.parse_val("66.6"));
975 assert_err!(DURATION.parse_val("farragut"));
976 assert_err!(DURATION.parse_val(""));
977 assert_eq!(
978 DURATION.parse_val("5 s"),
979 Ok(ConfigVal::Duration(Duration::from_secs(5)))
980 );
981
982 assert_eq!(
983 JSON.parse_val("true"),
984 Ok(ConfigVal::Json(serde_json::json!(true)))
985 );
986 assert_eq!(
987 JSON.parse_val("false"),
988 Ok(ConfigVal::Json(serde_json::json!(false)))
989 );
990 assert_eq!(
991 JSON.parse_val("42"),
992 Ok(ConfigVal::Json(serde_json::json!(42)))
993 );
994 assert_eq!(
995 JSON.parse_val("66.6"),
996 Ok(ConfigVal::Json(serde_json::json!(66.6)))
997 );
998 assert_err!(JSON.parse_val("farragut"));
999 assert_err!(JSON.parse_val(""));
1000 assert_err!(JSON.parse_val("5 s"));
1001 assert_eq!(
1002 JSON.parse_val("{\"joe\": \"developer\"}"),
1003 Ok(ConfigVal::Json(serde_json::json!({"joe": "developer"})))
1004 );
1005 }
1006}