better_url/
better_host.rs1use std::str::FromStr;
4
5#[cfg(feature = "serde")]
6use serde::{Serialize, Deserialize, ser::Serializer, de::{Visitor, Deserializer, Error}};
7
8use crate::*;
9
10#[derive(Debug, Clone)]
12pub struct BetterHost {
13 string: String,
15 details: HostDetails
17}
18
19impl BetterHost {
20 pub fn host_str(&self) -> &str {
22 &self.string
23 }
24
25 pub fn host_details(&self) -> &HostDetails {
27 &self.details
28 }
29
30 pub fn domain_details(&self) -> Option<&DomainDetails> {
32 self.host_details().domain_details()
33 }
34
35 pub fn ipv4_details(&self) -> Option<&Ipv4Details> {
37 self.host_details().ipv4_details()
38 }
39
40 pub fn ipv6_details(&self) -> Option<&Ipv6Details> {
42 self.host_details().ipv6_details()
43 }
44
45 pub fn normalized_host(&self) -> &str {
47 let mut ret = self.host_str();
48 ret = ret.strip_prefix("www.").unwrap_or(ret);
49 ret = ret.strip_suffix(".").unwrap_or(ret);
50 ret
51 }
52
53 pub fn domain(&self) -> Option<&str> {
55 self.host_str().get(self.domain_details()?.domain_bounds())
56 }
57
58 pub fn subdomain(&self) -> Option<&str> {
60 self.host_str().get(self.domain_details()?.subdomain_bounds()?)
61 }
62
63 pub fn not_domain_suffix(&self) -> Option<&str> {
65 self.host_str().get(self.domain_details()?.not_domain_suffix_bounds()?)
66 }
67
68 pub fn domain_middle(&self) -> Option<&str> {
70 self.host_str().get(self.domain_details()?.domain_middle_bounds()?)
71 }
72
73 pub fn reg_domain(&self) -> Option<&str> {
75 self.host_str().get(self.domain_details()?.reg_domain_bounds()?)
76 }
77
78 pub fn domain_suffix(&self) -> Option<&str> {
80 self.host_str().get(self.domain_details()?.domain_suffix_bounds()?)
81 }
82}
83
84impl PartialEq for BetterHost {
85 fn eq(&self, other: &Self) -> bool {
86 self.string == other.string
87 }
88}
89impl Eq for BetterHost {}
90
91impl FromStr for BetterHost {
92 type Err = <HostDetails as FromStr>::Err;
93
94 fn from_str(s: &str) -> Result<Self, Self::Err> {
95 Ok(Self {
96 details: s.parse()?,
97 string: s.into()
98 })
99 }
100}
101
102impl TryFrom<&str> for BetterHost {
103 type Error = <Self as FromStr>::Err;
104
105 fn try_from(value: &str) -> Result<Self, Self::Error> {
106 value.parse()
107 }
108}
109
110impl TryFrom<String> for BetterHost {
111 type Error = <Self as FromStr>::Err;
112
113 fn try_from(value: String) -> Result<Self, Self::Error> {
114 Ok(Self {
115 details: value.parse()?,
116 string: value
117 })
118 }
119}
120
121impl From<BetterHost> for String {
122 fn from(value: BetterHost) -> String {
123 value.string
124 }
125}
126
127impl std::fmt::Display for BetterHost {
128 fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
129 write!(formatter, "{}", self.string)
130 }
131}
132
133#[cfg(feature = "serde")]
135struct BetterHostVisitor;
136
137#[cfg(feature = "serde")]
138impl<'de> Visitor<'de> for BetterHostVisitor {
139 type Value = BetterHost;
140
141 fn visit_str<E: Error>(self, s: &str) -> Result<Self::Value, E> {
142 s.try_into().map_err(E::custom)
143 }
144
145 fn visit_string<E: Error>(self, s: String) -> Result<Self::Value, E> {
146 s.try_into().map_err(E::custom)
147 }
148
149 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150 write!(formatter, "Expected a string")
151 }
152}
153
154#[cfg(feature = "serde")]
155impl<'de> Deserialize<'de> for BetterHost {
156 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
157 deserializer.deserialize_any(BetterHostVisitor)
158 }
159}
160
161#[cfg(feature = "serde")]
162impl Serialize for BetterHost {
163 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
164 serializer.serialize_str(&self.string)
165 }
166}