1use std::{any, borrow::Cow, fmt, ops, time::Duration};
4
5use self::_private::{BoxedDeserializer, BoxedVisitor};
6use crate::{
7 de::{_private::ErasedDeserializer, DeserializeParam},
8 fallback::FallbackSource,
9 pat::PatternDisplay,
10 validation::Validate,
11};
12
13#[doc(hidden)] pub mod _private;
15#[cfg(test)]
16mod tests;
17
18#[derive(Debug, Clone, Copy)]
20#[cfg_attr(test, derive(PartialEq))]
21#[non_exhaustive]
22pub struct AliasOptions {
23 pub is_deprecated: bool,
25}
26
27impl Default for AliasOptions {
28 fn default() -> Self {
29 Self::new()
30 }
31}
32
33impl AliasOptions {
34 pub const fn new() -> Self {
36 AliasOptions {
37 is_deprecated: false,
38 }
39 }
40
41 #[must_use]
43 pub const fn deprecated(mut self) -> Self {
44 self.is_deprecated = true;
45 self
46 }
47
48 #[doc(hidden)] #[must_use]
50 pub fn combine(self, other: Self) -> Self {
51 Self {
52 is_deprecated: self.is_deprecated || other.is_deprecated,
53 }
54 }
55}
56
57#[derive(Debug, Clone)]
59pub struct ConfigMetadata {
60 pub ty: RustType,
62 pub help: &'static str,
64 pub params: &'static [ParamMetadata],
66 pub tag: Option<ConfigTag>,
68 pub nested_configs: &'static [NestedConfigMetadata],
70 #[doc(hidden)] pub deserializer: BoxedDeserializer,
72 #[doc(hidden)] pub visitor: BoxedVisitor,
74 #[doc(hidden)] pub validations: &'static [&'static dyn Validate<dyn any::Any>],
76}
77
78#[derive(Debug, Clone, Copy)]
80pub struct ConfigTag {
81 pub param: &'static ParamMetadata,
83 pub variants: &'static [ConfigVariant],
85 pub default_variant: Option<&'static ConfigVariant>,
87}
88
89#[derive(Debug, Clone, Copy)]
91pub struct ConfigVariant {
92 pub name: &'static str,
94 pub aliases: &'static [&'static str],
96 pub rust_name: &'static str,
98 pub help: &'static str,
100}
101
102#[derive(Debug, Clone, Copy)]
104pub struct ParamMetadata {
105 pub name: &'static str,
107 pub aliases: &'static [(&'static str, AliasOptions)],
109 pub help: &'static str,
111 pub rust_field_name: &'static str,
113 pub rust_type: RustType,
115 pub expecting: BasicTypes,
117 pub tag_variant: Option<&'static ConfigVariant>,
119 #[doc(hidden)] pub deserializer: &'static dyn ErasedDeserializer,
121 #[doc(hidden)] pub default_value: Option<fn() -> Box<dyn any::Any>>,
123 #[doc(hidden)] pub example_value: Option<fn() -> Box<dyn any::Any>>,
125 #[doc(hidden)]
126 pub fallback: Option<&'static dyn FallbackSource>,
127}
128
129impl ParamMetadata {
130 pub fn default_value(&self) -> Option<Box<dyn any::Any>> {
132 self.default_value.map(|value_fn| value_fn())
133 }
134
135 pub fn default_value_json(&self) -> Option<serde_json::Value> {
137 self.default_value()
138 .map(|val| self.deserializer.serialize_param(val.as_ref()))
139 }
140
141 pub fn example_value_json(&self) -> Option<serde_json::Value> {
143 let example = self.example_value?();
144 Some(self.deserializer.serialize_param(example.as_ref()))
145 }
146
147 pub fn type_description(&self) -> TypeDescription {
150 let mut description = TypeDescription::default();
151 self.deserializer.describe(&mut description);
152 description.rust_type = self.rust_type.name_in_code;
153 description
154 }
155}
156
157#[derive(Clone, Copy)]
159pub struct RustType {
160 id: fn() -> any::TypeId,
161 name_in_code: &'static str,
162}
163
164impl fmt::Debug for RustType {
165 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
166 formatter.write_str(self.name_in_code)
167 }
168}
169
170impl PartialEq for RustType {
171 fn eq(&self, other: &Self) -> bool {
172 (self.id)() == (other.id)()
173 }
174}
175
176impl RustType {
177 #[allow(clippy::incompatible_msrv)] pub const fn of<T: 'static>(name_in_code: &'static str) -> Self {
180 Self {
181 id: any::TypeId::of::<T>,
182 name_in_code,
183 }
184 }
185
186 pub fn id(&self) -> any::TypeId {
188 (self.id)()
189 }
190
191 pub const fn name_in_code(&self) -> &'static str {
193 self.name_in_code
194 }
195}
196
197#[derive(Clone, Copy, PartialEq, Eq, Hash)]
199pub struct BasicTypes(u8);
200
201impl BasicTypes {
202 pub const BOOL: Self = Self(1);
204 pub const INTEGER: Self = Self(2);
206 pub const FLOAT: Self = Self(4 | 2);
208 pub const STRING: Self = Self(8);
210 pub const ARRAY: Self = Self(16);
212 pub const OBJECT: Self = Self(32);
214 pub const ANY: Self = Self(63);
216
217 const COMPONENTS: &'static [(Self, &'static str)] = &[
218 (Self::BOOL, "Boolean"),
219 (Self::INTEGER, "integer"),
220 (Self::FLOAT, "float"),
221 (Self::STRING, "string"),
222 (Self::ARRAY, "array"),
223 (Self::OBJECT, "object"),
224 ];
225
226 pub(crate) const fn from_raw(raw: u8) -> Self {
227 assert!(raw != 0, "Raw `BasicTypes` cannot be 0");
228 assert!(
229 raw <= Self::ANY.0,
230 "Unused set bits in `BasicTypes` raw value"
231 );
232 Self(raw)
233 }
234
235 #[doc(hidden)] pub const fn raw(self) -> u8 {
237 self.0
238 }
239
240 #[must_use]
242 pub const fn or(self, rhs: Self) -> Self {
243 Self(self.0 | rhs.0)
244 }
245
246 pub const fn contains(self, needle: Self) -> bool {
248 self.0 & needle.0 == needle.0
249 }
250}
251
252impl fmt::Display for BasicTypes {
253 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
254 if *self == Self::ANY {
255 formatter.write_str("any")
256 } else {
257 let mut is_empty = true;
258 for &(component, name) in Self::COMPONENTS {
259 if self.contains(component) {
260 if !is_empty {
261 formatter.write_str(" | ")?;
262 }
263 formatter.write_str(name)?;
264 is_empty = false;
265 }
266 }
267 Ok(())
268 }
269 }
270}
271
272impl fmt::Debug for BasicTypes {
273 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
274 fmt::Display::fmt(self, formatter)
275 }
276}
277
278#[derive(Debug, Clone)]
279struct ChildDescription {
280 expecting: BasicTypes,
281 description: Box<TypeDescription>,
282}
283
284impl ChildDescription {
285 fn new<T: 'static, De: DeserializeParam<T>>(deserializer: &De, set_type: bool) -> Self {
286 let mut description = Box::default();
287 deserializer.describe(&mut description);
288 if set_type {
289 description.rust_type = any::type_name::<T>();
290 }
291 Self {
292 expecting: De::EXPECTING,
293 description,
294 }
295 }
296}
297
298#[derive(Debug, Clone, Copy)]
301#[non_exhaustive]
302#[doc(hidden)] pub enum TypeSuffixes {
304 All,
306 DurationUnits,
308 SizeUnits,
310 EtherUnits,
312}
313
314#[derive(Debug, Clone)]
315struct Items {
316 description: ChildDescription,
317 sep: Option<PatternDisplay>,
318}
319
320#[derive(Debug, Clone)]
321struct Entries {
322 keys: ChildDescription,
323 values: ChildDescription,
324 sep: Option<(PatternDisplay, PatternDisplay)>,
325}
326
327#[derive(Debug, Clone, Default)]
332pub struct TypeDescription {
333 rust_type: &'static str,
334 details: Option<Cow<'static, str>>,
335 unit: Option<UnitOfMeasurement>,
336 suffixes: Option<TypeSuffixes>,
337 pub(crate) is_secret: bool,
338 validations: Vec<String>,
339 deserialize_if: Option<String>,
340 items: Option<Items>,
341 entries: Option<Entries>,
342 fallback: Option<ChildDescription>,
343}
344
345impl TypeDescription {
346 #[doc(hidden)]
347 pub fn rust_type(&self) -> &str {
348 self.rust_type
349 }
350
351 pub fn details(&self) -> Option<&str> {
353 self.details.as_deref()
354 }
355
356 pub fn unit(&self) -> Option<UnitOfMeasurement> {
358 self.unit
359 }
360
361 #[doc(hidden)] pub fn suffixes(&self) -> Option<TypeSuffixes> {
363 self.suffixes
364 }
365
366 #[doc(hidden)] pub fn validations(&self) -> &[String] {
368 &self.validations
369 }
370
371 #[doc(hidden)] pub fn deserialize_if(&self) -> Option<&str> {
373 self.deserialize_if.as_deref()
374 }
375
376 pub fn items(&self) -> Option<(BasicTypes, &Self)> {
378 self.items
379 .as_ref()
380 .map(|child| (child.description.expecting, &*child.description.description))
381 }
382
383 #[doc(hidden)] pub fn item_separator(&self) -> Option<&PatternDisplay> {
386 self.items.as_ref()?.sep.as_ref()
387 }
388
389 pub fn keys(&self) -> Option<(BasicTypes, &Self)> {
391 let keys = &self.entries.as_ref()?.keys;
392 Some((keys.expecting, &*keys.description))
393 }
394
395 pub fn values(&self) -> Option<(BasicTypes, &Self)> {
397 let keys = &self.entries.as_ref()?.values;
398 Some((keys.expecting, &*keys.description))
399 }
400
401 #[doc(hidden)] pub fn entry_separators(&self) -> Option<(&PatternDisplay, &PatternDisplay)> {
405 let entries = self.entries.as_ref()?;
406 entries.sep.as_ref().map(|(entries, kv)| (entries, kv))
407 }
408
409 pub fn fallback(&self) -> Option<(BasicTypes, &Self)> {
411 let fallback = self.fallback.as_ref()?;
412 Some((fallback.expecting, &*fallback.description))
413 }
414
415 pub fn contains_secrets(&self) -> bool {
418 if self.is_secret {
419 return true;
420 }
421 if let Some(item) = &self.items
422 && item.description.description.contains_secrets()
423 {
424 return true;
425 }
426 if let Some(Entries { keys, values, .. }) = &self.entries {
427 if keys.description.contains_secrets() {
428 return true;
429 }
430 if values.description.contains_secrets() {
431 return true;
432 }
433 }
434 false
435 }
436
437 pub fn set_details(&mut self, details: impl Into<Cow<'static, str>>) -> &mut Self {
439 self.details = Some(details.into());
440 self
441 }
442
443 pub fn set_unit(&mut self, unit: UnitOfMeasurement) -> &mut Self {
445 self.unit = Some(unit);
446 self
447 }
448
449 pub(crate) fn set_suffixes(&mut self, suffixes: TypeSuffixes) -> &mut Self {
450 self.suffixes = Some(suffixes);
451 self
452 }
453
454 pub fn set_validations<T>(&mut self, validations: &[&'static dyn Validate<T>]) -> &mut Self {
456 self.validations = validations.iter().map(ToString::to_string).collect();
457 self
458 }
459
460 pub fn set_deserialize_if<T>(&mut self, condition: &'static dyn Validate<T>) -> &mut Self {
462 self.deserialize_if = Some(condition.to_string());
463 self
464 }
465
466 pub fn set_secret(&mut self) -> &mut Self {
468 self.is_secret = true;
469 self
470 }
471
472 pub fn set_items<T: 'static>(&mut self, items: &impl DeserializeParam<T>) -> &mut Self {
474 self.items = Some(Items {
475 description: ChildDescription::new(items, true),
476 sep: None,
477 });
478 self
479 }
480
481 pub(crate) fn set_items_sep(&mut self, separator: PatternDisplay) {
482 if let Some(items) = &mut self.items {
483 items.sep = Some(separator);
484 }
485 }
486
487 pub fn set_entries<K: 'static, V: 'static>(
489 &mut self,
490 keys: &impl DeserializeParam<K>,
491 values: &impl DeserializeParam<V>,
492 ) -> &mut Self {
493 self.entries = Some(Entries {
494 keys: ChildDescription::new(keys, true),
495 values: ChildDescription::new(values, true),
496 sep: None,
497 });
498 self
499 }
500
501 pub(crate) fn set_entries_sep(&mut self, entries: PatternDisplay, kv: PatternDisplay) {
502 if let Some(items) = &mut self.entries {
503 items.sep = Some((entries, kv));
504 }
505 }
506
507 pub fn set_fallback<T: 'static>(&mut self, fallback: &impl DeserializeParam<T>) {
509 self.fallback = Some(ChildDescription::new(fallback, false));
510 }
511}
512
513impl fmt::Display for TypeDescription {
514 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
515 if let Some(description) = &self.details {
516 write!(formatter, ", {description}")?;
517 }
518 if let Some(unit) = self.unit {
519 write!(formatter, " [unit: {unit}]")?;
520 }
521 Ok(())
522 }
523}
524
525#[derive(Debug, Clone, Copy)]
527pub struct NestedConfigMetadata {
528 pub name: &'static str,
530 pub aliases: &'static [(&'static str, AliasOptions)],
532 pub rust_field_name: &'static str,
534 pub tag_variant: Option<&'static ConfigVariant>,
536 pub meta: &'static ConfigMetadata,
538}
539
540#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
553#[non_exhaustive]
554pub enum TimeUnit {
555 Millis,
557 Seconds,
559 Minutes,
561 Hours,
563 Days,
565 Weeks,
567 }
569
570impl TimeUnit {
571 pub(crate) fn plural(self) -> &'static str {
572 match self {
573 TimeUnit::Millis => "milliseconds",
574 TimeUnit::Seconds => "seconds",
575 TimeUnit::Minutes => "minutes",
576 TimeUnit::Hours => "hours",
577 TimeUnit::Days => "days",
578 TimeUnit::Weeks => "weeks",
579 }
580 }
581
582 pub fn checked_mul(self, factor: u64) -> Option<Duration> {
584 Some(match self {
585 Self::Millis => Duration::from_millis(factor),
586 Self::Seconds => Duration::from_secs(factor),
587 Self::Minutes => {
588 let val = factor.checked_mul(60)?;
589 Duration::from_secs(val)
590 }
591 Self::Hours => {
592 let val = factor.checked_mul(3_600)?;
593 Duration::from_secs(val)
594 }
595 Self::Days => {
596 let val = factor.checked_mul(86_400)?;
597 Duration::from_secs(val)
598 }
599 Self::Weeks => {
600 let val = factor.checked_mul(86_400 * 7)?;
601 Duration::from_secs(val)
602 }
603 })
604 }
605}
606
607impl fmt::Display for TimeUnit {
608 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
609 formatter.write_str(self.plural())
610 }
611}
612
613impl From<TimeUnit> for Duration {
614 fn from(unit: TimeUnit) -> Self {
615 match unit {
616 TimeUnit::Millis => Duration::from_millis(1),
617 TimeUnit::Seconds => Duration::from_secs(1),
618 TimeUnit::Minutes => Duration::from_secs(60),
619 TimeUnit::Hours => Duration::from_secs(3_600),
620 TimeUnit::Days => Duration::from_secs(86_400),
621 TimeUnit::Weeks => Duration::from_secs(86_400 * 7),
622 }
623 }
624}
625
626impl ops::Mul<u64> for TimeUnit {
628 type Output = Duration;
629
630 fn mul(self, rhs: u64) -> Self::Output {
631 self.checked_mul(rhs)
632 .unwrap_or_else(|| panic!("Integer overflow getting {rhs} * {self}"))
633 }
634}
635
636impl ops::Mul<TimeUnit> for u64 {
638 type Output = Duration;
639
640 fn mul(self, rhs: TimeUnit) -> Self::Output {
641 rhs.checked_mul(self)
642 .unwrap_or_else(|| panic!("Integer overflow getting {self} * {rhs}"))
643 }
644}
645
646#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
648#[non_exhaustive]
649pub enum SizeUnit {
650 Bytes,
652 KiB,
654 MiB,
656 GiB,
658}
659
660impl SizeUnit {
661 pub(crate) const fn as_str(self) -> &'static str {
662 match self {
663 Self::Bytes => "bytes",
664 Self::KiB => "kilobytes",
665 Self::MiB => "megabytes",
666 Self::GiB => "gigabytes",
667 }
668 }
669
670 pub(crate) const fn value_in_unit(self) -> u64 {
671 match self {
672 Self::Bytes => 1,
673 Self::KiB => 1_024,
674 Self::MiB => 1_024 * 1_024,
675 Self::GiB => 1_024 * 1_024 * 1_024,
676 }
677 }
678}
679
680impl fmt::Display for SizeUnit {
681 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
682 formatter.write_str(self.as_str())
683 }
684}
685
686#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
688#[non_exhaustive]
689pub enum EtherUnit {
690 Wei,
692 Gwei,
694 Ether,
696}
697
698impl fmt::Display for EtherUnit {
699 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
700 formatter.write_str(self.as_str())
701 }
702}
703
704impl EtherUnit {
705 pub(crate) const fn value_in_unit(self) -> u128 {
706 match self {
707 Self::Wei => 1,
708 Self::Gwei => 1_000_000_000,
709 Self::Ether => 1_000_000_000_000_000_000,
710 }
711 }
712
713 pub(crate) const fn as_str(self) -> &'static str {
714 match self {
715 Self::Wei => "wei",
716 Self::Gwei => "gwei",
717 Self::Ether => "ether",
718 }
719 }
720}
721
722#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
724#[non_exhaustive]
725pub enum UnitOfMeasurement {
726 Time(TimeUnit),
728 ByteSize(SizeUnit),
730 Ether(EtherUnit),
732}
733
734impl fmt::Display for UnitOfMeasurement {
735 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
736 match self {
737 Self::Time(unit) => fmt::Display::fmt(unit, formatter),
738 Self::ByteSize(unit) => fmt::Display::fmt(unit, formatter),
739 Self::Ether(unit) => fmt::Display::fmt(unit, formatter),
740 }
741 }
742}
743
744impl From<TimeUnit> for UnitOfMeasurement {
745 fn from(unit: TimeUnit) -> Self {
746 Self::Time(unit)
747 }
748}
749
750impl From<SizeUnit> for UnitOfMeasurement {
751 fn from(unit: SizeUnit) -> Self {
752 Self::ByteSize(unit)
753 }
754}
755
756impl From<EtherUnit> for UnitOfMeasurement {
757 fn from(unit: EtherUnit) -> Self {
758 Self::Ether(unit)
759 }
760}