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 validation::Validate,
10};
11
12#[doc(hidden)] pub mod _private;
14#[cfg(test)]
15mod tests;
16
17#[derive(Debug, Clone, Copy)]
19#[cfg_attr(test, derive(PartialEq))]
20#[non_exhaustive]
21pub struct AliasOptions {
22 pub is_deprecated: bool,
24}
25
26impl Default for AliasOptions {
27 fn default() -> Self {
28 Self::new()
29 }
30}
31
32impl AliasOptions {
33 pub const fn new() -> Self {
35 AliasOptions {
36 is_deprecated: false,
37 }
38 }
39
40 #[must_use]
42 pub const fn deprecated(mut self) -> Self {
43 self.is_deprecated = true;
44 self
45 }
46
47 #[doc(hidden)] #[must_use]
49 pub fn combine(self, other: Self) -> Self {
50 Self {
51 is_deprecated: self.is_deprecated || other.is_deprecated,
52 }
53 }
54}
55
56#[derive(Debug, Clone)]
58pub struct ConfigMetadata {
59 pub ty: RustType,
61 pub help: &'static str,
63 pub params: &'static [ParamMetadata],
65 pub tag: Option<ConfigTag>,
67 pub nested_configs: &'static [NestedConfigMetadata],
69 #[doc(hidden)] pub deserializer: BoxedDeserializer,
71 #[doc(hidden)] pub visitor: BoxedVisitor,
73 #[doc(hidden)] pub validations: &'static [&'static dyn Validate<dyn any::Any>],
75}
76
77#[derive(Debug, Clone, Copy)]
79pub struct ConfigTag {
80 pub param: &'static ParamMetadata,
82 pub variants: &'static [ConfigVariant],
84 pub default_variant: Option<&'static ConfigVariant>,
86}
87
88#[derive(Debug, Clone, Copy)]
90pub struct ConfigVariant {
91 pub name: &'static str,
93 pub aliases: &'static [&'static str],
95 pub rust_name: &'static str,
97 pub help: &'static str,
99}
100
101#[derive(Debug, Clone, Copy)]
103pub struct ParamMetadata {
104 pub name: &'static str,
106 pub aliases: &'static [(&'static str, AliasOptions)],
108 pub help: &'static str,
110 pub rust_field_name: &'static str,
112 pub rust_type: RustType,
114 pub expecting: BasicTypes,
116 pub tag_variant: Option<&'static ConfigVariant>,
118 #[doc(hidden)] pub deserializer: &'static dyn ErasedDeserializer,
120 #[doc(hidden)] pub default_value: Option<fn() -> Box<dyn any::Any>>,
122 #[doc(hidden)] pub example_value: Option<fn() -> Box<dyn any::Any>>,
124 #[doc(hidden)]
125 pub fallback: Option<&'static dyn FallbackSource>,
126}
127
128impl ParamMetadata {
129 pub fn default_value(&self) -> Option<Box<dyn any::Any>> {
131 self.default_value.map(|value_fn| value_fn())
132 }
133
134 pub fn default_value_json(&self) -> Option<serde_json::Value> {
136 self.default_value()
137 .map(|val| self.deserializer.serialize_param(val.as_ref()))
138 }
139
140 pub fn example_value_json(&self) -> Option<serde_json::Value> {
142 let example = self.example_value?();
143 Some(self.deserializer.serialize_param(example.as_ref()))
144 }
145
146 pub fn type_description(&self) -> TypeDescription {
149 let mut description = TypeDescription::default();
150 self.deserializer.describe(&mut description);
151 description.rust_type = self.rust_type.name_in_code;
152 description
153 }
154}
155
156#[derive(Clone, Copy)]
158pub struct RustType {
159 id: fn() -> any::TypeId,
160 name_in_code: &'static str,
161}
162
163impl fmt::Debug for RustType {
164 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
165 formatter.write_str(self.name_in_code)
166 }
167}
168
169impl PartialEq for RustType {
170 fn eq(&self, other: &Self) -> bool {
171 (self.id)() == (other.id)()
172 }
173}
174
175impl RustType {
176 #[allow(clippy::incompatible_msrv)] pub const fn of<T: 'static>(name_in_code: &'static str) -> Self {
179 Self {
180 id: any::TypeId::of::<T>,
181 name_in_code,
182 }
183 }
184
185 pub fn id(&self) -> any::TypeId {
187 (self.id)()
188 }
189
190 pub const fn name_in_code(&self) -> &'static str {
192 self.name_in_code
193 }
194}
195
196#[derive(Clone, Copy, PartialEq, Eq, Hash)]
198pub struct BasicTypes(u8);
199
200impl BasicTypes {
201 pub const BOOL: Self = Self(1);
203 pub const INTEGER: Self = Self(2);
205 pub const FLOAT: Self = Self(4 | 2);
207 pub const STRING: Self = Self(8);
209 pub const ARRAY: Self = Self(16);
211 pub const OBJECT: Self = Self(32);
213 pub const ANY: Self = Self(63);
215
216 const COMPONENTS: &'static [(Self, &'static str)] = &[
217 (Self::BOOL, "Boolean"),
218 (Self::INTEGER, "integer"),
219 (Self::FLOAT, "float"),
220 (Self::STRING, "string"),
221 (Self::ARRAY, "array"),
222 (Self::OBJECT, "object"),
223 ];
224
225 pub(crate) const fn from_raw(raw: u8) -> Self {
226 assert!(raw != 0, "Raw `BasicTypes` cannot be 0");
227 assert!(
228 raw <= Self::ANY.0,
229 "Unused set bits in `BasicTypes` raw value"
230 );
231 Self(raw)
232 }
233
234 #[doc(hidden)] pub const fn raw(self) -> u8 {
236 self.0
237 }
238
239 #[must_use]
241 pub const fn or(self, rhs: Self) -> Self {
242 Self(self.0 | rhs.0)
243 }
244
245 pub const fn contains(self, needle: Self) -> bool {
247 self.0 & needle.0 == needle.0
248 }
249}
250
251impl fmt::Display for BasicTypes {
252 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
253 if *self == Self::ANY {
254 formatter.write_str("any")
255 } else {
256 let mut is_empty = true;
257 for &(component, name) in Self::COMPONENTS {
258 if self.contains(component) {
259 if !is_empty {
260 formatter.write_str(" | ")?;
261 }
262 formatter.write_str(name)?;
263 is_empty = false;
264 }
265 }
266 Ok(())
267 }
268 }
269}
270
271impl fmt::Debug for BasicTypes {
272 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
273 fmt::Display::fmt(self, formatter)
274 }
275}
276
277#[derive(Debug, Clone)]
278struct ChildDescription {
279 expecting: BasicTypes,
280 description: Box<TypeDescription>,
281}
282
283impl ChildDescription {
284 fn new<T: 'static, De: DeserializeParam<T>>(deserializer: &De, set_type: bool) -> Self {
285 let mut description = Box::default();
286 deserializer.describe(&mut description);
287 if set_type {
288 description.rust_type = any::type_name::<T>();
289 }
290 Self {
291 expecting: De::EXPECTING,
292 description,
293 }
294 }
295}
296
297#[derive(Debug, Clone, Copy)]
300#[non_exhaustive]
301#[doc(hidden)] pub enum TypeSuffixes {
303 All,
305 DurationUnits,
307 SizeUnits,
309 EtherUnits,
311}
312
313#[derive(Debug, Clone, Default)]
318pub struct TypeDescription {
319 rust_type: &'static str,
320 details: Option<Cow<'static, str>>,
321 unit: Option<UnitOfMeasurement>,
322 suffixes: Option<TypeSuffixes>,
323 pub(crate) is_secret: bool,
324 validations: Vec<String>,
325 deserialize_if: Option<String>,
326 items: Option<ChildDescription>,
327 entries: Option<(ChildDescription, ChildDescription)>,
328 fallback: Option<ChildDescription>,
329}
330
331impl TypeDescription {
332 #[doc(hidden)]
333 pub fn rust_type(&self) -> &str {
334 self.rust_type
335 }
336
337 pub fn details(&self) -> Option<&str> {
339 self.details.as_deref()
340 }
341
342 pub fn unit(&self) -> Option<UnitOfMeasurement> {
344 self.unit
345 }
346
347 #[doc(hidden)] pub fn suffixes(&self) -> Option<TypeSuffixes> {
349 self.suffixes
350 }
351
352 #[doc(hidden)] pub fn validations(&self) -> &[String] {
354 &self.validations
355 }
356
357 #[doc(hidden)] pub fn deserialize_if(&self) -> Option<&str> {
359 self.deserialize_if.as_deref()
360 }
361
362 pub fn items(&self) -> Option<(BasicTypes, &Self)> {
364 self.items
365 .as_ref()
366 .map(|child| (child.expecting, &*child.description))
367 }
368
369 pub fn keys(&self) -> Option<(BasicTypes, &Self)> {
371 let keys = &self.entries.as_ref()?.0;
372 Some((keys.expecting, &*keys.description))
373 }
374
375 pub fn values(&self) -> Option<(BasicTypes, &Self)> {
377 let keys = &self.entries.as_ref()?.1;
378 Some((keys.expecting, &*keys.description))
379 }
380
381 pub fn fallback(&self) -> Option<(BasicTypes, &Self)> {
383 let fallback = self.fallback.as_ref()?;
384 Some((fallback.expecting, &*fallback.description))
385 }
386
387 pub fn contains_secrets(&self) -> bool {
390 if self.is_secret {
391 return true;
392 }
393 if let Some(item) = &self.items {
394 if item.description.contains_secrets() {
395 return true;
396 }
397 }
398 if let Some((key, value)) = &self.entries {
399 if key.description.contains_secrets() {
400 return true;
401 }
402 if value.description.contains_secrets() {
403 return true;
404 }
405 }
406 false
407 }
408
409 pub fn set_details(&mut self, details: impl Into<Cow<'static, str>>) -> &mut Self {
411 self.details = Some(details.into());
412 self
413 }
414
415 pub fn set_unit(&mut self, unit: UnitOfMeasurement) -> &mut Self {
417 self.unit = Some(unit);
418 self
419 }
420
421 pub(crate) fn set_suffixes(&mut self, suffixes: TypeSuffixes) -> &mut Self {
422 self.suffixes = Some(suffixes);
423 self
424 }
425
426 pub fn set_validations<T>(&mut self, validations: &[&'static dyn Validate<T>]) -> &mut Self {
428 self.validations = validations.iter().map(ToString::to_string).collect();
429 self
430 }
431
432 pub fn set_deserialize_if<T>(&mut self, condition: &'static dyn Validate<T>) -> &mut Self {
434 self.deserialize_if = Some(condition.to_string());
435 self
436 }
437
438 pub fn set_secret(&mut self) -> &mut Self {
440 self.is_secret = true;
441 self
442 }
443
444 pub fn set_items<T: 'static>(&mut self, items: &impl DeserializeParam<T>) -> &mut Self {
446 self.items = Some(ChildDescription::new(items, true));
447 self
448 }
449
450 pub fn set_entries<K: 'static, V: 'static>(
452 &mut self,
453 keys: &impl DeserializeParam<K>,
454 values: &impl DeserializeParam<V>,
455 ) -> &mut Self {
456 self.entries = Some((
457 ChildDescription::new(keys, true),
458 ChildDescription::new(values, true),
459 ));
460 self
461 }
462
463 pub fn set_fallback<T: 'static>(&mut self, fallback: &impl DeserializeParam<T>) {
465 self.fallback = Some(ChildDescription::new(fallback, false));
466 }
467}
468
469impl fmt::Display for TypeDescription {
470 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
471 if let Some(description) = &self.details {
472 write!(formatter, ", {description}")?;
473 }
474 if let Some(unit) = self.unit {
475 write!(formatter, " [unit: {unit}]")?;
476 }
477 Ok(())
478 }
479}
480
481#[derive(Debug, Clone, Copy)]
483pub struct NestedConfigMetadata {
484 pub name: &'static str,
486 pub aliases: &'static [(&'static str, AliasOptions)],
488 pub rust_field_name: &'static str,
490 pub tag_variant: Option<&'static ConfigVariant>,
492 pub meta: &'static ConfigMetadata,
494}
495
496#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
509#[non_exhaustive]
510pub enum TimeUnit {
511 Millis,
513 Seconds,
515 Minutes,
517 Hours,
519 Days,
521 Weeks,
523 }
525
526impl TimeUnit {
527 pub(crate) fn plural(self) -> &'static str {
528 match self {
529 TimeUnit::Millis => "milliseconds",
530 TimeUnit::Seconds => "seconds",
531 TimeUnit::Minutes => "minutes",
532 TimeUnit::Hours => "hours",
533 TimeUnit::Days => "days",
534 TimeUnit::Weeks => "weeks",
535 }
536 }
537
538 pub fn checked_mul(self, factor: u64) -> Option<Duration> {
540 Some(match self {
541 Self::Millis => Duration::from_millis(factor),
542 Self::Seconds => Duration::from_secs(factor),
543 Self::Minutes => {
544 let val = factor.checked_mul(60)?;
545 Duration::from_secs(val)
546 }
547 Self::Hours => {
548 let val = factor.checked_mul(3_600)?;
549 Duration::from_secs(val)
550 }
551 Self::Days => {
552 let val = factor.checked_mul(86_400)?;
553 Duration::from_secs(val)
554 }
555 Self::Weeks => {
556 let val = factor.checked_mul(86_400 * 7)?;
557 Duration::from_secs(val)
558 }
559 })
560 }
561}
562
563impl fmt::Display for TimeUnit {
564 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
565 formatter.write_str(self.plural())
566 }
567}
568
569impl From<TimeUnit> for Duration {
570 fn from(unit: TimeUnit) -> Self {
571 match unit {
572 TimeUnit::Millis => Duration::from_millis(1),
573 TimeUnit::Seconds => Duration::from_secs(1),
574 TimeUnit::Minutes => Duration::from_secs(60),
575 TimeUnit::Hours => Duration::from_secs(3_600),
576 TimeUnit::Days => Duration::from_secs(86_400),
577 TimeUnit::Weeks => Duration::from_secs(86_400 * 7),
578 }
579 }
580}
581
582impl ops::Mul<u64> for TimeUnit {
584 type Output = Duration;
585
586 fn mul(self, rhs: u64) -> Self::Output {
587 self.checked_mul(rhs)
588 .unwrap_or_else(|| panic!("Integer overflow getting {rhs} * {self}"))
589 }
590}
591
592impl ops::Mul<TimeUnit> for u64 {
594 type Output = Duration;
595
596 fn mul(self, rhs: TimeUnit) -> Self::Output {
597 rhs.checked_mul(self)
598 .unwrap_or_else(|| panic!("Integer overflow getting {self} * {rhs}"))
599 }
600}
601
602#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
604#[non_exhaustive]
605pub enum SizeUnit {
606 Bytes,
608 KiB,
610 MiB,
612 GiB,
614}
615
616impl SizeUnit {
617 pub(crate) const fn as_str(self) -> &'static str {
618 match self {
619 Self::Bytes => "bytes",
620 Self::KiB => "kilobytes",
621 Self::MiB => "megabytes",
622 Self::GiB => "gigabytes",
623 }
624 }
625
626 pub(crate) const fn value_in_unit(self) -> u64 {
627 match self {
628 Self::Bytes => 1,
629 Self::KiB => 1_024,
630 Self::MiB => 1_024 * 1_024,
631 Self::GiB => 1_024 * 1_024 * 1_024,
632 }
633 }
634}
635
636impl fmt::Display for SizeUnit {
637 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
638 formatter.write_str(self.as_str())
639 }
640}
641
642#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
644#[non_exhaustive]
645pub enum EtherUnit {
646 Wei,
648 Gwei,
650 Ether,
652}
653
654impl fmt::Display for EtherUnit {
655 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
656 formatter.write_str(self.as_str())
657 }
658}
659
660impl EtherUnit {
661 pub(crate) const fn value_in_unit(self) -> u128 {
662 match self {
663 Self::Wei => 1,
664 Self::Gwei => 1_000_000_000,
665 Self::Ether => 1_000_000_000_000_000_000,
666 }
667 }
668
669 pub(crate) const fn as_str(self) -> &'static str {
670 match self {
671 Self::Wei => "wei",
672 Self::Gwei => "gwei",
673 Self::Ether => "ether",
674 }
675 }
676}
677
678#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
680#[non_exhaustive]
681pub enum UnitOfMeasurement {
682 Time(TimeUnit),
684 ByteSize(SizeUnit),
686 Ether(EtherUnit),
688}
689
690impl fmt::Display for UnitOfMeasurement {
691 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
692 match self {
693 Self::Time(unit) => fmt::Display::fmt(unit, formatter),
694 Self::ByteSize(unit) => fmt::Display::fmt(unit, formatter),
695 Self::Ether(unit) => fmt::Display::fmt(unit, formatter),
696 }
697 }
698}
699
700impl From<TimeUnit> for UnitOfMeasurement {
701 fn from(unit: TimeUnit) -> Self {
702 Self::Time(unit)
703 }
704}
705
706impl From<SizeUnit> for UnitOfMeasurement {
707 fn from(unit: SizeUnit) -> Self {
708 Self::ByteSize(unit)
709 }
710}
711
712impl From<EtherUnit> for UnitOfMeasurement {
713 fn from(unit: EtherUnit) -> Self {
714 Self::Ether(unit)
715 }
716}