nym_http_api_client/
url.rs1use std::fmt::Display;
7
8use itertools::Itertools;
9pub use url::ParseError;
10use url::form_urlencoded;
11
12pub trait IntoUrl {
14 fn to_url(self) -> Result<Url, ParseError>;
16
17 fn as_str(&self) -> &str;
19}
20
21impl IntoUrl for &str {
22 fn to_url(self) -> Result<Url, ParseError> {
23 let url = url::Url::parse(self)?;
24 Ok(url.into())
25 }
26
27 fn as_str(&self) -> &str {
28 self
29 }
30}
31
32impl IntoUrl for String {
33 fn to_url(self) -> Result<Url, ParseError> {
34 let url = url::Url::parse(&self)?;
35 Ok(url.into())
36 }
37
38 fn as_str(&self) -> &str {
39 self
40 }
41}
42
43impl IntoUrl for reqwest::Url {
44 fn to_url(self) -> Result<Url, ParseError> {
45 Ok(self.into())
46 }
47
48 fn as_str(&self) -> &str {
49 self.as_str()
50 }
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, Hash)]
60pub struct Url {
61 url: url::Url,
62 fronts: Option<Vec<url::Url>>,
63}
64
65impl IntoUrl for Url {
66 fn to_url(self) -> Result<Url, ParseError> {
67 Ok(self)
68 }
69
70 fn as_str(&self) -> &str {
71 self.url.as_str()
72 }
73}
74
75impl Display for Url {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 write!(f, "{}", self.url)
78 }
79}
80
81impl From<Url> for url::Url {
82 fn from(val: Url) -> Self {
83 val.url
84 }
85}
86
87impl From<reqwest::Url> for Url {
88 fn from(url: url::Url) -> Self {
89 Self { url, fronts: None }
90 }
91}
92
93impl From<&reqwest::Url> for Url {
94 fn from(url: &url::Url) -> Self {
95 Self {
96 url: url.clone(),
97 fronts: None,
98 }
99 }
100}
101
102impl AsRef<url::Url> for Url {
103 fn as_ref(&self) -> &url::Url {
104 &self.url
105 }
106}
107
108impl AsMut<url::Url> for Url {
109 fn as_mut(&mut self) -> &mut url::Url {
110 &mut self.url
111 }
112}
113
114impl std::str::FromStr for Url {
115 type Err = url::ParseError;
116
117 fn from_str(s: &str) -> Result<Self, Self::Err> {
118 let url = url::Url::parse(s)?;
119 Ok(Self { url, fronts: None })
120 }
121}
122
123impl Url {
124 pub fn new<U: reqwest::IntoUrl>(
127 url: U,
128 fronts: Option<Vec<U>>,
129 ) -> Result<Self, reqwest::Error> {
130 let mut url = Self {
131 url: url.into_url()?,
132 fronts: None,
133 };
134
135 if let Some(front_domains) = fronts {
137 let f: Vec<reqwest::Url> = front_domains
138 .into_iter()
139 .map(|front| front.into_url())
140 .try_collect()?;
141 url.fronts = Some(f);
142 }
143
144 Ok(url)
145 }
146
147 pub fn parse(s: &str) -> Result<Self, ParseError> {
149 let url = url::Url::parse(s)?;
150 Ok(Self { url, fronts: None })
151 }
152
153 pub fn inner_url(&self) -> &url::Url {
155 &self.url
156 }
157
158 pub fn has_front(&self) -> bool {
160 if let Some(fronts) = &self.fronts {
161 return !fronts.is_empty();
162 }
163 false
164 }
165
166 pub fn first_front_str(&self) -> Option<&str> {
173 self.fronts.as_ref()?.first()?.host_str()
174 }
175
176 pub fn fronts(&self) -> Option<&[url::Url]> {
178 self.fronts.as_deref()
179 }
180
181 pub fn host_str(&self) -> Option<&str> {
183 self.url.host_str()
184 }
185
186 pub fn as_str(&self) -> &str {
191 self.url.as_str()
192 }
193
194 pub fn scheme(&self) -> &str {
196 self.url.scheme()
197 }
198
199 pub fn query_pairs(&self) -> form_urlencoded::Parse<'_> {
202 self.url.query_pairs()
203 }
204
205 pub fn query_pairs_mut(&mut self) -> form_urlencoded::Serializer<'_, ::url::UrlQuery<'_>> {
208 self.url.query_pairs_mut()
209 }
210
211 pub fn set_query(&mut self, query: Option<&str>) {
213 self.url.set_query(query);
214 }
215
216 pub fn set_path(&mut self, path: &str) {
218 self.url.set_path(path);
219 }
220
221 pub fn set_scheme(&mut self, scheme: &str) {
223 self.url.set_scheme(scheme).unwrap();
224 }
225
226 pub fn set_host(&mut self, host: &str) {
230 self.url.set_host(Some(host)).unwrap();
231 }
232
233 pub fn set_port(&mut self, port: u16) {
239 self.url.set_port(Some(port)).unwrap();
240 }
241
242 pub fn path_segments(&self) -> Option<std::str::Split<'_, char>> {
246 self.url.path_segments()
247 }
248
249 #[allow(clippy::result_unit_err)]
253 pub fn path_segments_mut(&mut self) -> Result<::url::PathSegmentsMut<'_>, ()> {
254 self.url.path_segments_mut()
255 }
256}