Skip to main content

emailaddr/
options.rs

1use crate::MAX_LOCAL_PART_LENGTH;
2
3/// Default local-part length limit used by [`Limits`].
4pub const DEFAULT_MAX_LOCAL_PART_LENGTH: usize = MAX_LOCAL_PART_LENGTH;
5
6/// Default minimum DNS label count used by [`DomainOptions`].
7pub const DEFAULT_MINIMUM_DNS_LABELS: usize = 1;
8
9/// Email address parsing options.
10#[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  /// Default RFC-compatible parsing options.
30  #[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  /// Returns local-part parsing options.
40  #[cfg_attr(not(coverage), inline(always))]
41  pub const fn local(&self) -> LocalOptions {
42    self.local
43  }
44
45  /// Sets local-part parsing options.
46  #[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  /// Returns these options with local-part parsing options changed.
53  #[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  /// Returns domain-part parsing options.
61  #[cfg_attr(not(coverage), inline(always))]
62  pub const fn domain(&self) -> DomainOptions {
63    self.domain
64  }
65
66  /// Sets domain-part parsing options.
67  #[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  /// Returns these options with domain-part parsing options changed.
74  #[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  /// Returns parsing limits.
82  #[cfg_attr(not(coverage), inline(always))]
83  pub const fn limits(&self) -> Limits {
84    self.limits
85  }
86
87  /// Sets parsing limits.
88  #[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  /// Returns these options with parsing limits changed.
95  #[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/// Local-part parsing options.
104#[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  /// Default local-part parsing options.
125  #[cfg_attr(not(coverage), inline(always))]
126  pub const fn new() -> Self {
127    Self {
128      smtp_utf8: SmtpUtf8Policy::Allow,
129    }
130  }
131
132  /// Returns the SMTPUTF8 policy.
133  #[cfg_attr(not(coverage), inline(always))]
134  pub const fn smtp_utf8(&self) -> SmtpUtf8Policy {
135    self.smtp_utf8
136  }
137
138  /// Sets the SMTPUTF8 policy.
139  #[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  /// Returns these options with the SMTPUTF8 policy changed.
146  #[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/// Domain-part parsing options.
155#[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  /// Default domain-part parsing options.
189  #[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  /// Returns the minimum DNS label count.
199  #[cfg_attr(not(coverage), inline(always))]
200  pub const fn minimum_dns_labels(&self) -> usize {
201    self.minimum_dns_labels
202  }
203
204  /// Sets the minimum DNS label count.
205  #[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  /// Returns these options with the minimum DNS label count changed.
212  #[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  /// Returns these options with no extra DNS label count requirement.
220  #[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  /// Returns these options requiring at least two DNS labels.
228  #[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  /// Returns the domain literal policy.
236  #[cfg_attr(not(coverage), inline(always))]
237  pub const fn literals(&self) -> DomainLiteralPolicy {
238    self.literals
239  }
240
241  /// Sets the domain literal policy.
242  #[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  /// Returns these options with the domain literal policy changed.
249  #[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  /// Returns these options allowing address-literal domains.
257  #[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  /// Returns these options rejecting address-literal domains.
265  #[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  /// Returns the Unicode domain policy.
273  #[cfg_attr(not(coverage), inline(always))]
274  pub const fn unicode(&self) -> DomainUnicodePolicy {
275    self.unicode
276  }
277
278  /// Sets the Unicode domain policy.
279  #[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  /// Returns these options with the Unicode domain policy changed.
286  #[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/// Parsing limits.
295#[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  /// Default RFC-compatible parsing limits.
315  #[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  /// Returns the maximum local-part length in bytes.
323  #[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  /// Sets the maximum local-part length in bytes.
329  #[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  /// Returns these limits with the maximum local-part length changed.
336  #[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/// Policy for SMTPUTF8 local-parts.
345#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash)]
346#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
347#[non_exhaustive]
348pub enum SmtpUtf8Policy {
349  /// Accept UTF-8 local-parts.
350  #[default]
351  #[cfg_attr(feature = "clap", value(name = "allow"))]
352  Allow,
353  /// Reject non-ASCII local-parts.
354  #[cfg_attr(feature = "clap", value(name = "forbid"))]
355  Forbid,
356}
357
358impl SmtpUtf8Policy {
359  /// Returns the stable policy name.
360  #[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  /// Returns `true` if this policy accepts UTF-8 local-parts.
369  #[cfg_attr(not(coverage), inline(always))]
370  pub const fn is_allow(&self) -> bool {
371    matches!(self, Self::Allow)
372  }
373
374  /// Returns `true` if this policy rejects non-ASCII local-parts.
375  #[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/// Policy for address-literal domain-parts.
415#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash)]
416#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
417#[non_exhaustive]
418pub enum DomainLiteralPolicy {
419  /// Accept address-literal domains.
420  #[default]
421  #[cfg_attr(feature = "clap", value(name = "allow"))]
422  Allow,
423  /// Reject address-literal domains.
424  #[cfg_attr(feature = "clap", value(name = "forbid"))]
425  Forbid,
426}
427
428impl DomainLiteralPolicy {
429  /// Returns the stable policy name.
430  #[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  /// Returns `true` if address-literal domains are accepted.
439  #[cfg_attr(not(coverage), inline(always))]
440  pub const fn is_allow(&self) -> bool {
441    matches!(self, Self::Allow)
442  }
443
444  /// Returns `true` if address-literal domains are rejected.
445  #[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/// Policy for Unicode domain input.
485#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash)]
486#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
487#[non_exhaustive]
488pub enum DomainUnicodePolicy {
489  /// Reject non-ASCII domain input.
490  #[cfg_attr(feature = "clap", value(name = "ascii", alias("ascii_only")))]
491  AsciiOnly,
492  /// Accept Unicode domain input only through IDNA normalization.
493  #[default]
494  #[cfg_attr(feature = "clap", value(name = "idna"))]
495  Idna,
496  /// Preserve non-ASCII UTF-8 DNS labels as non-standard application data.
497  #[cfg_attr(
498    feature = "clap",
499    value(name = "raw", alias("raw_utf8"), alias("non_standard_utf8"))
500  )]
501  NonStandardUtf8,
502}
503
504impl DomainUnicodePolicy {
505  /// Returns the stable policy name.
506  #[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  /// Returns `true` if non-ASCII domain input is rejected.
516  #[cfg_attr(not(coverage), inline(always))]
517  pub const fn is_ascii_only(&self) -> bool {
518    matches!(self, Self::AsciiOnly)
519  }
520
521  /// Returns `true` if Unicode domain input uses IDNA normalization.
522  #[cfg_attr(not(coverage), inline(always))]
523  pub const fn is_idna(&self) -> bool {
524    matches!(self, Self::Idna)
525  }
526
527  /// Returns `true` if non-ASCII UTF-8 DNS labels are preserved.
528  #[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}