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 pub shorthand: Option<ConfigShorthand>,
89}
90
91#[derive(Debug, Clone, Copy)]
94pub struct ConfigShorthand {
95 pub variant: &'static ConfigVariant,
97 pub param: &'static ParamMetadata,
99}
100
101#[derive(Debug, Clone, Copy)]
103pub struct ConfigVariant {
104 pub name: &'static str,
106 pub aliases: &'static [&'static str],
108 pub rust_name: &'static str,
110 pub help: &'static str,
112}
113
114#[derive(Debug, Clone, Copy)]
116pub struct ParamMetadata {
117 pub name: &'static str,
119 pub aliases: &'static [(&'static str, AliasOptions)],
121 pub help: &'static str,
123 pub rust_field_name: &'static str,
125 pub rust_type: RustType,
127 pub expecting: BasicTypes,
129 pub tag_variant: Option<&'static ConfigVariant>,
131 #[doc(hidden)] pub deserializer: &'static dyn ErasedDeserializer,
133 #[doc(hidden)] pub default_value: Option<fn() -> Box<dyn any::Any>>,
135 #[doc(hidden)] pub example_value: Option<fn() -> Box<dyn any::Any>>,
137 #[doc(hidden)]
138 pub fallback: Option<&'static dyn FallbackSource>,
139}
140
141impl ParamMetadata {
142 pub fn default_value(&self) -> Option<Box<dyn any::Any>> {
144 self.default_value.map(|value_fn| value_fn())
145 }
146
147 pub fn default_value_json(&self) -> Option<serde_json::Value> {
149 self.default_value()
150 .map(|val| self.deserializer.serialize_param(val.as_ref()))
151 }
152
153 pub fn example_value_json(&self) -> Option<serde_json::Value> {
155 let example = self.example_value?();
156 Some(self.deserializer.serialize_param(example.as_ref()))
157 }
158
159 pub fn type_description(&self) -> TypeDescription {
162 let mut description = TypeDescription::default();
163 self.deserializer.describe(&mut description);
164 description.rust_type = self.rust_type.name_in_code;
165 description
166 }
167}
168
169#[derive(Clone, Copy)]
171pub struct RustType {
172 id: fn() -> any::TypeId,
173 name_in_code: &'static str,
174}
175
176impl fmt::Debug for RustType {
177 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
178 formatter.write_str(self.name_in_code)
179 }
180}
181
182impl PartialEq for RustType {
183 fn eq(&self, other: &Self) -> bool {
184 (self.id)() == (other.id)()
185 }
186}
187
188impl RustType {
189 #[allow(clippy::incompatible_msrv)] pub const fn of<T: 'static>(name_in_code: &'static str) -> Self {
192 Self {
193 id: any::TypeId::of::<T>,
194 name_in_code,
195 }
196 }
197
198 pub fn id(&self) -> any::TypeId {
200 (self.id)()
201 }
202
203 pub const fn name_in_code(&self) -> &'static str {
205 self.name_in_code
206 }
207}
208
209#[derive(Clone, Copy, PartialEq, Eq, Hash)]
211pub struct BasicTypes(u8);
212
213impl BasicTypes {
214 pub const BOOL: Self = Self(1);
216 pub const INTEGER: Self = Self(2);
218 pub const FLOAT: Self = Self(4 | 2);
220 pub const STRING: Self = Self(8);
222 pub const ARRAY: Self = Self(16);
224 pub const OBJECT: Self = Self(32);
226 pub const ANY: Self = Self(63);
228
229 const COMPONENTS: &'static [(Self, &'static str)] = &[
230 (Self::BOOL, "Boolean"),
231 (Self::INTEGER, "integer"),
232 (Self::FLOAT, "float"),
233 (Self::STRING, "string"),
234 (Self::ARRAY, "array"),
235 (Self::OBJECT, "object"),
236 ];
237
238 pub(crate) const fn from_raw(raw: u8) -> Self {
239 assert!(raw != 0, "Raw `BasicTypes` cannot be 0");
240 assert!(
241 raw <= Self::ANY.0,
242 "Unused set bits in `BasicTypes` raw value"
243 );
244 Self(raw)
245 }
246
247 #[doc(hidden)] pub const fn raw(self) -> u8 {
249 self.0
250 }
251
252 #[must_use]
254 pub const fn or(self, rhs: Self) -> Self {
255 Self(self.0 | rhs.0)
256 }
257
258 pub const fn contains(self, needle: Self) -> bool {
260 self.0 & needle.0 == needle.0
261 }
262}
263
264impl fmt::Display for BasicTypes {
265 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
266 if *self == Self::ANY {
267 formatter.write_str("any")
268 } else {
269 let mut is_empty = true;
270 for &(component, name) in Self::COMPONENTS {
271 if self.contains(component) {
272 if !is_empty {
273 formatter.write_str(" | ")?;
274 }
275 formatter.write_str(name)?;
276 is_empty = false;
277 }
278 }
279 Ok(())
280 }
281 }
282}
283
284impl fmt::Debug for BasicTypes {
285 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
286 fmt::Display::fmt(self, formatter)
287 }
288}
289
290#[derive(Debug, Clone)]
291struct ChildDescription {
292 expecting: BasicTypes,
293 description: Box<TypeDescription>,
294}
295
296impl ChildDescription {
297 fn new<T: 'static, De: DeserializeParam<T>>(deserializer: &De, set_type: bool) -> Self {
298 let mut description = Box::default();
299 deserializer.describe(&mut description);
300 if set_type {
301 description.rust_type = any::type_name::<T>();
302 }
303 Self {
304 expecting: De::EXPECTING,
305 description,
306 }
307 }
308}
309
310#[derive(Debug, Clone, Copy)]
313#[non_exhaustive]
314#[doc(hidden)] pub enum TypeSuffixes {
316 All,
318 DurationUnits,
320 SizeUnits,
322 EtherUnits,
324}
325
326#[derive(Debug, Clone)]
327struct Items {
328 description: ChildDescription,
329 sep: Option<PatternDisplay>,
330}
331
332#[derive(Debug, Clone)]
333struct Entries {
334 keys: ChildDescription,
335 values: ChildDescription,
336 sep: Option<(PatternDisplay, PatternDisplay)>,
337}
338
339#[derive(Debug, Clone, Default)]
344pub struct TypeDescription {
345 rust_type: &'static str,
346 details: Option<Cow<'static, str>>,
347 unit: Option<UnitOfMeasurement>,
348 suffixes: Option<TypeSuffixes>,
349 pub(crate) is_secret: bool,
350 validations: Vec<String>,
351 deserialize_if: Option<String>,
352 items: Option<Items>,
353 entries: Option<Entries>,
354 fallback: Option<ChildDescription>,
355}
356
357impl TypeDescription {
358 #[doc(hidden)]
359 pub fn rust_type(&self) -> &str {
360 self.rust_type
361 }
362
363 pub fn details(&self) -> Option<&str> {
365 self.details.as_deref()
366 }
367
368 pub fn unit(&self) -> Option<UnitOfMeasurement> {
370 self.unit
371 }
372
373 #[doc(hidden)] pub fn suffixes(&self) -> Option<TypeSuffixes> {
375 self.suffixes
376 }
377
378 #[doc(hidden)] pub fn validations(&self) -> &[String] {
380 &self.validations
381 }
382
383 #[doc(hidden)] pub fn deserialize_if(&self) -> Option<&str> {
385 self.deserialize_if.as_deref()
386 }
387
388 pub fn items(&self) -> Option<(BasicTypes, &Self)> {
390 self.items
391 .as_ref()
392 .map(|child| (child.description.expecting, &*child.description.description))
393 }
394
395 #[doc(hidden)] pub fn item_separator(&self) -> Option<&PatternDisplay> {
398 self.items.as_ref()?.sep.as_ref()
399 }
400
401 pub fn keys(&self) -> Option<(BasicTypes, &Self)> {
403 let keys = &self.entries.as_ref()?.keys;
404 Some((keys.expecting, &*keys.description))
405 }
406
407 pub fn values(&self) -> Option<(BasicTypes, &Self)> {
409 let keys = &self.entries.as_ref()?.values;
410 Some((keys.expecting, &*keys.description))
411 }
412
413 #[doc(hidden)] pub fn entry_separators(&self) -> Option<(&PatternDisplay, &PatternDisplay)> {
417 let entries = self.entries.as_ref()?;
418 entries.sep.as_ref().map(|(entries, kv)| (entries, kv))
419 }
420
421 pub fn fallback(&self) -> Option<(BasicTypes, &Self)> {
423 let fallback = self.fallback.as_ref()?;
424 Some((fallback.expecting, &*fallback.description))
425 }
426
427 pub fn contains_secrets(&self) -> bool {
430 if self.is_secret {
431 return true;
432 }
433 if let Some(item) = &self.items
434 && item.description.description.contains_secrets()
435 {
436 return true;
437 }
438 if let Some(Entries { keys, values, .. }) = &self.entries {
439 if keys.description.contains_secrets() {
440 return true;
441 }
442 if values.description.contains_secrets() {
443 return true;
444 }
445 }
446 false
447 }
448
449 pub fn set_details(&mut self, details: impl Into<Cow<'static, str>>) -> &mut Self {
451 self.details = Some(details.into());
452 self
453 }
454
455 pub fn set_unit(&mut self, unit: UnitOfMeasurement) -> &mut Self {
457 self.unit = Some(unit);
458 self
459 }
460
461 pub(crate) fn set_suffixes(&mut self, suffixes: TypeSuffixes) -> &mut Self {
462 self.suffixes = Some(suffixes);
463 self
464 }
465
466 pub fn set_validations<T>(&mut self, validations: &[&'static dyn Validate<T>]) -> &mut Self {
468 self.validations = validations.iter().map(ToString::to_string).collect();
469 self
470 }
471
472 pub fn set_deserialize_if<T>(&mut self, condition: &'static dyn Validate<T>) -> &mut Self {
474 self.deserialize_if = Some(condition.to_string());
475 self
476 }
477
478 pub fn set_secret(&mut self) -> &mut Self {
480 self.is_secret = true;
481 self
482 }
483
484 pub fn set_items<T: 'static>(&mut self, items: &impl DeserializeParam<T>) -> &mut Self {
486 self.items = Some(Items {
487 description: ChildDescription::new(items, true),
488 sep: None,
489 });
490 self
491 }
492
493 pub(crate) fn set_items_sep(&mut self, separator: PatternDisplay) {
494 if let Some(items) = &mut self.items {
495 items.sep = Some(separator);
496 }
497 }
498
499 pub fn set_entries<K: 'static, V: 'static>(
501 &mut self,
502 keys: &impl DeserializeParam<K>,
503 values: &impl DeserializeParam<V>,
504 ) -> &mut Self {
505 self.entries = Some(Entries {
506 keys: ChildDescription::new(keys, true),
507 values: ChildDescription::new(values, true),
508 sep: None,
509 });
510 self
511 }
512
513 pub(crate) fn set_entries_sep(&mut self, entries: PatternDisplay, kv: PatternDisplay) {
514 if let Some(items) = &mut self.entries {
515 items.sep = Some((entries, kv));
516 }
517 }
518
519 pub fn set_fallback<T: 'static>(&mut self, fallback: &impl DeserializeParam<T>) {
521 self.fallback = Some(ChildDescription::new(fallback, false));
522 }
523}
524
525impl fmt::Display for TypeDescription {
526 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
527 if let Some(description) = &self.details {
528 write!(formatter, ", {description}")?;
529 }
530 if let Some(unit) = self.unit {
531 write!(formatter, " [unit: {unit}]")?;
532 }
533 Ok(())
534 }
535}
536
537#[derive(Debug, Clone, Copy)]
539pub struct NestedConfigMetadata {
540 pub name: &'static str,
542 pub aliases: &'static [(&'static str, AliasOptions)],
544 pub rust_field_name: &'static str,
546 pub tag_variant: Option<&'static ConfigVariant>,
548 pub meta: &'static ConfigMetadata,
550}
551
552#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
565#[non_exhaustive]
566pub enum TimeUnit {
567 Millis,
569 Seconds,
571 Minutes,
573 Hours,
575 Days,
577 Weeks,
579 }
581
582impl TimeUnit {
583 pub(crate) fn plural(self) -> &'static str {
584 match self {
585 TimeUnit::Millis => "milliseconds",
586 TimeUnit::Seconds => "seconds",
587 TimeUnit::Minutes => "minutes",
588 TimeUnit::Hours => "hours",
589 TimeUnit::Days => "days",
590 TimeUnit::Weeks => "weeks",
591 }
592 }
593
594 pub fn checked_mul(self, factor: u64) -> Option<Duration> {
596 Some(match self {
597 Self::Millis => Duration::from_millis(factor),
598 Self::Seconds => Duration::from_secs(factor),
599 Self::Minutes => {
600 let val = factor.checked_mul(60)?;
601 Duration::from_secs(val)
602 }
603 Self::Hours => {
604 let val = factor.checked_mul(3_600)?;
605 Duration::from_secs(val)
606 }
607 Self::Days => {
608 let val = factor.checked_mul(86_400)?;
609 Duration::from_secs(val)
610 }
611 Self::Weeks => {
612 let val = factor.checked_mul(86_400 * 7)?;
613 Duration::from_secs(val)
614 }
615 })
616 }
617}
618
619impl fmt::Display for TimeUnit {
620 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
621 formatter.write_str(self.plural())
622 }
623}
624
625impl From<TimeUnit> for Duration {
626 fn from(unit: TimeUnit) -> Self {
627 match unit {
628 TimeUnit::Millis => Duration::from_millis(1),
629 TimeUnit::Seconds => Duration::from_secs(1),
630 TimeUnit::Minutes => Duration::from_mins(1),
631 TimeUnit::Hours => Duration::from_hours(1),
632 TimeUnit::Days => Duration::from_hours(24),
633 TimeUnit::Weeks => Duration::from_hours(24 * 7),
634 }
635 }
636}
637
638impl ops::Mul<u64> for TimeUnit {
640 type Output = Duration;
641
642 fn mul(self, rhs: u64) -> Self::Output {
643 self.checked_mul(rhs)
644 .unwrap_or_else(|| panic!("Integer overflow getting {rhs} * {self}"))
645 }
646}
647
648impl ops::Mul<TimeUnit> for u64 {
650 type Output = Duration;
651
652 fn mul(self, rhs: TimeUnit) -> Self::Output {
653 rhs.checked_mul(self)
654 .unwrap_or_else(|| panic!("Integer overflow getting {self} * {rhs}"))
655 }
656}
657
658#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
660#[non_exhaustive]
661pub enum SizeUnit {
662 Bytes,
664 KiB,
666 MiB,
668 GiB,
670}
671
672impl SizeUnit {
673 pub(crate) const fn as_str(self) -> &'static str {
674 match self {
675 Self::Bytes => "bytes",
676 Self::KiB => "kilobytes",
677 Self::MiB => "megabytes",
678 Self::GiB => "gigabytes",
679 }
680 }
681
682 pub(crate) const fn value_in_unit(self) -> u64 {
683 match self {
684 Self::Bytes => 1,
685 Self::KiB => 1_024,
686 Self::MiB => 1_024 * 1_024,
687 Self::GiB => 1_024 * 1_024 * 1_024,
688 }
689 }
690}
691
692impl fmt::Display for SizeUnit {
693 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
694 formatter.write_str(self.as_str())
695 }
696}
697
698#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
700#[non_exhaustive]
701pub enum EtherUnit {
702 Wei,
704 Gwei,
706 Ether,
708}
709
710impl fmt::Display for EtherUnit {
711 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
712 formatter.write_str(self.as_str())
713 }
714}
715
716impl EtherUnit {
717 pub(crate) const fn value_in_unit(self) -> u128 {
718 match self {
719 Self::Wei => 1,
720 Self::Gwei => 1_000_000_000,
721 Self::Ether => 1_000_000_000_000_000_000,
722 }
723 }
724
725 pub(crate) const fn as_str(self) -> &'static str {
726 match self {
727 Self::Wei => "wei",
728 Self::Gwei => "gwei",
729 Self::Ether => "ether",
730 }
731 }
732}
733
734#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
736#[non_exhaustive]
737pub enum UnitOfMeasurement {
738 Time(TimeUnit),
740 ByteSize(SizeUnit),
742 Ether(EtherUnit),
744}
745
746impl fmt::Display for UnitOfMeasurement {
747 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
748 match self {
749 Self::Time(unit) => fmt::Display::fmt(unit, formatter),
750 Self::ByteSize(unit) => fmt::Display::fmt(unit, formatter),
751 Self::Ether(unit) => fmt::Display::fmt(unit, formatter),
752 }
753 }
754}
755
756impl From<TimeUnit> for UnitOfMeasurement {
757 fn from(unit: TimeUnit) -> Self {
758 Self::Time(unit)
759 }
760}
761
762impl From<SizeUnit> for UnitOfMeasurement {
763 fn from(unit: SizeUnit) -> Self {
764 Self::ByteSize(unit)
765 }
766}
767
768impl From<EtherUnit> for UnitOfMeasurement {
769 fn from(unit: EtherUnit) -> Self {
770 Self::Ether(unit)
771 }
772}