1use std::convert::TryInto;
2
3use super::{Authority, Parts, PathAndQuery, Scheme};
4use crate::Uri;
5
6#[derive(Debug)]
11pub struct Builder {
12 parts: Result<Parts, crate::Error>,
13}
14
15impl Builder {
16 #[inline]
31 pub fn new() -> Builder {
32 Builder::default()
33 }
34
35 pub fn scheme<T>(self, scheme: T) -> Self
46 where
47 T: TryInto<Scheme>,
48 <T as TryInto<Scheme>>::Error: Into<crate::Error>,
49 {
50 self.map(move |mut parts| {
51 let scheme = scheme.try_into().map_err(Into::into)?;
52 parts.scheme = Some(scheme);
53 Ok(parts)
54 })
55 }
56
57 pub fn authority<T>(self, auth: T) -> Self
70 where
71 T: TryInto<Authority>,
72 <T as TryInto<Authority>>::Error: Into<crate::Error>,
73 {
74 self.map(move |mut parts| {
75 let auth = auth.try_into().map_err(Into::into)?;
76 parts.authority = Some(auth);
77 Ok(parts)
78 })
79 }
80
81 pub fn path_and_query<T>(self, p_and_q: T) -> Self
94 where
95 T: TryInto<PathAndQuery>,
96 <T as TryInto<PathAndQuery>>::Error: Into<crate::Error>,
97 {
98 self.map(move |mut parts| {
99 let p_and_q = match p_and_q.try_into() {
100 Ok(p_and_q) => p_and_q,
101 Err(err) => {
102 let err = err.into();
103 if err.is_empty_uri() {
104 PathAndQuery::empty()
105 } else {
106 return Err(err);
107 }
108 }
109 };
110 parts.path_and_query = Some(p_and_q);
111 Ok(parts)
112 })
113 }
114
115 pub fn build(self) -> Result<Uri, crate::Error> {
140 let parts = self.parts?;
141 Uri::from_parts(parts).map_err(Into::into)
142 }
143
144 fn map<F>(self, func: F) -> Self
147 where
148 F: FnOnce(Parts) -> Result<Parts, crate::Error>,
149 {
150 Builder {
151 parts: self.parts.and_then(func),
152 }
153 }
154}
155
156impl Default for Builder {
157 #[inline]
158 fn default() -> Builder {
159 Builder {
160 parts: Ok(Parts::default()),
161 }
162 }
163}
164
165impl From<Uri> for Builder {
166 fn from(uri: Uri) -> Self {
167 Self {
168 parts: Ok(uri.into_parts()),
169 }
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn build_from_str() {
179 let uri = Builder::new()
180 .scheme(Scheme::HTTP)
181 .authority("hyper.rs")
182 .path_and_query("/foo?a=1")
183 .build()
184 .unwrap();
185 assert_eq!(uri.scheme_str(), Some("http"));
186 assert_eq!(uri.authority().unwrap().host(), "hyper.rs");
187 assert_eq!(uri.path(), "/foo");
188 assert_eq!(uri.query(), Some("a=1"));
189 }
190
191 #[test]
192 fn build_from_string() {
193 for i in 1..10 {
194 let uri = Builder::new()
195 .path_and_query(format!("/foo?a={}", i))
196 .build()
197 .unwrap();
198 let expected_query = format!("a={}", i);
199 assert_eq!(uri.path(), "/foo");
200 assert_eq!(uri.query(), Some(expected_query.as_str()));
201 }
202 }
203
204 #[test]
205 fn build_from_string_ref() {
206 for i in 1..10 {
207 let p_a_q = format!("/foo?a={}", i);
208 let uri = Builder::new().path_and_query(&p_a_q).build().unwrap();
209 let expected_query = format!("a={}", i);
210 assert_eq!(uri.path(), "/foo");
211 assert_eq!(uri.query(), Some(expected_query.as_str()));
212 }
213 }
214
215 #[test]
216 fn build_from_empty_path_and_query() {
217 let uri = Builder::new()
218 .scheme(Scheme::HTTP)
219 .authority("localhost:8080")
220 .path_and_query("")
221 .build()
222 .unwrap();
223
224 assert_eq!(uri, "http://localhost:8080");
225 assert_eq!(uri.path(), "/");
226 }
227
228 #[test]
229 fn empty_path_and_query_remains_strict() {
230 assert!(PathAndQuery::try_from("").is_err());
231 }
232
233 #[test]
234 fn authority_form_path_and_query_remains_strict() {
235 assert!(Builder::new()
236 .path_and_query("localhost:8080")
237 .build()
238 .is_err());
239 }
240
241 #[test]
242 fn build_from_uri() {
243 let original_uri = Uri::default();
244 let uri = Builder::from(original_uri.clone()).build().unwrap();
245 assert_eq!(original_uri, uri);
246 }
247
248 #[test]
249 fn build_star_for_http2() {
250 let uri = Builder::new()
251 .scheme("https")
252 .authority("example.com")
253 .path_and_query("*")
254 .build()
255 .unwrap();
256
257 assert_eq!(uri.scheme(), Some(&Scheme::HTTPS));
258 assert_eq!(uri.host(), Some("example.com"));
259 assert_eq!(uri.path(), "*");
260 }
261}