uriparse/
uri.rs

1//! URIs, Relative References, and URI References
2//!
3//! See [RFC3986](https://tools.ietf.org/html/rfc3986).
4//!
5//! This module is composed of three primary types [`URI`], [`RelativeReference`], and
6//! [`URIReference`] that are all very similar. The first thing to note is that URIs and relative
7//! references are types of URI references. They differ in only one way: URIs have schemes, while
8//! relative references do not.
9//!
10//! As a result, choose the type that best fits your use case. If you need absolute URIs, you should
11//! use [`URI`], but if you want relative references (e.g. `"/"` in a GET request) use
12//! [`RelativeReference`]. If you can accept both, then use [`URIReference`].
13
14use std::convert::{Infallible, TryFrom};
15use std::error::Error;
16use std::fmt::{self, Display, Formatter};
17
18use crate::authority::{Authority, AuthorityError, Host, Password, Username};
19use crate::fragment::{Fragment, FragmentError};
20use crate::path::{Path, PathError};
21use crate::query::{Query, QueryError};
22use crate::scheme::{Scheme, SchemeError};
23use crate::uri_reference::{URIReference, URIReferenceBuilder, URIReferenceError};
24
25/// A Uniform Resource Identifier (URI) as defined in
26/// [RFC3986](https://tools.ietf.org/html/rfc3986).
27///
28/// A URI is a URI reference, one with a scheme.
29#[derive(Clone, Debug, Eq, Hash, PartialEq)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31pub struct URI<'uri> {
32    /// All URIs are also URI references, so we just maintain a [`URIReference`] underneath.
33    uri_reference: URIReference<'uri>,
34}
35
36impl<'uri> URI<'uri> {
37    pub fn as_uri_reference(&self) -> &URIReference<'uri> {
38        &self.uri_reference
39    }
40
41    /// Returns the authority, if present, of the URI.
42    ///
43    /// # Examples
44    ///
45    /// ```
46    /// use std::convert::TryFrom;
47    ///
48    /// use uriparse::URI;
49    ///
50    /// let uri = URI::try_from("http://example.com:80/my/path").unwrap();
51    /// assert_eq!(uri.authority().unwrap().to_string(), "example.com:80");
52    /// ```
53    pub fn authority(&self) -> Option<&Authority<'uri>> {
54        self.uri_reference.authority()
55    }
56
57    /// Constructs a default builder for a URI.
58    ///
59    /// This provides an alternative means of constructing a URI besides parsing and
60    /// [`URI::from_parts`].
61    ///
62    /// # Examples
63    ///
64    /// ```
65    /// use std::convert::TryFrom;
66    ///
67    /// use uriparse::{Authority, Path, Scheme, URI};
68    ///
69    /// let uri = URI::builder()
70    ///     .with_scheme(Scheme::HTTP)
71    ///     .with_authority(Some(Authority::try_from("example.com").unwrap()))
72    ///     .with_path(Path::try_from("/my/path").unwrap())
73    ///     .build()
74    ///     .unwrap();
75    /// assert_eq!(uri.to_string(), "http://example.com/my/path");
76    /// ```
77    pub fn builder<'new_uri>() -> URIBuilder<'new_uri> {
78        URIBuilder::new()
79    }
80
81    /// Returns whether the URI can act as a base URI.
82    ///
83    /// A URI can be a base if it is absolute (i.e. it has no fragment component).
84    ///
85    /// # Examples
86    ///
87    /// ```
88    /// use std::convert::TryFrom;
89    ///
90    /// use uriparse::URI;
91    ///
92    /// let uri = URI::try_from("http://example.com/my/path").unwrap();
93    /// assert!(uri.can_be_a_base());
94    ///
95    /// let uri = URI::try_from("ftp://127.0.0.1#fragment").unwrap();
96    /// assert!(!uri.can_be_a_base());
97    /// ```
98    pub fn can_be_a_base(&self) -> bool {
99        !self.uri_reference.has_fragment()
100    }
101
102    /// Constructs a new [`URI`] from the individual parts: scheme, authority, path, query, and
103    /// fragment.
104    ///
105    /// The lifetime used by the resulting value will be the lifetime of the part that is most
106    /// restricted in scope.
107    ///
108    /// # Examples
109    ///
110    /// ```
111    /// use std::convert::TryFrom;
112    ///
113    /// use uriparse::{Fragment, URI};
114    ///
115    /// let uri = URI::from_parts(
116    ///     "http",
117    ///     Some("example.com"),
118    ///     "",
119    ///     Some("query"),
120    ///     None::<Fragment>
121    /// ).unwrap();
122    /// assert_eq!(uri.to_string(), "http://example.com/?query");
123    /// ```
124    pub fn from_parts<
125        'new_uri,
126        TScheme,
127        TAuthority,
128        TPath,
129        TQuery,
130        TFragment,
131        TSchemeError,
132        TAuthorityError,
133        TPathError,
134        TQueryError,
135        TFragmentError,
136    >(
137        scheme: TScheme,
138        authority: Option<TAuthority>,
139        path: TPath,
140        query: Option<TQuery>,
141        fragment: Option<TFragment>,
142    ) -> Result<URI<'new_uri>, URIError>
143    where
144        Scheme<'new_uri>: TryFrom<TScheme, Error = TSchemeError>,
145        Authority<'new_uri>: TryFrom<TAuthority, Error = TAuthorityError>,
146        Path<'new_uri>: TryFrom<TPath, Error = TPathError>,
147        Query<'new_uri>: TryFrom<TQuery, Error = TQueryError>,
148        Fragment<'new_uri>: TryFrom<TFragment, Error = TFragmentError>,
149        URIReferenceError: From<TSchemeError>
150            + From<TAuthorityError>
151            + From<TPathError>
152            + From<TQueryError>
153            + From<TFragmentError>,
154    {
155        let uri_reference =
156            URIReference::from_parts(Some(scheme), authority, path, query, fragment)
157                .map_err(|error| URIError::try_from(error).unwrap())?;
158        Ok(URI { uri_reference })
159    }
160
161    /// Returns the fragment, if present, of the URI.
162    ///
163    /// # Examples
164    ///
165    /// ```
166    /// use std::convert::TryFrom;
167    ///
168    /// use uriparse::URI;
169    ///
170    /// let uri = URI::try_from("http://example.com#fragment").unwrap();
171    /// assert_eq!(uri.fragment().unwrap(), "fragment");
172    /// ```
173    pub fn fragment(&self) -> Option<&Fragment<'uri>> {
174        self.uri_reference.fragment()
175    }
176
177    /// Returns whether the URI has an authority component.
178    ///
179    /// # Examples
180    ///
181    /// ```
182    /// use std::convert::TryFrom;
183    ///
184    /// use uriparse::URI;
185    ///
186    /// let uri = URI::try_from("http://example.com").unwrap();
187    /// assert!(uri.has_authority());
188    ///
189    /// let uri = URI::try_from("urn:test").unwrap();
190    /// assert!(!uri.has_authority());
191    /// ```
192    pub fn has_authority(&self) -> bool {
193        self.uri_reference.has_authority()
194    }
195
196    /// Returns whether the URI has a fragment component.
197    ///
198    /// # Examples
199    ///
200    /// ```
201    /// use std::convert::TryFrom;
202    ///
203    /// use uriparse::URI;
204    ///
205    /// let uri = URI::try_from("http://example.com#test").unwrap();
206    /// assert!(uri.has_fragment());
207    ///
208    /// let uri = URI::try_from("http://example.com").unwrap();
209    /// assert!(!uri.has_fragment());
210    /// ```
211    pub fn has_fragment(&self) -> bool {
212        self.uri_reference.has_fragment()
213    }
214
215    /// Returns whether the URI has a password component.
216    ///
217    /// # Examples
218    ///
219    /// ```
220    /// use std::convert::TryFrom;
221    ///
222    /// use uriparse::URI;
223    ///
224    /// let uri = URI::try_from("http://user:pass@127.0.0.1").unwrap();
225    /// assert!(uri.has_password());
226    ///
227    /// let uri = URI::try_from("http://user@127.0.0.1").unwrap();
228    /// assert!(!uri.has_password());
229    /// ```
230    pub fn has_password(&self) -> bool {
231        self.uri_reference.has_password()
232    }
233
234    /// Returns whether the URI has a port.
235    ///
236    /// # Examples
237    ///
238    /// ```
239    /// use std::convert::TryFrom;
240    ///
241    /// use uriparse::URI;
242    ///
243    /// let uri = URI::try_from("http://127.0.0.1:8080").unwrap();
244    /// assert!(uri.has_port());
245    ///
246    /// let uri = URI::try_from("http://127.0.0.1").unwrap();
247    /// assert!(!uri.has_port());
248    /// ```
249    pub fn has_port(&self) -> bool {
250        self.uri_reference.has_port()
251    }
252
253    /// Returns whether the URI has a query component.
254    ///
255    /// # Examples
256    ///
257    /// ```
258    /// use std::convert::TryFrom;
259    ///
260    /// use uriparse::URI;
261    ///
262    /// let uri = URI::try_from("http://example.com/my/path?my=query").unwrap();
263    /// assert!(uri.has_query());
264    ///
265    /// let uri = URI::try_from("http://example.com/my/path").unwrap();
266    /// assert!(!uri.has_query());
267    /// ```
268    pub fn has_query(&self) -> bool {
269        self.uri_reference.has_query()
270    }
271
272    /// Returns whether the URI has a username component.
273    ///
274    /// # Examples
275    ///
276    /// ```
277    /// use std::convert::TryFrom;
278    ///
279    /// use uriparse::URI;
280    ///
281    /// let uri = URI::try_from("http://username@example.com").unwrap();
282    /// assert!(uri.has_username());
283    ///
284    /// let uri = URI::try_from("http://example.com").unwrap();
285    /// assert!(!uri.has_username());
286    /// ```
287    pub fn has_username(&self) -> bool {
288        self.uri_reference.has_username()
289    }
290
291    /// Returns the host, if present, of the URI.
292    ///
293    /// # Examples
294    ///
295    /// ```
296    /// use std::convert::TryFrom;
297    ///
298    /// use uriparse::URI;
299    ///
300    /// let uri = URI::try_from("http://username@example.com").unwrap();
301    /// assert_eq!(uri.host().unwrap().to_string(), "example.com");
302    /// ```
303    pub fn host(&self) -> Option<&Host<'uri>> {
304        self.uri_reference.host()
305    }
306
307    /// Converts the URI into a base URI (i.e. the fragment component is removed).
308    ///
309    /// # Examples
310    ///
311    /// ```
312    /// use std::convert::TryFrom;
313    ///
314    /// use uriparse::URI;
315    ///
316    /// let uri = URI::try_from("http://example.com#fragment").unwrap();
317    /// assert_eq!(uri.to_string(), "http://example.com/#fragment");
318    /// let uri = uri.into_base_uri();
319    /// assert_eq!(uri.to_string(), "http://example.com/");
320    /// ```
321    pub fn into_base_uri(self) -> URI<'uri> {
322        let (scheme, authority, path, query, _) = self.uri_reference.into_parts();
323        let uri_reference =
324            URIReference::from_parts(scheme, authority, path, query, None::<Fragment>).unwrap();
325        URI { uri_reference }
326    }
327
328    /// Consumes the URI and converts it into a builder with the same values.
329    ///
330    /// # Examples
331    ///
332    /// ```
333    /// use std::convert::TryFrom;
334    ///
335    /// use uriparse::{Fragment, Query, URI};
336    ///
337    /// let uri = URI::try_from("http://example.com/path?query#fragment").unwrap();
338    /// let mut builder = uri.into_builder();
339    /// builder.query(None::<Query>).fragment(None::<Fragment>);
340    /// let uri = builder.build().unwrap();
341    /// assert_eq!(uri.to_string(), "http://example.com/path");
342    /// ```
343    pub fn into_builder(self) -> URIBuilder<'uri> {
344        let (scheme, authority, path, query, fragment) = self.uri_reference.into_parts();
345        let mut builder = URIBuilder::new();
346        builder
347            .scheme(scheme.unwrap())
348            .authority(authority)
349            .path(path)
350            .query(query)
351            .fragment(fragment);
352        builder
353    }
354
355    /// Converts the [`URI`] into an owned copy.
356    ///
357    /// If you construct the URI from a source with a non-static lifetime, you may run into
358    /// lifetime problems due to the way the struct is designed. Calling this function will ensure
359    /// that the returned value has a static lifetime.
360    ///
361    /// This is different from just cloning. Cloning the URI will just copy the references, and thus
362    /// the lifetime will remain the same.
363    pub fn into_owned(self) -> URI<'static> {
364        URI {
365            uri_reference: self.uri_reference.into_owned(),
366        }
367    }
368
369    /// Consumes the [`URI`] and returns its parts: scheme, authority, path, query, and fragment.
370    ///
371    /// # Examples
372    ///
373    /// ```
374    /// use std::convert::TryFrom;
375    ///
376    /// use uriparse::URI;
377    ///
378    /// let uri = URI::try_from(
379    ///     "http://username:password@example.com:80/my/path?my=query#fragment",
380    /// ).unwrap();
381    /// let (scheme, authority, path, query, fragment) = uri.into_parts();
382    ///
383    /// assert_eq!(scheme, "http");
384    /// assert_eq!(authority.unwrap().to_string(), "username:password@example.com:80");
385    /// assert_eq!(path, "/my/path");
386    /// assert_eq!(query.unwrap(), "my=query");
387    /// assert_eq!(fragment.unwrap(), "fragment");
388    /// ```
389    pub fn into_parts(
390        self,
391    ) -> (
392        Scheme<'uri>,
393        Option<Authority<'uri>>,
394        Path<'uri>,
395        Option<Query<'uri>>,
396        Option<Fragment<'uri>>,
397    ) {
398        let (scheme, authority, path, query, fragment) = self.uri_reference.into_parts();
399        (scheme.unwrap(), authority, path, query, fragment)
400    }
401
402    /// Returns whether the URI is normalized.
403    ///
404    /// A normalized URI will have all of its components normalized.
405    ///
406    /// # Examples
407    ///
408    /// ```
409    /// use std::convert::TryFrom;
410    ///
411    /// use uriparse::URI;
412    ///
413    /// let uri = URI::try_from("http://example.com/?a=b").unwrap();
414    /// assert!(uri.is_normalized());
415    ///
416    /// let mut uri = URI::try_from("http://EXAMPLE.com/?a=b").unwrap();
417    /// assert!(!uri.is_normalized());
418    /// uri.normalize();
419    /// assert!(uri.is_normalized());
420    /// ```
421    pub fn is_normalized(&self) -> bool {
422        self.uri_reference.is_normalized()
423    }
424
425    /// Maps the authority using the given map function.
426    ///
427    /// This function will panic if, as a result of the authority change, the URI reference becomes
428    /// invalid.
429    ///
430    /// # Examples
431    ///
432    /// ```
433    /// use std::convert::TryFrom;
434    ///
435    /// use uriparse::{Authority, URI};
436    ///
437    /// let mut uri = URI::try_from("http://example.com").unwrap();
438    /// uri.map_authority(|_| Some(Authority::try_from("127.0.0.1").unwrap()));
439    /// assert_eq!(uri.to_string(), "http://127.0.0.1/");
440    /// ```
441    pub fn map_authority<TMapper>(&mut self, mapper: TMapper) -> Option<&Authority<'uri>>
442    where
443        TMapper: FnOnce(Option<Authority<'uri>>) -> Option<Authority<'uri>>,
444    {
445        self.uri_reference.map_authority(mapper)
446    }
447
448    /// Maps the fragment using the given map function.
449    ///
450    /// # Examples
451    ///
452    /// ```
453    /// use std::convert::TryFrom;
454    ///
455    /// use uriparse::{Fragment, URI};
456    ///
457    /// let mut uri = URI::try_from("http://example.com").unwrap();
458    /// uri.map_fragment(|_| Some(Fragment::try_from("fragment").unwrap()));
459    /// assert_eq!(uri.to_string(), "http://example.com/#fragment");
460    /// ```
461    pub fn map_fragment<TMapper>(&mut self, mapper: TMapper) -> Option<&Fragment<'uri>>
462    where
463        TMapper: FnOnce(Option<Fragment<'uri>>) -> Option<Fragment<'uri>>,
464    {
465        self.uri_reference.map_fragment(mapper)
466    }
467
468    /// Maps the path using the given map function.
469    ///
470    /// This function will panic if, as a result of the path change, the URI becomes invalid.
471    ///
472    /// # Examples
473    ///
474    /// ```
475    /// use std::convert::TryFrom;
476    ///
477    /// use uriparse::URI;
478    ///
479    /// let mut uri = URI::try_from("http://example.com").unwrap();
480    /// uri.map_path(|mut path| {
481    ///     path.push("test").unwrap();
482    ///     path.push("path").unwrap();
483    ///     path
484    /// });
485    /// assert_eq!(uri.to_string(), "http://example.com/test/path");
486    /// ```
487    pub fn map_path<TMapper>(&mut self, mapper: TMapper) -> &Path<'uri>
488    where
489        TMapper: FnOnce(Path<'uri>) -> Path<'uri>,
490    {
491        self.uri_reference.map_path(mapper)
492    }
493
494    /// Maps the query using the given map function.
495    ///
496    /// # Examples
497    ///
498    /// ```
499    /// use std::convert::TryFrom;
500    ///
501    /// use uriparse::{Query, URI};
502    ///
503    /// let mut uri = URI::try_from("http://example.com").unwrap();
504    /// uri.map_query(|_| Some(Query::try_from("query").unwrap()));
505    /// assert_eq!(uri.to_string(), "http://example.com/?query");
506    /// ```
507    pub fn map_query<TMapper>(&mut self, mapper: TMapper) -> Option<&Query<'uri>>
508    where
509        TMapper: FnOnce(Option<Query<'uri>>) -> Option<Query<'uri>>,
510    {
511        self.uri_reference.map_query(mapper)
512    }
513
514    /// Maps the scheme using the given map function.
515    ///
516    /// # Examples
517    ///
518    /// ```
519    /// use std::convert::TryFrom;
520    ///
521    /// use uriparse::{Scheme, URI};
522    ///
523    /// let mut uri = URI::try_from("http://example.com").unwrap();
524    /// uri.map_scheme(|_| Scheme::try_from("https").unwrap());
525    /// assert_eq!(uri.to_string(), "https://example.com/");
526    /// ```
527    pub fn map_scheme<TMapper>(&mut self, mapper: TMapper) -> Option<&Scheme<'uri>>
528    where
529        TMapper: FnOnce(Scheme<'uri>) -> Scheme<'uri>,
530    {
531        self.uri_reference
532            .map_scheme(|scheme| Some(mapper(scheme.unwrap())))
533    }
534
535    /// Normalizes the URI.
536    ///
537    /// A normalized URI will have all of its components normalized.
538    ///
539    /// # Examples
540    ///
541    /// ```
542    /// use std::convert::TryFrom;
543    ///
544    /// use uriparse::URI;
545    ///
546    /// let mut uri = URI::try_from("http://example.com/?a=b").unwrap();
547    /// uri.normalize();
548    /// assert_eq!(uri.to_string(), "http://example.com/?a=b");
549    ///
550    /// let mut uri = URI::try_from("http://EXAMPLE.com/?a=b").unwrap();
551    /// assert_eq!(uri.to_string(), "http://EXAMPLE.com/?a=b");
552    /// uri.normalize();
553    /// assert_eq!(uri.to_string(), "http://example.com/?a=b");
554    /// ```
555    pub fn normalize(&mut self) {
556        self.uri_reference.normalize();
557    }
558
559    /// Returns the path of the URI.
560    ///
561    /// # Examples
562    ///
563    /// ```
564    /// use std::convert::TryFrom;
565    ///
566    /// use uriparse::URI;
567    ///
568    /// let uri = URI::try_from("http://127.0.0.1/my/path").unwrap();
569    /// assert_eq!(uri.path(), "/my/path");
570    /// ```
571    pub fn path(&self) -> &Path<'uri> {
572        self.uri_reference.path()
573    }
574
575    /// Returns the password, if present, of the URI.
576    ///
577    /// Usage of a password in URIs is deprecated.
578    ///
579    /// # Examples
580    ///
581    /// ```
582    /// use std::convert::TryFrom;
583    ///
584    /// use uriparse::URI;
585    ///
586    /// let uri = URI::try_from("http://user:pass@example.com").unwrap();
587    /// assert_eq!(uri.password().unwrap(), "pass");
588    /// ```
589    pub fn password(&self) -> Option<&Password<'uri>> {
590        self.uri_reference.password()
591    }
592
593    /// Returns the port, if present, of the URI.
594    ///
595    /// # Examples
596    ///
597    /// ```
598    /// use std::convert::TryFrom;
599    ///
600    /// use uriparse::URI;
601    ///
602    /// let uri = URI::try_from("http://example.com:8080/").unwrap();
603    /// assert_eq!(uri.port().unwrap(), 8080);
604    /// ```
605    pub fn port(&self) -> Option<u16> {
606        self.uri_reference.port()
607    }
608
609    /// Returns the query, if present, of the URI.
610    ///
611    /// # Examples
612    ///
613    /// ```
614    /// use std::convert::TryFrom;
615    ///
616    /// use uriparse::URI;
617    ///
618    /// let uri = URI::try_from("http://127.0.0.1?my=query").unwrap();
619    /// assert_eq!(uri.query().unwrap(), "my=query");
620    /// ```
621    pub fn query(&self) -> Option<&Query<'uri>> {
622        self.uri_reference.query()
623    }
624
625    /// Creates a new URI which is created by resolving the given reference against this URI.
626    ///
627    /// The algorithm used for resolving the reference is described in
628    /// [[RFC3986, Section 5.2.2](https://tools.ietf.org/html/rfc3986#section-5.2.2)].
629    pub fn resolve(&self, reference: &'uri URIReference<'uri>) -> URI<'uri> {
630        let mut builder = URIBuilder::new();
631
632        if let Some(scheme) = reference.scheme() {
633            let mut path = reference.path().clone();
634            path.remove_dot_segments();
635
636            builder
637                .scheme(scheme.clone())
638                .authority(reference.authority().cloned())
639                .path(path)
640                .query(reference.query().cloned());
641        } else {
642            if reference.authority().is_some() {
643                let mut path = reference.path().clone();
644                path.remove_dot_segments();
645
646                builder
647                    .authority(reference.authority().cloned())
648                    .path(path)
649                    .query(reference.query().cloned());
650            } else {
651                if reference.path().is_relative()
652                    && reference.path().segments().len() == 1
653                    && reference.path().segments()[0].is_empty()
654                {
655                    let mut path = self.path().clone();
656                    path.remove_dot_segments();
657                    builder.path(path);
658
659                    if reference.query().is_some() {
660                        builder.query(reference.query().cloned());
661                    } else {
662                        builder.query(self.query().cloned());
663                    }
664                } else {
665                    if reference.path().is_absolute() {
666                        let mut path = reference.path().clone();
667                        path.remove_dot_segments();
668                        builder.path(path);
669                    } else {
670                        let mut path = if self.authority().is_some()
671                            && self.path().segments().len() == 1
672                            && self.path().segments()[0].is_empty()
673                        {
674                            let mut path = reference.path().clone();
675                            path.set_absolute(true);
676                            path
677                        } else {
678                            let mut path = self.path().clone();
679                            path.pop();
680
681                            for segment in reference.path().segments() {
682                                path.push(segment.clone()).unwrap();
683                            }
684
685                            path
686                        };
687
688                        path.remove_dot_segments();
689                        builder.path(path);
690                    }
691
692                    builder.query(reference.query().cloned());
693                }
694
695                builder.authority(self.authority().cloned());
696            }
697
698            builder.scheme(self.scheme().clone());
699        }
700
701        builder.fragment(reference.fragment().cloned());
702        builder.build().unwrap()
703    }
704
705    /// Returns the scheme of the URI.
706    ///
707    /// # Examples
708    ///
709    /// ```
710    /// use std::convert::TryFrom;
711    ///
712    /// use uriparse::URI;
713    ///
714    /// let uri = URI::try_from("http://127.0.0.1/").unwrap();
715    /// assert_eq!(uri.scheme(), "http");
716    /// ```
717    pub fn scheme(&self) -> &Scheme<'uri> {
718        self.uri_reference.scheme().unwrap()
719    }
720
721    /// Sets the authority of the URI.
722    ///
723    /// An error will be returned if the conversion to an [`Authority`] fails.
724    ///
725    /// The existing path will be set to absolute (i.e. starts with a `'/'`).
726    ///
727    /// # Examples
728    ///
729    /// ```
730    /// use std::convert::TryFrom;
731    ///
732    /// use uriparse::URI;
733    ///
734    /// let mut uri = URI::try_from("http://example.com").unwrap();
735    /// uri.set_authority(Some("user@example.com:80"));
736    /// assert_eq!(uri.to_string(), "http://user@example.com:80/");
737    /// ```
738    pub fn set_authority<TAuthority, TAuthorityError>(
739        &mut self,
740        authority: Option<TAuthority>,
741    ) -> Result<Option<&Authority<'uri>>, URIError>
742    where
743        Authority<'uri>: TryFrom<TAuthority, Error = TAuthorityError>,
744        URIReferenceError: From<TAuthorityError>,
745    {
746        self.uri_reference
747            .set_authority(authority)
748            .map_err(|error| URIError::try_from(error).unwrap())
749    }
750
751    /// Sets the fragment of the URI.
752    ///
753    /// An error will be returned if the conversion to a [`Fragment`] fails.
754    ///
755    /// # Examples
756    ///
757    /// ```
758    /// use std::convert::TryFrom;
759    ///
760    /// use uriparse::URI;
761    ///
762    /// let mut uri = URI::try_from("http://example.com").unwrap();
763    /// uri.set_fragment(Some("fragment"));
764    /// assert_eq!(uri.to_string(), "http://example.com/#fragment");
765    /// ```
766    pub fn set_fragment<TFragment, TFragmentError>(
767        &mut self,
768        fragment: Option<TFragment>,
769    ) -> Result<Option<&Fragment<'uri>>, URIError>
770    where
771        Fragment<'uri>: TryFrom<TFragment, Error = TFragmentError>,
772        URIReferenceError: From<TFragmentError>,
773    {
774        self.uri_reference
775            .set_fragment(fragment)
776            .map_err(|error| URIError::try_from(error).unwrap())
777    }
778
779    /// Sets the path of the URI.
780    ///
781    /// An error will be returned in one of two cases:
782    ///  - The conversion to [`Path`] failed.
783    ///  - The path was set to a value that resulted in an invalid URI.
784    ///
785    /// Regardless of whether the given path was set as absolute or relative, if the URI
786    /// reference currently has an authority, the path will be forced to be absolute.
787    ///
788    /// # Examples
789    ///
790    /// ```
791    /// use std::convert::TryFrom;
792    ///
793    /// use uriparse::URI;
794    ///
795    /// let mut uri = URI::try_from("http://example.com").unwrap();
796    /// uri.set_path("my/path");
797    /// assert_eq!(uri.to_string(), "http://example.com/my/path");
798    /// ```
799    pub fn set_path<TPath, TPathError>(&mut self, path: TPath) -> Result<&Path<'uri>, URIError>
800    where
801        Path<'uri>: TryFrom<TPath, Error = TPathError>,
802        URIReferenceError: From<TPathError>,
803    {
804        self.uri_reference
805            .set_path(path)
806            .map_err(|error| URIError::try_from(error).unwrap())
807    }
808
809    /// Sets the query of the URI.
810    ///
811    /// An error will be returned if the conversion to a [`Query`] fails.
812    ///
813    /// # Examples
814    ///
815    /// ```
816    /// use std::convert::TryFrom;
817    ///
818    /// use uriparse::URI;
819    ///
820    /// let mut uri = URI::try_from("http://example.com").unwrap();
821    /// uri.set_query(Some("myquery"));
822    /// assert_eq!(uri.to_string(), "http://example.com/?myquery");
823    /// ```
824    pub fn set_query<TQuery, TQueryError>(
825        &mut self,
826        query: Option<TQuery>,
827    ) -> Result<Option<&Query<'uri>>, URIError>
828    where
829        Query<'uri>: TryFrom<TQuery, Error = TQueryError>,
830        URIReferenceError: From<TQueryError>,
831    {
832        self.uri_reference
833            .set_query(query)
834            .map_err(|error| URIError::try_from(error).unwrap())
835    }
836
837    /// Sets the scheme of the URI.
838    ///
839    /// An error will be returned if the conversion to a [`Scheme`] fails.
840    ///
841    /// # Examples
842    ///
843    /// ```
844    /// use std::convert::TryFrom;
845    ///
846    /// use uriparse::URI;
847    ///
848    /// let mut uri = URI::try_from("http://example.com").unwrap();
849    /// uri.set_scheme("https");
850    /// assert_eq!(uri.to_string(), "https://example.com/");
851    /// ```
852    pub fn set_scheme<TScheme, TSchemeError>(
853        &mut self,
854        scheme: TScheme,
855    ) -> Result<&Scheme<'uri>, URIError>
856    where
857        Scheme<'uri>: TryFrom<TScheme, Error = TSchemeError>,
858        URIReferenceError: From<TSchemeError>,
859    {
860        self.uri_reference
861            .set_scheme(Some(scheme))
862            .map_err(|error| URIError::try_from(error).unwrap())?;
863        Ok(self.scheme())
864    }
865
866    /// Returns a new URI which is identical but has a lifetime tied to this URI.
867    ///
868    /// This function will perform a memory allocation.
869    pub fn to_borrowed(&self) -> URI {
870        URI {
871            uri_reference: self.uri_reference.to_borrowed(),
872        }
873    }
874
875    /// Returns the username, if present, of the URI.
876    ///
877    /// # Examples
878    ///
879    /// ```
880    /// use std::convert::TryFrom;
881    ///
882    /// use uriparse::URI;
883    ///
884    /// let uri = URI::try_from("http://username@example.com").unwrap();
885    /// assert_eq!(uri.username().unwrap(), "username");
886    /// ```
887    pub fn username(&self) -> Option<&Username<'uri>> {
888        self.uri_reference.username()
889    }
890}
891
892impl Display for URI<'_> {
893    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
894        self.uri_reference.fmt(formatter)
895    }
896}
897
898impl<'uri> From<URI<'uri>> for String {
899    fn from(value: URI<'uri>) -> Self {
900        value.to_string()
901    }
902}
903
904impl<'uri> From<URI<'uri>> for URIReference<'uri> {
905    fn from(value: URI<'uri>) -> Self {
906        value.uri_reference
907    }
908}
909
910impl<'uri> TryFrom<&'uri [u8]> for URI<'uri> {
911    type Error = URIError;
912
913    fn try_from(value: &'uri [u8]) -> Result<Self, Self::Error> {
914        let uri_reference =
915            URIReference::try_from(value).map_err(|error| URIError::try_from(error).unwrap())?;
916
917        if uri_reference.is_relative_reference() {
918            Err(URIError::NotURI)
919        } else {
920            Ok(URI { uri_reference })
921        }
922    }
923}
924
925impl<'uri> TryFrom<&'uri str> for URI<'uri> {
926    type Error = URIError;
927
928    fn try_from(value: &'uri str) -> Result<Self, Self::Error> {
929        URI::try_from(value.as_bytes())
930    }
931}
932
933impl<'uri> TryFrom<URIReference<'uri>> for URI<'uri> {
934    type Error = URIError;
935
936    fn try_from(value: URIReference<'uri>) -> Result<Self, Self::Error> {
937        if value.is_uri() {
938            Ok(URI {
939                uri_reference: value,
940            })
941        } else {
942            Err(URIError::NotURI)
943        }
944    }
945}
946
947/// A builder type for [`URI]`.
948///
949/// You must use the [`URI::scheme`] and [`URI::path`] functions before building as URIs always
950/// have a scheme and path. Everything else is optional.
951#[derive(Clone, Debug, Default, Eq, PartialEq)]
952pub struct URIBuilder<'uri> {
953    /// All URIs are also URI references, so we just maintain a [`URIReferenceBuilder`] underneath.
954    uri_reference_builder: URIReferenceBuilder<'uri>,
955}
956
957impl<'uri> URIBuilder<'uri> {
958    /// Sets the authority part of the URI.
959    ///
960    /// It is optional to specify a authority.
961    ///
962    /// # Examples
963    ///
964    /// ```
965    /// use std::convert::TryFrom;
966    ///
967    /// use uriparse::{Authority, Path, Scheme, URIBuilder};
968    ///
969    /// let mut builder = URIBuilder::new();
970    /// builder
971    ///     .scheme(Scheme::HTTP)
972    ///     .authority(Some(Authority::try_from("example.com").unwrap()))
973    ///     .path(Path::try_from("/my/path").unwrap());
974    /// let reference = builder.build().unwrap();
975    /// assert_eq!(reference.to_string(), "http://example.com/my/path");
976    /// ```
977    pub fn authority(&mut self, authority: Option<Authority<'uri>>) -> &mut Self {
978        self.uri_reference_builder.authority(authority);
979        self
980    }
981
982    /// Consumes the builder and tries to build a [`URI`].
983    ///
984    /// This function will error in one of three situations:
985    ///  - A scheme and path were not specified in the builder.
986    ///  - While all individual components were valid, their combination as a URI was invalid.
987    ///
988    /// # Examples
989    ///
990    /// First error type (scheme and/or path were not specified):
991    ///
992    /// ```
993    /// use std::convert::TryFrom;
994    ///
995    /// use uriparse::{Authority, Path, URIBuilder};
996    ///
997    /// let result = URIBuilder::new()
998    ///     .with_authority(Some(Authority::try_from("example.com").unwrap()))
999    ///     .with_path(Path::try_from("/my/path").unwrap())
1000    ///     .build();
1001    /// assert!(result.is_err());
1002    /// ```
1003    ///
1004    /// Second error type (URI with no authority cannot have path starting with `"//"`):
1005    ///
1006    /// ```
1007    /// use std::convert::TryFrom;
1008    ///
1009    /// use uriparse::{Scheme, Path, URIBuilder};
1010    ///
1011    /// let result = URIBuilder::new()
1012    ///     .with_scheme(Scheme::URN)
1013    ///     .with_path(Path::try_from("//path").unwrap())
1014    ///     .build();
1015    /// assert!(result.is_err());
1016    /// ```
1017    pub fn build(self) -> Result<URI<'uri>, URIError> {
1018        let uri_reference = self
1019            .uri_reference_builder
1020            .build()
1021            .map_err(|error| URIError::try_from(error).unwrap())?;
1022
1023        if !uri_reference.has_scheme() {
1024            return Err(URIError::MissingScheme);
1025        }
1026
1027        Ok(URI { uri_reference })
1028    }
1029
1030    /// Sets the fragment part of the URI.
1031    ///
1032    /// It is optional to specify a fragment.
1033    ///
1034    /// # Examples
1035    ///
1036    /// ```
1037    /// use std::convert::TryFrom;
1038    ///
1039    /// use uriparse::{Fragment, Path, Scheme, URIBuilder};
1040    ///
1041    /// let mut builder = URIBuilder::new();
1042    /// builder
1043    ///     .scheme(Scheme::URN)
1044    ///     .path(Path::try_from("path").unwrap())
1045    ///     .fragment(Some(Fragment::try_from("fragment").unwrap()));
1046    /// let uri = builder.build().unwrap();
1047    /// assert_eq!(uri.to_string(), "urn:path#fragment");
1048    /// ```
1049    pub fn fragment(&mut self, fragment: Option<Fragment<'uri>>) -> &mut Self {
1050        self.uri_reference_builder.fragment(fragment);
1051        self
1052    }
1053
1054    /// Constructs a new builder with nothing set.
1055    pub fn new() -> Self {
1056        URIBuilder::default()
1057    }
1058
1059    /// Sets the path part of the URI.
1060    ///
1061    /// It is required to specify a path. Not doing so will result in an error during the
1062    /// [`URIBuilder::build`] function.
1063    ///
1064    /// # Examples
1065    ///
1066    /// ```
1067    /// use std::convert::TryFrom;
1068    ///
1069    /// use uriparse::{Path, Scheme, URIBuilder};
1070    ///
1071    /// let mut builder = URIBuilder::new();
1072    /// builder
1073    ///     .scheme(Scheme::URN)
1074    ///     .path(Path::try_from("path").unwrap());
1075    /// let uri = builder.build().unwrap();
1076    /// assert_eq!(uri.to_string(), "urn:path");
1077    /// ```
1078    pub fn path(&mut self, path: Path<'uri>) -> &mut Self {
1079        self.uri_reference_builder.path(path);
1080        self
1081    }
1082
1083    /// Sets the query part of the URI reference.
1084    ///
1085    /// It is optional to specify a query.
1086    ///
1087    /// # Examples
1088    ///
1089    /// ```
1090    /// use std::convert::TryFrom;
1091    ///
1092    /// use uriparse::{Path, Query, Scheme, URIBuilder};
1093    ///
1094    /// let mut builder = URIBuilder::new();
1095    /// builder
1096    ///     .scheme(Scheme::URN)
1097    ///     .path(Path::try_from("path").unwrap())
1098    ///     .query(Some(Query::try_from("query").unwrap()));
1099    /// let uri = builder.build().unwrap();
1100    /// assert_eq!(uri.to_string(), "urn:path?query");
1101    /// ```
1102    pub fn query(&mut self, query: Option<Query<'uri>>) -> &mut Self {
1103        self.uri_reference_builder.query(query);
1104        self
1105    }
1106
1107    /// Sets the scheme part of the URI reference.
1108    ///
1109    /// It is required to specify a scheme. Not doing so will result in an error during the
1110    /// [`URIBuilder::build`] function.
1111    ///
1112    /// # Examples
1113    ///
1114    /// ```
1115    /// use std::convert::TryFrom;
1116    ///
1117    /// use uriparse::{Authority, Path, Scheme, URIBuilder};
1118    ///
1119    /// let mut builder = URIBuilder::new();
1120    /// builder
1121    ///     .scheme(Scheme::HTTP)
1122    ///     .authority(Some(Authority::try_from("example.com").unwrap()))
1123    ///     .path(Path::try_from("/my/path").unwrap());
1124    /// let uri = builder.build().unwrap();
1125    /// assert_eq!(uri.to_string(), "http://example.com/my/path");
1126    /// ```
1127    pub fn scheme(&mut self, scheme: Scheme<'uri>) -> &mut Self {
1128        self.uri_reference_builder.scheme(Some(scheme));
1129        self
1130    }
1131
1132    /// Sets the authority part of the URI.1
1133    ///
1134    /// If the given authority is not a valid authority (i.e. the conversion fails), an error is
1135    /// stored internally and checked during the [`URIBuilder::build`] function. The error state
1136    /// will be rewritten for any following calls to this function.
1137    ///
1138    /// It is optional to specify an authority.
1139    ///
1140    /// # Examples
1141    ///
1142    /// ```
1143    /// use uriparse::URIBuilder;
1144    ///
1145    /// let mut builder = URIBuilder::new();
1146    /// builder
1147    ///     .try_scheme("http")
1148    ///     .unwrap()
1149    ///     .try_authority(Some("example.com"))
1150    ///     .unwrap()
1151    ///     .try_path("/my/path")
1152    ///     .unwrap();
1153    /// let uri = builder.build().unwrap();
1154    /// assert_eq!(uri.to_string(), "http://example.com/my/path");
1155    /// ```
1156    pub fn try_authority<TAuthority, TAuthorityError>(
1157        &mut self,
1158        authority: Option<TAuthority>,
1159    ) -> Result<&mut Self, AuthorityError>
1160    where
1161        Authority<'uri>: TryFrom<TAuthority, Error = TAuthorityError>,
1162        AuthorityError: From<TAuthorityError>,
1163    {
1164        self.uri_reference_builder.try_authority(authority)?;
1165        Ok(self)
1166    }
1167
1168    /// Sets the fragment part of the URI.
1169    ///
1170    /// If the given fragment is not a valid fragment (i.e. the conversion fails), an error is
1171    /// stored internally and checked during the [`URIBuilder::build`] function. The error state
1172    /// will be rewritten for any following calls to this function.
1173    ///
1174    /// It is optional to specify a fragment.
1175    ///
1176    /// # Examples
1177    ///
1178    /// ```
1179    /// use uriparse::URIBuilder;
1180    ///
1181    /// let mut builder = URIBuilder::new();
1182    /// builder
1183    ///     .try_scheme("urn")
1184    ///     .unwrap()
1185    ///     .try_path("path")
1186    ///     .unwrap()
1187    ///     .try_fragment(Some("fragment"))
1188    ///     .unwrap();
1189    /// let uri = builder.build().unwrap();
1190    /// assert_eq!(uri.to_string(), "urn:path#fragment");
1191    /// ```
1192    pub fn try_fragment<TFragment, TFragmentError>(
1193        &mut self,
1194        fragment: Option<TFragment>,
1195    ) -> Result<&mut Self, FragmentError>
1196    where
1197        Fragment<'uri>: TryFrom<TFragment, Error = TFragmentError>,
1198        FragmentError: From<TFragmentError>,
1199    {
1200        self.uri_reference_builder.try_fragment(fragment)?;
1201        Ok(self)
1202    }
1203
1204    /// Sets the path part of the URI.
1205    ///
1206    /// If the given path is not a valid path (i.e. the conversion fails), an error is stored
1207    /// internally and checked during the [`URIBuilder::build`] function. The error state will be
1208    /// rewritten for any following calls to this function.
1209    ///
1210    /// It is required to specify a path.
1211    ///
1212    /// # Examples
1213    ///
1214    /// ```
1215    /// use uriparse::URIBuilder;
1216    ///
1217    /// let mut builder = URIBuilder::new();
1218    /// builder
1219    ///     .try_scheme("urn")
1220    ///     .unwrap()
1221    ///     .try_path("path")
1222    ///     .unwrap();
1223    /// let uri = builder.build().unwrap();
1224    /// assert_eq!(uri.to_string(), "urn:path");
1225    /// ```
1226    pub fn try_path<TPath, TPathError>(&mut self, path: TPath) -> Result<&mut Self, PathError>
1227    where
1228        Path<'uri>: TryFrom<TPath, Error = TPathError>,
1229        PathError: From<TPathError>,
1230    {
1231        self.uri_reference_builder.try_path(path)?;
1232        Ok(self)
1233    }
1234
1235    /// Sets the query part of the URI.
1236    ///
1237    /// If the given query is not a valid query (i.e. the conversion fails), an error is stored
1238    /// internally and checked during the [`URIBuilder::build`] function. The error state will be
1239    /// rewritten for any following calls to this function.
1240    ///
1241    /// It is optional to specify a query.
1242    ///
1243    /// # Examples
1244    ///
1245    /// ```
1246    /// use uriparse::URIBuilder;
1247    ///
1248    /// let mut builder = URIBuilder::new();
1249    /// builder
1250    ///     .try_scheme("urn")
1251    ///     .unwrap()
1252    ///     .try_path("path")
1253    ///     .unwrap()
1254    ///     .try_query(Some("query"))
1255    ///     .unwrap();
1256    /// let uri = builder.build().unwrap();
1257    /// assert_eq!(uri.to_string(), "urn:path?query");
1258    /// ```
1259    pub fn try_query<TQuery, TQueryError>(
1260        &mut self,
1261        query: Option<TQuery>,
1262    ) -> Result<&mut Self, QueryError>
1263    where
1264        Query<'uri>: TryFrom<TQuery, Error = TQueryError>,
1265        QueryError: From<TQueryError>,
1266    {
1267        self.uri_reference_builder.try_query(query)?;
1268        Ok(self)
1269    }
1270
1271    /// Sets the scheme part of the URI.
1272    ///
1273    /// If the given scheme is not a valid scheme (i.e. the conversion fails), an error is stored
1274    /// internally and checked during the [`URIBuilder::build`] function. The error state will be
1275    /// rewritten for any following calls to this function.
1276    ///
1277    /// It is required to specify a scheme. Not doing so will result in an error during the
1278    /// [`URIBuilder::build`] function.
1279    ///
1280    /// # Examples
1281    ///
1282    /// ```
1283    /// use std::convert::TryFrom;
1284    ///
1285    /// use uriparse::{Path, Scheme, URIBuilder};
1286    ///
1287    /// let mut builder = URIBuilder::new();
1288    /// builder
1289    ///     .try_scheme("urn")
1290    ///     .unwrap()
1291    ///     .try_path("path")
1292    ///     .unwrap();
1293    /// let uri = builder.build().unwrap();
1294    /// assert_eq!(uri.to_string(), "urn:path");
1295    /// ```
1296    pub fn try_scheme<TScheme, TSchemeError>(
1297        &mut self,
1298        scheme: TScheme,
1299    ) -> Result<&mut Self, SchemeError>
1300    where
1301        Scheme<'uri>: TryFrom<TScheme, Error = TSchemeError>,
1302        SchemeError: From<TSchemeError>,
1303    {
1304        self.uri_reference_builder.try_scheme(Some(scheme))?;
1305        Ok(self)
1306    }
1307
1308    /// Consumes the builder and sets the authority part of the URI.
1309    ///
1310    /// It is optional to specify an authority.
1311    ///
1312    /// # Examples
1313    ///
1314    /// ```
1315    /// use std::convert::TryFrom;
1316    ///
1317    /// use uriparse::{Authority, Path, Scheme, URIBuilder};
1318    ///
1319    /// let uri = URIBuilder::new()
1320    ///     .with_scheme(Scheme::HTTP)
1321    ///     .with_authority(Some(Authority::try_from("example.com").unwrap()))
1322    ///     .with_path(Path::try_from("/").unwrap())
1323    ///     .build()
1324    ///     .unwrap();
1325    /// assert_eq!(uri.to_string(), "http://example.com/")
1326    /// ```
1327    pub fn with_authority(mut self, authority: Option<Authority<'uri>>) -> Self {
1328        self.authority(authority);
1329        self
1330    }
1331
1332    /// Consumes the builder and sets the fragment part of the URI.
1333    ///
1334    /// It is optional to specify a fragment.
1335    ///
1336    /// # Examples
1337    ///
1338    /// ```
1339    /// use std::convert::TryFrom;
1340    ///
1341    /// use uriparse::{Fragment, Path, Scheme, URIBuilder};
1342    ///
1343    /// let uri = URIBuilder::new()
1344    ///     .with_scheme(Scheme::URN)
1345    ///     .with_path(Path::try_from("").unwrap())
1346    ///     .with_fragment(Some(Fragment::try_from("fragment").unwrap()))
1347    ///     .build()
1348    ///     .unwrap();
1349    /// assert_eq!(uri.to_string(), "urn:#fragment")
1350    /// ```
1351    pub fn with_fragment(mut self, fragment: Option<Fragment<'uri>>) -> Self {
1352        self.fragment(fragment);
1353        self
1354    }
1355
1356    /// Consumes the builder and sets the path part of the URI.
1357    ///
1358    /// It is required to specify a path. Not doing so will result in an error during the
1359    /// [`URIBuilder::build`] function.
1360    ///
1361    /// # Examples
1362    ///
1363    /// ```
1364    /// use std::convert::TryFrom;
1365    ///
1366    /// use uriparse::{Authority, Path, Scheme, URIBuilder};
1367    ///
1368    /// let reference = URIBuilder::new()
1369    ///     .with_scheme(Scheme::HTTP)
1370    ///     .with_authority(Some(Authority::try_from("example.com").unwrap()))
1371    ///     .with_path(Path::try_from("/").unwrap())
1372    ///     .build()
1373    ///     .unwrap();
1374    /// assert_eq!(reference.to_string(), "http://example.com/")
1375    /// ```
1376    pub fn with_path(mut self, path: Path<'uri>) -> Self {
1377        self.path(path);
1378        self
1379    }
1380
1381    /// Consumes the builder and sets the query part of the URI.
1382    ///
1383    /// It is optional to specify a query.
1384    ///
1385    /// # Examples
1386    ///
1387    /// ```
1388    /// use std::convert::TryFrom;
1389    ///
1390    /// use uriparse::{Path, Query, Scheme, URIBuilder};
1391    ///
1392    /// let uri = URIBuilder::new()
1393    ///     .with_scheme(Scheme::URN)
1394    ///     .with_path(Path::try_from("").unwrap())
1395    ///     .with_query(Some(Query::try_from("query").unwrap()))
1396    ///     .build()
1397    ///     .unwrap();
1398    /// assert_eq!(uri.to_string(), "urn:?query")
1399    /// ```
1400    pub fn with_query(mut self, query: Option<Query<'uri>>) -> Self {
1401        self.query(query);
1402        self
1403    }
1404
1405    /// Consumes the builder and sets the scheme part of the URI.
1406    ///
1407    /// It is required to specify a scheme. Not doing so will result in an error during the
1408    /// [`URIBuilder::build`] function.
1409    ///
1410    /// # Examples
1411    ///
1412    /// ```
1413    /// use std::convert::TryFrom;
1414    ///
1415    /// use uriparse::{Authority, Path, Scheme, URIBuilder};
1416    ///
1417    /// let reference = URIBuilder::new()
1418    ///     .with_scheme(Scheme::HTTP)
1419    ///     .with_authority(Some(Authority::try_from("example.com").unwrap()))
1420    ///     .with_path(Path::try_from("/").unwrap())
1421    ///     .build()
1422    ///     .unwrap();
1423    /// assert_eq!(reference.to_string(), "http://example.com/")
1424    /// ```
1425    pub fn with_scheme(mut self, scheme: Scheme<'uri>) -> Self {
1426        self.scheme(scheme);
1427        self
1428    }
1429}
1430
1431/// An error representing an invalid URI.
1432#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1433#[non_exhaustive]
1434pub enum URIError {
1435    /// Represents the case when there is no authority, but the first path segment starts with
1436    /// `"//"`. This is not allowed because it would be interpreted as an authority component.
1437    ///
1438    /// This can only occur when using creation functions that act on individual parts (e.g.
1439    /// [`URI::from_parts`]).
1440    AbsolutePathStartsWithTwoSlashes,
1441
1442    /// The authority component of the relative reference was invalid.
1443    Authority(AuthorityError),
1444
1445    /// The fragment component of the relative reference was invalid.
1446    Fragment(FragmentError),
1447
1448    /// This error occurs when you do not specify a path component on the builder.
1449    ///
1450    /// This can only occur when using [`URIBuilder`].
1451    MissingPath,
1452
1453    /// This error occurs when you do not specify a scheme component on the builder.
1454    ///
1455    /// This can only occur when using [`URIBuilder`].
1456    MissingScheme,
1457
1458    /// When parsing from some byte string source, if the source ends up being a relative reference,
1459    /// then it is obviously not a URI.
1460    ///
1461    /// This can only occur when parsing from a byte string source.
1462    NotURI,
1463
1464    /// The path component of the relative reference was invalid.
1465    Path(PathError),
1466
1467    /// The query component of the relative reference was invalid.
1468    Query(QueryError),
1469
1470    /// The scheme component of the relative reference was invalid.
1471    Scheme(SchemeError),
1472}
1473
1474impl Display for URIError {
1475    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1476        use self::URIError::*;
1477
1478        match self {
1479            AbsolutePathStartsWithTwoSlashes => {
1480                write!(formatter, "absolute path URI starts with two slashes")
1481            }
1482            Authority(error) => error.fmt(formatter),
1483            Fragment(error) => error.fmt(formatter),
1484            MissingPath => write!(formatter, "missing path"),
1485            MissingScheme => write!(formatter, "missing scheme"),
1486            NotURI => write!(formatter, "not URI"),
1487            Path(error) => error.fmt(formatter),
1488            Query(error) => error.fmt(formatter),
1489            Scheme(error) => error.fmt(formatter),
1490        }
1491    }
1492}
1493
1494impl Error for URIError {}
1495
1496impl From<Infallible> for URIError {
1497    fn from(_: Infallible) -> Self {
1498        URIError::AbsolutePathStartsWithTwoSlashes
1499    }
1500}
1501
1502impl From<AuthorityError> for URIError {
1503    fn from(value: AuthorityError) -> Self {
1504        URIError::Authority(value)
1505    }
1506}
1507
1508impl From<FragmentError> for URIError {
1509    fn from(value: FragmentError) -> Self {
1510        URIError::Fragment(value)
1511    }
1512}
1513
1514impl From<PathError> for URIError {
1515    fn from(value: PathError) -> Self {
1516        URIError::Path(value)
1517    }
1518}
1519
1520impl From<QueryError> for URIError {
1521    fn from(value: QueryError) -> Self {
1522        URIError::Query(value)
1523    }
1524}
1525
1526impl From<SchemeError> for URIError {
1527    fn from(value: SchemeError) -> Self {
1528        URIError::Scheme(value)
1529    }
1530}
1531
1532impl TryFrom<URIReferenceError> for URIError {
1533    type Error = ();
1534
1535    fn try_from(value: URIReferenceError) -> Result<Self, Self::Error> {
1536        use self::URIError::*;
1537
1538        match value {
1539            URIReferenceError::AbsolutePathStartsWithTwoSlashes => {
1540                Ok(AbsolutePathStartsWithTwoSlashes)
1541            }
1542            URIReferenceError::Authority(error) => Ok(Authority(error)),
1543            URIReferenceError::Fragment(error) => Ok(Fragment(error)),
1544            URIReferenceError::MissingPath => Ok(MissingPath),
1545            URIReferenceError::Path(error) => Ok(Path(error)),
1546            URIReferenceError::Query(error) => Ok(Query(error)),
1547            URIReferenceError::Scheme(error) => Ok(Scheme(error)),
1548            URIReferenceError::SchemelessPathStartsWithColonSegment => Err(()),
1549        }
1550    }
1551}
1552
1553#[cfg(test)]
1554mod test {
1555    use super::*;
1556
1557    #[test]
1558    fn test_resolve() {
1559        fn test_case(value: &str, expected: &str) {
1560            let base_uri = URI::try_from("http://a/b/c/d;p?q").unwrap();
1561            let reference = URIReference::try_from(value).unwrap();
1562            assert_eq!(base_uri.resolve(&reference).to_string(), expected);
1563        }
1564
1565        test_case("g:h", "g:h");
1566        test_case("g", "http://a/b/c/g");
1567        test_case("./g", "http://a/b/c/g");
1568        test_case("g/", "http://a/b/c/g/");
1569        test_case("/g", "http://a/g");
1570        test_case("//g", "http://g/");
1571        test_case("?y", "http://a/b/c/d;p?y");
1572        test_case("g?y", "http://a/b/c/g?y");
1573        test_case("#s", "http://a/b/c/d;p?q#s");
1574        test_case("g#s", "http://a/b/c/g#s");
1575        test_case("g?y#s", "http://a/b/c/g?y#s");
1576        test_case(";x", "http://a/b/c/;x");
1577        test_case("g;x", "http://a/b/c/g;x");
1578        test_case("g;x?y#s", "http://a/b/c/g;x?y#s");
1579        test_case("", "http://a/b/c/d;p?q");
1580        test_case(".", "http://a/b/c/");
1581        test_case("./", "http://a/b/c/");
1582        test_case("..", "http://a/b/");
1583        test_case("../", "http://a/b/");
1584        test_case("../g", "http://a/b/g");
1585        test_case("../..", "http://a/");
1586        test_case("../../", "http://a/");
1587        test_case("../../g", "http://a/g");
1588        test_case("../../../g", "http://a/g");
1589        test_case("../../../g", "http://a/g");
1590        test_case("/./g", "http://a/g");
1591        test_case("/../g", "http://a/g");
1592        test_case("g.", "http://a/b/c/g.");
1593        test_case(".g", "http://a/b/c/.g");
1594        test_case("g..", "http://a/b/c/g..");
1595        test_case("..g", "http://a/b/c/..g");
1596        test_case("./../g", "http://a/b/g");
1597        test_case("./g/.", "http://a/b/c/g/");
1598        test_case("g/./h", "http://a/b/c/g/h");
1599        test_case("g/../h", "http://a/b/c/h");
1600        test_case("g;x=1/./y", "http://a/b/c/g;x=1/y");
1601        test_case("g;x=1/../y", "http://a/b/c/y");
1602        test_case("g?y/./x", "http://a/b/c/g?y/./x");
1603        test_case("g?y/../x", "http://a/b/c/g?y/../x");
1604        test_case("g#s/./x", "http://a/b/c/g#s/./x");
1605        test_case("g#s/../x", "http://a/b/c/g#s/../x");
1606        test_case("http:g", "http:g");
1607    }
1608
1609    #[cfg(feature = "serde")]
1610    #[test]
1611    fn test_serde() {
1612        let uri = URI::try_from("http://a/b/c/d;p?q").unwrap();
1613
1614        // Perform serialization
1615        let json_string = serde_json::to_string(&uri).unwrap();
1616
1617        // Perform deserialization
1618        let uri2 = serde_json::from_str(&json_string).unwrap();
1619
1620        assert_eq!(
1621            uri, uri2,
1622            "Information lost in serialization/deserialization"
1623        );
1624    }
1625}