1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use std::fmt::Display;

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::{
    fqdn::FullyQualifiedDomainNameError,
    segment::{DomainSegment, DomainSegmentError},
    FullyQualifiedDomainName, PartiallyQualifiedDomainName,
};

#[derive(
    Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord,
)]
pub enum DomainName {
    Full(FullyQualifiedDomainName),
    Partial(PartiallyQualifiedDomainName),
}

impl DomainName {
    pub fn is_fully_qualified(&self) -> bool {
        match self {
            DomainName::Full(_) => true,
            DomainName::Partial(_) => false,
        }
    }

    pub fn is_partially_qualified(&self) -> bool {
        match self {
            DomainName::Full(_) => false,
            DomainName::Partial(_) => true,
        }
    }

    pub fn as_partial(&self) -> Option<&PartiallyQualifiedDomainName> {
        match self {
            DomainName::Partial(partial) => Some(partial),
            _ => None,
        }
    }

    pub fn as_full(&self) -> Option<&FullyQualifiedDomainName> {
        match self {
            DomainName::Full(full) => Some(full),
            _ => None,
        }
    }
}

impl Default for DomainName {
    fn default() -> Self {
        DomainName::Full(FullyQualifiedDomainName::default())
    }
}

impl From<PartiallyQualifiedDomainName> for DomainName {
    fn from(value: PartiallyQualifiedDomainName) -> Self {
        DomainName::Partial(value)
    }
}

impl From<FullyQualifiedDomainName> for DomainName {
    fn from(value: FullyQualifiedDomainName) -> Self {
        DomainName::Full(value)
    }
}

impl TryFrom<String> for DomainName {
    type Error = DomainSegmentError;

    fn try_from(value: String) -> Result<Self, Self::Error> {
        Self::try_from(value.as_str())
    }
}

impl TryFrom<&str> for DomainName {
    type Error = DomainSegmentError;

    fn try_from(value: &str) -> Result<Self, Self::Error> {
        match FullyQualifiedDomainName::try_from(value) {
            Ok(fqdn) => Ok(DomainName::Full(fqdn)),
            Err(FullyQualifiedDomainNameError::DomainIsPartiallyQualified) => Ok(
                DomainName::Partial(PartiallyQualifiedDomainName::try_from(value).unwrap()),
            ),
            Err(FullyQualifiedDomainNameError::SegmentError(err)) => Err(err),
        }
    }
}

impl Display for DomainName {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            DomainName::Full(full) => full.fmt(f),
            DomainName::Partial(partial) => partial.fmt(f),
        }
    }
}

impl AsRef<[DomainSegment]> for DomainName {
    fn as_ref(&self) -> &[DomainSegment] {
        match self {
            DomainName::Full(full) => full.as_ref(),
            DomainName::Partial(partial) => partial.as_ref(),
        }
    }
}

impl PartialEq<PartiallyQualifiedDomainName> for DomainName {
    fn eq(&self, other: &PartiallyQualifiedDomainName) -> bool {
        match self {
            DomainName::Full(_) => false,
            DomainName::Partial(partial) => partial.eq(other),
        }
    }
}

impl PartialEq<FullyQualifiedDomainName> for DomainName {
    fn eq(&self, other: &FullyQualifiedDomainName) -> bool {
        match self {
            DomainName::Full(full) => full.eq(other),
            DomainName::Partial(_) => false,
        }
    }
}