1pub fn uri() -> Uri {
18 Uri::default()
19}
20
21#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
23pub struct Uri(url::Url);
24
25impl std::fmt::Debug for Uri {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 f.debug_tuple("Uri").field(&self.as_str()).finish()
28 }
29}
30
31impl std::fmt::Display for Uri {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 self.as_str().fmt(f)
34 }
35}
36
37impl std::convert::TryFrom<&str> for Uri {
38 type Error = url::ParseError;
39 fn try_from(t: &str) -> Result<Self, Self::Error> {
40 Self::new(t)
41 }
42}
43
44#[cfg(feature = "actix-web")]
45impl From<&actix_web::http::uri::Uri> for Uri {
46 fn from(t: &actix_web::http::uri::Uri) -> Self {
47 Self::default()
48 .with_path(t.path())
49 .with_query(t.query())
50 }
51}
52
53impl AsRef<str> for Uri {
54 fn as_ref(&self) -> &str {
55 self.as_str()
56 }
57}
58
59impl Default for Uri {
60 fn default() -> Self {
61 Self(Self::base_url())
62 }
63}
64
65impl Uri {
66 fn base_url() -> url::Url {
67 use once_cell::sync::Lazy;
68 static URL: Lazy<url::Url> =
69 Lazy::new(|| "http://_".parse().expect("`http://_` is a valid `URL`"));
70 URL.clone()
71 }
72
73 pub fn new(input: &str) -> Result<Self, url::ParseError> {
75 Self::base_url().join(input).map(Self)
76 }
77
78 pub fn join(&self, input: &str) -> Result<Self, url::ParseError> {
80 self.0.join(input).map(Self)
81 }
82
83 pub fn as_str(&self) -> &str {
85 &self.0[url::Position::BeforePath..]
86 }
87
88 pub fn path(&self) -> &str {
90 self.0.path()
91 }
92
93 pub fn query(&self) -> Option<&str> {
95 self.0.query()
96 }
97
98 pub fn fragment(&self) -> Option<&str> {
100 self.0.fragment()
101 }
102
103 pub fn path_segments(&self) -> std::str::Split<char> {
105 self.0.path_segments().expect("`Uri` is always-a-base")
106 }
107
108 pub fn path_segments_mut(&mut self) -> url::PathSegmentsMut {
110 self.0.path_segments_mut().expect("`Uri` is always-a-base")
111 }
112
113 pub fn query_pairs(&self) -> url::form_urlencoded::Parse {
115 self.0.query_pairs()
116 }
117
118 pub fn query_pairs_mut(&mut self) -> url::form_urlencoded::Serializer<url::UrlQuery> {
120 self.0.query_pairs_mut()
121 }
122
123 pub fn set_path(&mut self, path: &str) {
125 self.0.set_path(path)
126 }
127
128 pub fn set_query(&mut self, query: Option<&str>) {
130 self.0.set_query(query)
131 }
132
133 pub fn set_fragment(&mut self, fragment: Option<&str>) {
135 self.0.set_fragment(fragment)
136 }
137
138 pub fn with_path(mut self, path: &str) -> Self {
140 self.set_path(path);
141 self
142 }
143
144 pub fn with_query(mut self, query: Option<&str>) -> Self {
146 self.set_query(query);
147 self
148 }
149
150 pub fn with_fragment(mut self, fragment: Option<&str>) -> Self {
152 self.set_fragment(fragment);
153 self
154 }
155
156 pub fn with_path_segments_mut<F>(mut self, cls: F) -> Self
158 where
159 F: for<'a, 'b> Fn(&'b mut url::PathSegmentsMut<'a>) -> &'b mut url::PathSegmentsMut<'a>,
160 {
161 {
162 let mut path_segments_mut = self.path_segments_mut();
163 cls(&mut path_segments_mut);
164 }
165 self
166 }
167
168 pub fn with_query_pairs_mut<F>(mut self, cls: F) -> Self
170 where
171 F: for<'a, 'b> Fn(
172 &'b mut url::form_urlencoded::Serializer<'a, url::UrlQuery<'a>>,
173 )
174 -> &'b mut url::form_urlencoded::Serializer<'a, url::UrlQuery<'a>>,
175 {
176 {
177 let mut query_pairs_mut = self.query_pairs_mut();
178 cls(&mut query_pairs_mut);
179 }
180 self
181 }
182}
183
184#[cfg(test)]
185mod tests {
186
187 use super::*;
188
189 #[test]
190 fn it_works() {
191
192 let uri = Uri::default()
193 .with_path_segments_mut(|p| p.push("foo"));
194
195 assert_eq!("Uri(\"/foo\")", format!("{:?}", &uri));
196
197 let mut uri = Uri::new("../../../foo.html?lorem=ipsum").unwrap();
198
199 assert_eq!("/foo.html?lorem=ipsum", uri.as_str());
200
201 uri.query_pairs_mut().clear().append_pair("foo", "bar & baz");
202
203 assert_eq!("/foo.html?foo=bar+%26+baz", uri.as_str());
204
205 let mut uri = Uri::default();
206
207 uri.path_segments_mut().extend(&["foo", "bar", "baz"]);
208
209 assert_eq!("/foo/bar/baz", uri.as_str());
210
211 let uri = uri.join("/baz").unwrap();
212
213 assert_eq!("/baz", uri.as_str());
214
215 let mut uri = uri.join("?foo=bar").unwrap();
216
217 assert_eq!("/baz?foo=bar", uri.as_str());
218
219 uri.path_segments_mut().clear();
220
221 assert_eq!("/?foo=bar", uri.as_str());
222
223 let uri = Uri::default()
224 .with_path_segments_mut(|p| p.extend(&["foo", "bar"]))
225 .with_query_pairs_mut(|q| q.append_pair("foo", "bar"))
226 .with_fragment(Some("baz"));
227
228 assert_eq!("/foo/bar?foo=bar#baz", uri.as_str());
229
230 let uri = Uri::default().with_path("/a/b/c/d/e/f/g");
231
232 let uri = uri.join("../../../../..").unwrap();
233
234 assert_eq!("/a/", uri.as_str());
235
236 }
237}