1use crate::MAX_LOCAL_PART_LENGTH;
2
3pub const DEFAULT_MAX_LOCAL_PART_LENGTH: usize = MAX_LOCAL_PART_LENGTH;
5
6pub const DEFAULT_MINIMUM_DNS_LABELS: usize = 1;
8
9#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
11#[cfg_attr(feature = "clap", derive(clap::Args))]
12pub struct Options {
13 #[cfg_attr(feature = "clap", command(flatten))]
14 local: LocalOptions,
15 #[cfg_attr(feature = "clap", command(flatten))]
16 domain: DomainOptions,
17 #[cfg_attr(feature = "clap", command(flatten))]
18 limits: Limits,
19}
20
21impl Default for Options {
22 #[cfg_attr(not(coverage), inline(always))]
23 fn default() -> Self {
24 Self::new()
25 }
26}
27
28impl Options {
29 #[cfg_attr(not(coverage), inline(always))]
31 pub const fn new() -> Self {
32 Self {
33 local: LocalOptions::new(),
34 domain: DomainOptions::new(),
35 limits: Limits::new(),
36 }
37 }
38
39 #[cfg_attr(not(coverage), inline(always))]
41 pub const fn local(&self) -> LocalOptions {
42 self.local
43 }
44
45 #[cfg_attr(not(coverage), inline(always))]
47 pub const fn set_local(&mut self, local: LocalOptions) -> &mut Self {
48 self.local = local;
49 self
50 }
51
52 #[must_use]
54 #[cfg_attr(not(coverage), inline(always))]
55 pub const fn with_local(mut self, local: LocalOptions) -> Self {
56 self.set_local(local);
57 self
58 }
59
60 #[cfg_attr(not(coverage), inline(always))]
62 pub const fn domain(&self) -> DomainOptions {
63 self.domain
64 }
65
66 #[cfg_attr(not(coverage), inline(always))]
68 pub const fn set_domain(&mut self, domain: DomainOptions) -> &mut Self {
69 self.domain = domain;
70 self
71 }
72
73 #[must_use]
75 #[cfg_attr(not(coverage), inline(always))]
76 pub const fn with_domain(mut self, domain: DomainOptions) -> Self {
77 self.set_domain(domain);
78 self
79 }
80
81 #[cfg_attr(not(coverage), inline(always))]
83 pub const fn limits(&self) -> Limits {
84 self.limits
85 }
86
87 #[cfg_attr(not(coverage), inline(always))]
89 pub const fn set_limits(&mut self, limits: Limits) -> &mut Self {
90 self.limits = limits;
91 self
92 }
93
94 #[must_use]
96 #[cfg_attr(not(coverage), inline(always))]
97 pub const fn with_limits(mut self, limits: Limits) -> Self {
98 self.set_limits(limits);
99 self
100 }
101}
102
103#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
105#[cfg_attr(feature = "clap", derive(clap::Args))]
106pub struct LocalOptions {
107 #[cfg_attr(feature = "clap", arg(
108 id = "email-local-smtp-utf8",
109 long = "email-local-smtp-utf8",
110 value_enum,
111 default_value_t = SmtpUtf8Policy::Allow,
112 ))]
113 smtp_utf8: SmtpUtf8Policy,
114}
115
116impl Default for LocalOptions {
117 #[cfg_attr(not(coverage), inline(always))]
118 fn default() -> Self {
119 Self::new()
120 }
121}
122
123impl LocalOptions {
124 #[cfg_attr(not(coverage), inline(always))]
126 pub const fn new() -> Self {
127 Self {
128 smtp_utf8: SmtpUtf8Policy::Allow,
129 }
130 }
131
132 #[cfg_attr(not(coverage), inline(always))]
134 pub const fn smtp_utf8(&self) -> SmtpUtf8Policy {
135 self.smtp_utf8
136 }
137
138 #[cfg_attr(not(coverage), inline(always))]
140 pub const fn set_smtp_utf8(&mut self, smtp_utf8: SmtpUtf8Policy) -> &mut Self {
141 self.smtp_utf8 = smtp_utf8;
142 self
143 }
144
145 #[must_use]
147 #[cfg_attr(not(coverage), inline(always))]
148 pub const fn with_smtp_utf8(mut self, smtp_utf8: SmtpUtf8Policy) -> Self {
149 self.set_smtp_utf8(smtp_utf8);
150 self
151 }
152}
153
154#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
156#[cfg_attr(feature = "clap", derive(clap::Args))]
157pub struct DomainOptions {
158 #[cfg_attr(feature = "clap", arg(
159 id = "email-domain-minimum-dns-labels",
160 long = "email-domain-minimum-dns-labels",
161 default_value_t = DEFAULT_MINIMUM_DNS_LABELS,
162 ))]
163 minimum_dns_labels: usize,
164 #[cfg_attr(feature = "clap", arg(
165 id = "email-domain-literals",
166 long = "email-domain-literals",
167 value_enum,
168 default_value_t = DomainLiteralPolicy::Allow,
169 ))]
170 literals: DomainLiteralPolicy,
171 #[cfg_attr(feature = "clap", arg(
172 id = "email-domain-unicode",
173 long = "email-domain-unicode",
174 value_enum,
175 default_value_t = DomainUnicodePolicy::Idna,
176 ))]
177 unicode: DomainUnicodePolicy,
178}
179
180impl Default for DomainOptions {
181 #[cfg_attr(not(coverage), inline(always))]
182 fn default() -> Self {
183 Self::new()
184 }
185}
186
187impl DomainOptions {
188 #[cfg_attr(not(coverage), inline(always))]
190 pub const fn new() -> Self {
191 Self {
192 minimum_dns_labels: DEFAULT_MINIMUM_DNS_LABELS,
193 literals: DomainLiteralPolicy::Allow,
194 unicode: DomainUnicodePolicy::Idna,
195 }
196 }
197
198 #[cfg_attr(not(coverage), inline(always))]
200 pub const fn minimum_dns_labels(&self) -> usize {
201 self.minimum_dns_labels
202 }
203
204 #[cfg_attr(not(coverage), inline(always))]
206 pub const fn set_minimum_dns_labels(&mut self, minimum_dns_labels: usize) -> &mut Self {
207 self.minimum_dns_labels = minimum_dns_labels;
208 self
209 }
210
211 #[must_use]
213 #[cfg_attr(not(coverage), inline(always))]
214 pub const fn with_minimum_dns_labels(mut self, minimum_dns_labels: usize) -> Self {
215 self.set_minimum_dns_labels(minimum_dns_labels);
216 self
217 }
218
219 #[must_use]
221 #[cfg_attr(not(coverage), inline(always))]
222 pub const fn with_no_minimum_dns_labels(mut self) -> Self {
223 self.set_minimum_dns_labels(0);
224 self
225 }
226
227 #[must_use]
229 #[cfg_attr(not(coverage), inline(always))]
230 pub const fn with_required_tld(mut self) -> Self {
231 self.set_minimum_dns_labels(2);
232 self
233 }
234
235 #[cfg_attr(not(coverage), inline(always))]
237 pub const fn literals(&self) -> DomainLiteralPolicy {
238 self.literals
239 }
240
241 #[cfg_attr(not(coverage), inline(always))]
243 pub const fn set_literals(&mut self, literals: DomainLiteralPolicy) -> &mut Self {
244 self.literals = literals;
245 self
246 }
247
248 #[must_use]
250 #[cfg_attr(not(coverage), inline(always))]
251 pub const fn with_literals(mut self, literals: DomainLiteralPolicy) -> Self {
252 self.set_literals(literals);
253 self
254 }
255
256 #[must_use]
258 #[cfg_attr(not(coverage), inline(always))]
259 pub const fn with_domain_literals(mut self) -> Self {
260 self.set_literals(DomainLiteralPolicy::Allow);
261 self
262 }
263
264 #[must_use]
266 #[cfg_attr(not(coverage), inline(always))]
267 pub const fn without_domain_literals(mut self) -> Self {
268 self.set_literals(DomainLiteralPolicy::Forbid);
269 self
270 }
271
272 #[cfg_attr(not(coverage), inline(always))]
274 pub const fn unicode(&self) -> DomainUnicodePolicy {
275 self.unicode
276 }
277
278 #[cfg_attr(not(coverage), inline(always))]
280 pub const fn set_unicode(&mut self, unicode: DomainUnicodePolicy) -> &mut Self {
281 self.unicode = unicode;
282 self
283 }
284
285 #[must_use]
287 #[cfg_attr(not(coverage), inline(always))]
288 pub const fn with_unicode(mut self, unicode: DomainUnicodePolicy) -> Self {
289 self.set_unicode(unicode);
290 self
291 }
292}
293
294#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
296#[cfg_attr(feature = "clap", derive(clap::Args))]
297pub struct Limits {
298 #[cfg_attr(feature = "clap", arg(
299 id = "email-limits-max-local-part-len",
300 long = "email-limits-max-local-part-len",
301 default_value_t = DEFAULT_MAX_LOCAL_PART_LENGTH,
302 ))]
303 max_local_part_len: usize,
304}
305
306impl Default for Limits {
307 #[cfg_attr(not(coverage), inline(always))]
308 fn default() -> Self {
309 Self::new()
310 }
311}
312
313impl Limits {
314 #[cfg_attr(not(coverage), inline(always))]
316 pub const fn new() -> Self {
317 Self {
318 max_local_part_len: DEFAULT_MAX_LOCAL_PART_LENGTH,
319 }
320 }
321
322 #[cfg_attr(not(coverage), inline(always))]
324 pub const fn max_local_part_len(&self) -> usize {
325 self.max_local_part_len
326 }
327
328 #[cfg_attr(not(coverage), inline(always))]
330 pub const fn set_max_local_part_len(&mut self, max_local_part_len: usize) -> &mut Self {
331 self.max_local_part_len = max_local_part_len;
332 self
333 }
334
335 #[must_use]
337 #[cfg_attr(not(coverage), inline(always))]
338 pub const fn with_max_local_part_len(mut self, max_local_part_len: usize) -> Self {
339 self.set_max_local_part_len(max_local_part_len);
340 self
341 }
342}
343
344#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash)]
346#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
347#[non_exhaustive]
348pub enum SmtpUtf8Policy {
349 #[default]
351 #[cfg_attr(feature = "clap", value(name = "allow"))]
352 Allow,
353 #[cfg_attr(feature = "clap", value(name = "forbid"))]
355 Forbid,
356}
357
358impl SmtpUtf8Policy {
359 #[cfg_attr(not(coverage), inline(always))]
361 pub const fn as_str(&self) -> &'static str {
362 match self {
363 Self::Allow => "allow",
364 Self::Forbid => "forbid",
365 }
366 }
367
368 #[cfg_attr(not(coverage), inline(always))]
370 pub const fn is_allow(&self) -> bool {
371 matches!(self, Self::Allow)
372 }
373
374 #[cfg_attr(not(coverage), inline(always))]
376 pub const fn is_forbid(&self) -> bool {
377 matches!(self, Self::Forbid)
378 }
379
380 #[cfg(feature = "serde")]
381 const fn as_u8(&self) -> u8 {
382 match self {
383 Self::Allow => 0,
384 Self::Forbid => 1,
385 }
386 }
387
388 #[cfg(feature = "serde")]
389 const fn from_u8(value: u8) -> Option<Self> {
390 match value {
391 0 => Some(Self::Allow),
392 1 => Some(Self::Forbid),
393 _ => None,
394 }
395 }
396
397 #[cfg(feature = "serde")]
398 fn from_str_name(value: &str) -> Option<Self> {
399 match value {
400 "allow" => Some(Self::Allow),
401 "forbid" => Some(Self::Forbid),
402 _ => None,
403 }
404 }
405}
406
407impl core::fmt::Display for SmtpUtf8Policy {
408 #[inline]
409 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
410 f.write_str(self.as_str())
411 }
412}
413
414#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash)]
416#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
417#[non_exhaustive]
418pub enum DomainLiteralPolicy {
419 #[default]
421 #[cfg_attr(feature = "clap", value(name = "allow"))]
422 Allow,
423 #[cfg_attr(feature = "clap", value(name = "forbid"))]
425 Forbid,
426}
427
428impl DomainLiteralPolicy {
429 #[cfg_attr(not(coverage), inline(always))]
431 pub const fn as_str(&self) -> &'static str {
432 match self {
433 Self::Allow => "allow",
434 Self::Forbid => "forbid",
435 }
436 }
437
438 #[cfg_attr(not(coverage), inline(always))]
440 pub const fn is_allow(&self) -> bool {
441 matches!(self, Self::Allow)
442 }
443
444 #[cfg_attr(not(coverage), inline(always))]
446 pub const fn is_forbid(&self) -> bool {
447 matches!(self, Self::Forbid)
448 }
449
450 #[cfg(feature = "serde")]
451 const fn as_u8(&self) -> u8 {
452 match self {
453 Self::Allow => 0,
454 Self::Forbid => 1,
455 }
456 }
457
458 #[cfg(feature = "serde")]
459 const fn from_u8(value: u8) -> Option<Self> {
460 match value {
461 0 => Some(Self::Allow),
462 1 => Some(Self::Forbid),
463 _ => None,
464 }
465 }
466
467 #[cfg(feature = "serde")]
468 fn from_str_name(value: &str) -> Option<Self> {
469 match value {
470 "allow" => Some(Self::Allow),
471 "forbid" => Some(Self::Forbid),
472 _ => None,
473 }
474 }
475}
476
477impl core::fmt::Display for DomainLiteralPolicy {
478 #[inline]
479 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
480 f.write_str(self.as_str())
481 }
482}
483
484#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash)]
486#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
487#[non_exhaustive]
488pub enum DomainUnicodePolicy {
489 #[cfg_attr(feature = "clap", value(name = "ascii", alias("ascii_only")))]
491 AsciiOnly,
492 #[default]
494 #[cfg_attr(feature = "clap", value(name = "idna"))]
495 Idna,
496 #[cfg_attr(
498 feature = "clap",
499 value(name = "raw", alias("raw_utf8"), alias("non_standard_utf8"))
500 )]
501 NonStandardUtf8,
502}
503
504impl DomainUnicodePolicy {
505 #[cfg_attr(not(coverage), inline(always))]
507 pub const fn as_str(&self) -> &'static str {
508 match self {
509 Self::AsciiOnly => "ascii",
510 Self::Idna => "idna",
511 Self::NonStandardUtf8 => "raw",
512 }
513 }
514
515 #[cfg_attr(not(coverage), inline(always))]
517 pub const fn is_ascii_only(&self) -> bool {
518 matches!(self, Self::AsciiOnly)
519 }
520
521 #[cfg_attr(not(coverage), inline(always))]
523 pub const fn is_idna(&self) -> bool {
524 matches!(self, Self::Idna)
525 }
526
527 #[cfg_attr(not(coverage), inline(always))]
529 pub const fn is_non_standard_utf8(&self) -> bool {
530 matches!(self, Self::NonStandardUtf8)
531 }
532
533 #[cfg(feature = "serde")]
534 const fn as_u8(&self) -> u8 {
535 match self {
536 Self::AsciiOnly => 0,
537 Self::Idna => 1,
538 Self::NonStandardUtf8 => 2,
539 }
540 }
541
542 #[cfg(feature = "serde")]
543 const fn from_u8(value: u8) -> Option<Self> {
544 match value {
545 0 => Some(Self::AsciiOnly),
546 1 => Some(Self::Idna),
547 2 => Some(Self::NonStandardUtf8),
548 _ => None,
549 }
550 }
551
552 #[cfg(feature = "serde")]
553 fn from_str_name(value: &str) -> Option<Self> {
554 match value {
555 "ascii" | "ascii_only" => Some(Self::AsciiOnly),
556 "idna" => Some(Self::Idna),
557 "raw" | "raw_utf8" | "non_standard_utf8" => Some(Self::NonStandardUtf8),
558 _ => None,
559 }
560 }
561}
562
563impl core::fmt::Display for DomainUnicodePolicy {
564 #[inline]
565 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
566 f.write_str(self.as_str())
567 }
568}
569
570#[cfg(feature = "serde")]
571mod serde {
572 use core::{fmt, marker::PhantomData};
573
574 use serde_core::{
575 Deserialize, Deserializer, Serialize, Serializer,
576 de::{self, IgnoredAny, MapAccess, SeqAccess, Unexpected, Visitor},
577 ser::SerializeStruct,
578 };
579
580 use super::{
581 DomainLiteralPolicy, DomainOptions, DomainUnicodePolicy, Limits, LocalOptions, Options,
582 SmtpUtf8Policy,
583 };
584
585 trait UnitPolicy: Copy {
586 const EXPECTING: &'static str;
587 const VARIANTS: &'static [&'static str];
588
589 fn as_name(&self) -> &'static str;
590 fn as_discriminant(&self) -> u8;
591 fn from_name(value: &str) -> Option<Self>;
592 fn from_discriminant(value: u8) -> Option<Self>;
593 }
594
595 struct UnitPolicyVisitor<P>(PhantomData<fn() -> P>);
596
597 impl<P> UnitPolicyVisitor<P> {
598 const fn new() -> Self {
599 Self(PhantomData)
600 }
601 }
602
603 impl<P> Visitor<'_> for UnitPolicyVisitor<P>
604 where
605 P: UnitPolicy,
606 {
607 type Value = P;
608
609 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
610 f.write_str(P::EXPECTING)
611 }
612
613 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
614 where
615 E: de::Error,
616 {
617 P::from_name(value).ok_or_else(|| E::unknown_variant(value, P::VARIANTS))
618 }
619
620 fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
621 where
622 E: de::Error,
623 {
624 let value = core::str::from_utf8(value)
625 .map_err(|_| E::invalid_value(Unexpected::Bytes(value), &self))?;
626 self.visit_str(value)
627 }
628
629 fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E>
630 where
631 E: de::Error,
632 {
633 P::from_discriminant(value)
634 .ok_or_else(|| E::invalid_value(Unexpected::Unsigned(u64::from(value)), &self))
635 }
636
637 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
638 where
639 E: de::Error,
640 {
641 let Ok(value) = u8::try_from(value) else {
642 return Err(E::invalid_value(Unexpected::Unsigned(value), &self));
643 };
644 self.visit_u8(value)
645 }
646 }
647
648 fn serialize_unit_policy<P, S>(value: &P, serializer: S) -> Result<S::Ok, S::Error>
649 where
650 P: UnitPolicy,
651 S: Serializer,
652 {
653 if serializer.is_human_readable() {
654 serializer.serialize_str(value.as_name())
655 } else {
656 serializer.serialize_u8(value.as_discriminant())
657 }
658 }
659
660 fn deserialize_unit_policy<'de, P, D>(deserializer: D) -> Result<P, D::Error>
661 where
662 P: UnitPolicy,
663 D: Deserializer<'de>,
664 {
665 if deserializer.is_human_readable() {
666 deserializer.deserialize_str(UnitPolicyVisitor::<P>::new())
667 } else {
668 deserializer.deserialize_u8(UnitPolicyVisitor::<P>::new())
669 }
670 }
671
672 impl UnitPolicy for SmtpUtf8Policy {
673 const EXPECTING: &'static str = "an SMTPUTF8 policy";
674 const VARIANTS: &'static [&'static str] = &["allow", "forbid"];
675
676 fn as_name(&self) -> &'static str {
677 self.as_str()
678 }
679
680 fn as_discriminant(&self) -> u8 {
681 self.as_u8()
682 }
683
684 fn from_name(value: &str) -> Option<Self> {
685 Self::from_str_name(value)
686 }
687
688 fn from_discriminant(value: u8) -> Option<Self> {
689 Self::from_u8(value)
690 }
691 }
692
693 impl Serialize for SmtpUtf8Policy {
694 #[inline]
695 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
696 where
697 S: Serializer,
698 {
699 serialize_unit_policy(self, serializer)
700 }
701 }
702
703 impl<'de> Deserialize<'de> for SmtpUtf8Policy {
704 #[inline]
705 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
706 where
707 D: Deserializer<'de>,
708 {
709 deserialize_unit_policy(deserializer)
710 }
711 }
712
713 impl UnitPolicy for DomainLiteralPolicy {
714 const EXPECTING: &'static str = "a domain literal policy";
715 const VARIANTS: &'static [&'static str] = &["allow", "forbid"];
716
717 fn as_name(&self) -> &'static str {
718 self.as_str()
719 }
720
721 fn as_discriminant(&self) -> u8 {
722 self.as_u8()
723 }
724
725 fn from_name(value: &str) -> Option<Self> {
726 Self::from_str_name(value)
727 }
728
729 fn from_discriminant(value: u8) -> Option<Self> {
730 Self::from_u8(value)
731 }
732 }
733
734 impl Serialize for DomainLiteralPolicy {
735 #[inline]
736 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
737 where
738 S: Serializer,
739 {
740 serialize_unit_policy(self, serializer)
741 }
742 }
743
744 impl<'de> Deserialize<'de> for DomainLiteralPolicy {
745 #[inline]
746 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
747 where
748 D: Deserializer<'de>,
749 {
750 deserialize_unit_policy(deserializer)
751 }
752 }
753
754 impl UnitPolicy for DomainUnicodePolicy {
755 const EXPECTING: &'static str = "a domain Unicode policy";
756 const VARIANTS: &'static [&'static str] = &["ascii", "idna", "raw"];
757
758 fn as_name(&self) -> &'static str {
759 self.as_str()
760 }
761
762 fn as_discriminant(&self) -> u8 {
763 self.as_u8()
764 }
765
766 fn from_name(value: &str) -> Option<Self> {
767 Self::from_str_name(value)
768 }
769
770 fn from_discriminant(value: u8) -> Option<Self> {
771 Self::from_u8(value)
772 }
773 }
774
775 impl Serialize for DomainUnicodePolicy {
776 #[inline]
777 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
778 where
779 S: Serializer,
780 {
781 serialize_unit_policy(self, serializer)
782 }
783 }
784
785 impl<'de> Deserialize<'de> for DomainUnicodePolicy {
786 #[inline]
787 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
788 where
789 D: Deserializer<'de>,
790 {
791 deserialize_unit_policy(deserializer)
792 }
793 }
794
795 impl Serialize for Options {
796 #[inline]
797 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
798 where
799 S: Serializer,
800 {
801 let mut state = serializer.serialize_struct("Options", 3)?;
802 state.serialize_field("local", &self.local())?;
803 state.serialize_field("domain", &self.domain())?;
804 state.serialize_field("limits", &self.limits())?;
805 state.end()
806 }
807 }
808
809 impl<'de> Deserialize<'de> for Options {
810 #[inline]
811 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
812 where
813 D: Deserializer<'de>,
814 {
815 let human_readable = deserializer.is_human_readable();
816 deserializer.deserialize_struct(
817 "Options",
818 &["local", "domain", "limits"],
819 OptionsVisitor { human_readable },
820 )
821 }
822 }
823
824 enum OptionsField {
825 Local,
826 Domain,
827 Limits,
828 }
829
830 struct OptionsFieldVisitor;
831
832 impl Visitor<'_> for OptionsFieldVisitor {
833 type Value = OptionsField;
834
835 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
836 f.write_str("an Options field")
837 }
838
839 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
840 where
841 E: de::Error,
842 {
843 match value {
844 "local" => Ok(OptionsField::Local),
845 "domain" => Ok(OptionsField::Domain),
846 "limits" => Ok(OptionsField::Limits),
847 _ => Err(E::unknown_field(value, &["local", "domain", "limits"])),
848 }
849 }
850 }
851
852 impl<'de> Deserialize<'de> for OptionsField {
853 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
854 where
855 D: Deserializer<'de>,
856 {
857 deserializer.deserialize_identifier(OptionsFieldVisitor)
858 }
859 }
860
861 struct OptionsVisitor {
862 human_readable: bool,
863 }
864
865 impl<'de> Visitor<'de> for OptionsVisitor {
866 type Value = Options;
867
868 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
869 f.write_str("email address parsing options")
870 }
871
872 fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
873 where
874 M: MapAccess<'de>,
875 {
876 let mut local = None;
877 let mut domain = None;
878 let mut limits = None;
879 while let Some(field) = access.next_key()? {
880 match field {
881 OptionsField::Local => {
882 if local.is_some() {
883 return Err(de::Error::duplicate_field("local"));
884 }
885 local = Some(access.next_value()?);
886 }
887 OptionsField::Domain => {
888 if domain.is_some() {
889 return Err(de::Error::duplicate_field("domain"));
890 }
891 domain = Some(access.next_value()?);
892 }
893 OptionsField::Limits => {
894 if limits.is_some() {
895 return Err(de::Error::duplicate_field("limits"));
896 }
897 limits = Some(access.next_value()?);
898 }
899 }
900 }
901
902 let (local, domain, limits) = if self.human_readable {
903 (
904 local.unwrap_or_default(),
905 domain.unwrap_or_default(),
906 limits.unwrap_or_default(),
907 )
908 } else {
909 (
910 local.ok_or_else(|| de::Error::missing_field("local"))?,
911 domain.ok_or_else(|| de::Error::missing_field("domain"))?,
912 limits.ok_or_else(|| de::Error::missing_field("limits"))?,
913 )
914 };
915
916 Ok(
917 Options::new()
918 .with_local(local)
919 .with_domain(domain)
920 .with_limits(limits),
921 )
922 }
923
924 fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
925 where
926 A: SeqAccess<'de>,
927 {
928 if self.human_readable {
929 return Err(de::Error::invalid_type(Unexpected::Seq, &self));
930 }
931
932 let local = access
933 .next_element()?
934 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
935 let domain = access
936 .next_element()?
937 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
938 let limits = access
939 .next_element()?
940 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
941 if access.next_element::<IgnoredAny>()?.is_some() {
942 return Err(de::Error::invalid_length(4, &self));
943 }
944
945 Ok(
946 Options::new()
947 .with_local(local)
948 .with_domain(domain)
949 .with_limits(limits),
950 )
951 }
952 }
953
954 impl Serialize for LocalOptions {
955 #[inline]
956 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
957 where
958 S: Serializer,
959 {
960 let mut state = serializer.serialize_struct("LocalOptions", 1)?;
961 state.serialize_field("smtp_utf8", &self.smtp_utf8())?;
962 state.end()
963 }
964 }
965
966 impl<'de> Deserialize<'de> for LocalOptions {
967 #[inline]
968 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
969 where
970 D: Deserializer<'de>,
971 {
972 let human_readable = deserializer.is_human_readable();
973 deserializer.deserialize_struct(
974 "LocalOptions",
975 &["smtp_utf8"],
976 LocalOptionsVisitor { human_readable },
977 )
978 }
979 }
980
981 enum LocalOptionsField {
982 SmtpUtf8,
983 }
984
985 struct LocalOptionsFieldVisitor;
986
987 impl Visitor<'_> for LocalOptionsFieldVisitor {
988 type Value = LocalOptionsField;
989
990 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
991 f.write_str("a LocalOptions field")
992 }
993
994 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
995 where
996 E: de::Error,
997 {
998 match value {
999 "smtp_utf8" => Ok(LocalOptionsField::SmtpUtf8),
1000 _ => Err(E::unknown_field(value, &["smtp_utf8"])),
1001 }
1002 }
1003 }
1004
1005 impl<'de> Deserialize<'de> for LocalOptionsField {
1006 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1007 where
1008 D: Deserializer<'de>,
1009 {
1010 deserializer.deserialize_identifier(LocalOptionsFieldVisitor)
1011 }
1012 }
1013
1014 struct LocalOptionsVisitor {
1015 human_readable: bool,
1016 }
1017
1018 impl<'de> Visitor<'de> for LocalOptionsVisitor {
1019 type Value = LocalOptions;
1020
1021 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1022 f.write_str("local-part parsing options")
1023 }
1024
1025 fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
1026 where
1027 M: MapAccess<'de>,
1028 {
1029 let mut smtp_utf8 = None;
1030 while let Some(field) = access.next_key()? {
1031 match field {
1032 LocalOptionsField::SmtpUtf8 => {
1033 if smtp_utf8.is_some() {
1034 return Err(de::Error::duplicate_field("smtp_utf8"));
1035 }
1036 smtp_utf8 = Some(access.next_value()?);
1037 }
1038 }
1039 }
1040
1041 let smtp_utf8 = if self.human_readable {
1042 smtp_utf8.unwrap_or_default()
1043 } else {
1044 smtp_utf8.ok_or_else(|| de::Error::missing_field("smtp_utf8"))?
1045 };
1046
1047 Ok(LocalOptions::new().with_smtp_utf8(smtp_utf8))
1048 }
1049
1050 fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
1051 where
1052 A: SeqAccess<'de>,
1053 {
1054 if self.human_readable {
1055 return Err(de::Error::invalid_type(Unexpected::Seq, &self));
1056 }
1057
1058 let smtp_utf8 = access
1059 .next_element()?
1060 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
1061 if access.next_element::<IgnoredAny>()?.is_some() {
1062 return Err(de::Error::invalid_length(2, &self));
1063 }
1064
1065 Ok(LocalOptions::new().with_smtp_utf8(smtp_utf8))
1066 }
1067 }
1068
1069 impl Serialize for DomainOptions {
1070 #[inline]
1071 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1072 where
1073 S: Serializer,
1074 {
1075 let mut state = serializer.serialize_struct("DomainOptions", 3)?;
1076 state.serialize_field("minimum_dns_labels", &self.minimum_dns_labels())?;
1077 state.serialize_field("literals", &self.literals())?;
1078 state.serialize_field("unicode", &self.unicode())?;
1079 state.end()
1080 }
1081 }
1082
1083 impl<'de> Deserialize<'de> for DomainOptions {
1084 #[inline]
1085 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1086 where
1087 D: Deserializer<'de>,
1088 {
1089 let human_readable = deserializer.is_human_readable();
1090 deserializer.deserialize_struct(
1091 "DomainOptions",
1092 &["minimum_dns_labels", "literals", "unicode"],
1093 DomainOptionsVisitor { human_readable },
1094 )
1095 }
1096 }
1097
1098 enum DomainOptionsField {
1099 MinimumDnsLabels,
1100 Literals,
1101 Unicode,
1102 }
1103
1104 struct DomainOptionsFieldVisitor;
1105
1106 impl Visitor<'_> for DomainOptionsFieldVisitor {
1107 type Value = DomainOptionsField;
1108
1109 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1110 f.write_str("a DomainOptions field")
1111 }
1112
1113 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
1114 where
1115 E: de::Error,
1116 {
1117 match value {
1118 "minimum_dns_labels" => Ok(DomainOptionsField::MinimumDnsLabels),
1119 "literals" => Ok(DomainOptionsField::Literals),
1120 "unicode" => Ok(DomainOptionsField::Unicode),
1121 _ => Err(E::unknown_field(
1122 value,
1123 &["minimum_dns_labels", "literals", "unicode"],
1124 )),
1125 }
1126 }
1127 }
1128
1129 impl<'de> Deserialize<'de> for DomainOptionsField {
1130 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1131 where
1132 D: Deserializer<'de>,
1133 {
1134 deserializer.deserialize_identifier(DomainOptionsFieldVisitor)
1135 }
1136 }
1137
1138 struct DomainOptionsVisitor {
1139 human_readable: bool,
1140 }
1141
1142 impl<'de> Visitor<'de> for DomainOptionsVisitor {
1143 type Value = DomainOptions;
1144
1145 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1146 f.write_str("domain-part parsing options")
1147 }
1148
1149 fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
1150 where
1151 M: MapAccess<'de>,
1152 {
1153 let mut minimum_dns_labels = None;
1154 let mut literals = None;
1155 let mut unicode = None;
1156 while let Some(field) = access.next_key()? {
1157 match field {
1158 DomainOptionsField::MinimumDnsLabels => {
1159 if minimum_dns_labels.is_some() {
1160 return Err(de::Error::duplicate_field("minimum_dns_labels"));
1161 }
1162 minimum_dns_labels = Some(access.next_value()?);
1163 }
1164 DomainOptionsField::Literals => {
1165 if literals.is_some() {
1166 return Err(de::Error::duplicate_field("literals"));
1167 }
1168 literals = Some(access.next_value()?);
1169 }
1170 DomainOptionsField::Unicode => {
1171 if unicode.is_some() {
1172 return Err(de::Error::duplicate_field("unicode"));
1173 }
1174 unicode = Some(access.next_value()?);
1175 }
1176 }
1177 }
1178
1179 let (minimum_dns_labels, literals, unicode) = if self.human_readable {
1180 (
1181 minimum_dns_labels.unwrap_or_else(|| DomainOptions::new().minimum_dns_labels()),
1182 literals.unwrap_or_default(),
1183 unicode.unwrap_or_default(),
1184 )
1185 } else {
1186 (
1187 minimum_dns_labels.ok_or_else(|| de::Error::missing_field("minimum_dns_labels"))?,
1188 literals.ok_or_else(|| de::Error::missing_field("literals"))?,
1189 unicode.ok_or_else(|| de::Error::missing_field("unicode"))?,
1190 )
1191 };
1192
1193 Ok(
1194 DomainOptions::new()
1195 .with_minimum_dns_labels(minimum_dns_labels)
1196 .with_literals(literals)
1197 .with_unicode(unicode),
1198 )
1199 }
1200
1201 fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
1202 where
1203 A: SeqAccess<'de>,
1204 {
1205 if self.human_readable {
1206 return Err(de::Error::invalid_type(Unexpected::Seq, &self));
1207 }
1208
1209 let minimum_dns_labels = access
1210 .next_element()?
1211 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
1212 let literals = access
1213 .next_element()?
1214 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
1215 let unicode = access
1216 .next_element()?
1217 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
1218 if access.next_element::<IgnoredAny>()?.is_some() {
1219 return Err(de::Error::invalid_length(4, &self));
1220 }
1221
1222 Ok(
1223 DomainOptions::new()
1224 .with_minimum_dns_labels(minimum_dns_labels)
1225 .with_literals(literals)
1226 .with_unicode(unicode),
1227 )
1228 }
1229 }
1230
1231 impl Serialize for Limits {
1232 #[inline]
1233 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1234 where
1235 S: Serializer,
1236 {
1237 let mut state = serializer.serialize_struct("Limits", 1)?;
1238 state.serialize_field("max_local_part_len", &self.max_local_part_len())?;
1239 state.end()
1240 }
1241 }
1242
1243 impl<'de> Deserialize<'de> for Limits {
1244 #[inline]
1245 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1246 where
1247 D: Deserializer<'de>,
1248 {
1249 let human_readable = deserializer.is_human_readable();
1250 deserializer.deserialize_struct(
1251 "Limits",
1252 &["max_local_part_len"],
1253 LimitsVisitor { human_readable },
1254 )
1255 }
1256 }
1257
1258 enum LimitsField {
1259 MaxLocalPartLen,
1260 }
1261
1262 struct LimitsFieldVisitor;
1263
1264 impl Visitor<'_> for LimitsFieldVisitor {
1265 type Value = LimitsField;
1266
1267 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1268 f.write_str("a Limits field")
1269 }
1270
1271 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
1272 where
1273 E: de::Error,
1274 {
1275 match value {
1276 "max_local_part_len" => Ok(LimitsField::MaxLocalPartLen),
1277 _ => Err(E::unknown_field(value, &["max_local_part_len"])),
1278 }
1279 }
1280 }
1281
1282 impl<'de> Deserialize<'de> for LimitsField {
1283 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1284 where
1285 D: Deserializer<'de>,
1286 {
1287 deserializer.deserialize_identifier(LimitsFieldVisitor)
1288 }
1289 }
1290
1291 struct LimitsVisitor {
1292 human_readable: bool,
1293 }
1294
1295 impl<'de> Visitor<'de> for LimitsVisitor {
1296 type Value = Limits;
1297
1298 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1299 f.write_str("parsing limits")
1300 }
1301
1302 fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
1303 where
1304 M: MapAccess<'de>,
1305 {
1306 let mut max_local_part_len = None;
1307 while let Some(field) = access.next_key()? {
1308 match field {
1309 LimitsField::MaxLocalPartLen => {
1310 if max_local_part_len.is_some() {
1311 return Err(de::Error::duplicate_field("max_local_part_len"));
1312 }
1313 max_local_part_len = Some(access.next_value()?);
1314 }
1315 }
1316 }
1317
1318 let max_local_part_len = if self.human_readable {
1319 max_local_part_len.unwrap_or_else(|| Limits::new().max_local_part_len())
1320 } else {
1321 max_local_part_len.ok_or_else(|| de::Error::missing_field("max_local_part_len"))?
1322 };
1323
1324 Ok(Limits::new().with_max_local_part_len(max_local_part_len))
1325 }
1326
1327 fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
1328 where
1329 A: SeqAccess<'de>,
1330 {
1331 if self.human_readable {
1332 return Err(de::Error::invalid_type(Unexpected::Seq, &self));
1333 }
1334
1335 let max_local_part_len = access
1336 .next_element()?
1337 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
1338 if access.next_element::<IgnoredAny>()?.is_some() {
1339 return Err(de::Error::invalid_length(2, &self));
1340 }
1341
1342 Ok(Limits::new().with_max_local_part_len(max_local_part_len))
1343 }
1344 }
1345}