uriparse/
uri_reference.rs

1use std::convert::{Infallible, TryFrom};
2use std::error::Error;
3use std::fmt::{self, Display, Formatter, Write};
4use std::mem;
5
6use crate::authority::{parse_authority, Authority, AuthorityError, Host, Password, Username};
7use crate::fragment::{Fragment, FragmentError};
8use crate::path::{parse_path, Path, PathError};
9use crate::query::{parse_query, Query, QueryError};
10use crate::scheme::{parse_scheme, Scheme, SchemeError};
11
12/// A URI reference as defined in
13/// [[RFC3986, Section 4.1]](https://tools.ietf.org/html/rfc3986#section-4.1).
14///
15/// Specifically, a URI reference is either a URI or a relative reference (a schemeless URI).
16#[derive(Clone, Debug, Eq, Hash, PartialEq)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18pub struct URIReference<'uri> {
19    /// The authority component of the URI reference as defined in
20    /// [[RFC3986, Section 3.2]](https://tools.ietf.org/html/rfc3986#section-3.2).
21    authority: Option<Authority<'uri>>,
22
23    /// The fragment component of the URI reference as defined in
24    /// [[RFC3986, Section 3.5]](https://tools.ietf.org/html/rfc3986#section-3.5).
25    fragment: Option<Fragment<'uri>>,
26
27    /// The path component of the URI reference as defined in
28    /// [[RFC3986, Section 3.3]](https://tools.ietf.org/html/rfc3986#section-3.3).
29    path: Path<'uri>,
30
31    /// The query component of the URI reference as defined in
32    /// [[RFC3986, Section 3.4]](https://tools.ietf.org/html/rfc3986#section-3.4).
33    query: Option<Query<'uri>>,
34
35    /// The scheme component of the URI reference as defined in
36    /// [[RFC3986, Section 3.1](https://tools.ietf.org/html/rfc3986#section-3.1).
37    scheme: Option<Scheme<'uri>>,
38}
39
40impl<'uri> URIReference<'uri> {
41    /// Returns the authority, if present, of the URI reference.
42    ///
43    /// # Examples
44    ///
45    /// ```
46    /// use std::convert::TryFrom;
47    ///
48    /// use uriparse::URIReference;
49    ///
50    /// let reference = URIReference::try_from("//example.com/my/path").unwrap();
51    /// assert_eq!(reference.authority().unwrap().to_string(), "example.com");
52    /// ```
53    pub fn authority(&self) -> Option<&Authority<'uri>> {
54        self.authority.as_ref()
55    }
56
57    /// Constructs a default builder for a URI reference.
58    ///
59    /// This provides an alternative means of constructing a URI reference besides parsing and
60    /// [`URIReference::from_parts`].
61    ///
62    /// # Examples
63    ///
64    /// ```
65    /// use std::convert::TryFrom;
66    ///
67    /// use uriparse::{Authority, Path, Scheme, URIReference};
68    ///
69    /// let reference = URIReference::builder()
70    ///     .with_scheme(Some(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!(reference.to_string(), "http://example.com/my/path");
76    /// ```
77    pub fn builder<'new_uri>() -> URIReferenceBuilder<'new_uri> {
78        URIReferenceBuilder::default()
79    }
80
81    /// Returns whether the URI reference 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::URIReference;
91    ///
92    /// let reference = URIReference::try_from("http://example.com/my/path").unwrap();
93    /// assert!(reference.can_be_a_base());
94    ///
95    /// let reference = URIReference::try_from("ftp://127.0.0.1#fragment").unwrap();
96    /// assert!(!reference.can_be_a_base());
97    /// ```
98    pub fn can_be_a_base(&self) -> bool {
99        self.has_scheme() && !self.has_fragment()
100    }
101
102    /// Constructs a new [`URIReference`] from the individual parts: scheme, authority, path, query,
103    /// and 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::{Scheme, URIReference};
114    ///
115    /// let reference = URIReference::from_parts(
116    ///     None::<Scheme>,
117    ///     Some("example.com"),
118    ///     "/my/path",
119    ///     Some("query"),
120    ///     Some("fragment")
121    /// ).unwrap();
122    /// assert_eq!(reference.to_string(), "//example.com/my/path?query#fragment");
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: Option<TScheme>,
138        authority: Option<TAuthority>,
139        path: TPath,
140        query: Option<TQuery>,
141        fragment: Option<TFragment>,
142    ) -> Result<URIReference<'new_uri>, URIReferenceError>
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 scheme = match scheme {
156            Some(scheme) => Some(Scheme::try_from(scheme)?),
157            None => None,
158        };
159
160        let authority = match authority {
161            Some(authority) => Some(Authority::try_from(authority)?),
162            None => None,
163        };
164
165        let mut path = Path::try_from(path)?;
166
167        if authority.is_some() {
168            path.set_absolute(true);
169        }
170
171        validate_absolute_path(authority.as_ref(), &path)?;
172        validate_schemeless_path(scheme.as_ref(), authority.as_ref(), &path)?;
173
174        let query = match query {
175            Some(query) => Some(Query::try_from(query)?),
176            None => None,
177        };
178
179        let fragment = match fragment {
180            Some(fragment) => Some(Fragment::try_from(fragment)?),
181            None => None,
182        };
183
184        Ok(URIReference {
185            authority,
186            fragment,
187            path,
188            query,
189            scheme,
190        })
191    }
192
193    /// Returns the fragment, if present, of the URI reference.
194    ///
195    /// # Examples
196    ///
197    /// ```
198    /// use std::convert::TryFrom;
199    ///
200    /// use uriparse::URIReference;
201    ///
202    /// let reference = URIReference::try_from("http://example.com#fragment").unwrap();
203    /// assert_eq!(reference.fragment().unwrap(), "fragment");
204    /// ```
205    pub fn fragment(&self) -> Option<&Fragment<'uri>> {
206        self.fragment.as_ref()
207    }
208
209    /// Returns whether the URI reference has an authority component.
210    ///
211    /// # Examples
212    ///
213    /// ```
214    /// use std::convert::TryFrom;
215    ///
216    /// use uriparse::URIReference;
217    ///
218    /// let reference = URIReference::try_from("http://example.com").unwrap();
219    /// assert!(reference.has_authority());
220    ///
221    /// let reference = URIReference::try_from("").unwrap();
222    /// assert!(!reference.has_authority());
223    /// ```
224    pub fn has_authority(&self) -> bool {
225        self.authority.is_some()
226    }
227
228    /// Returns whether the URI reference has a fragment component.
229    ///
230    /// # Examples
231    ///
232    /// ```
233    /// use std::convert::TryFrom;
234    ///
235    /// use uriparse::URIReference;
236    ///
237    /// let reference = URIReference::try_from("#test").unwrap();
238    /// assert!(reference.has_fragment());
239    ///
240    /// let reference = URIReference::try_from("http://example.com").unwrap();
241    /// assert!(!reference.has_fragment());
242    /// ```
243    pub fn has_fragment(&self) -> bool {
244        self.fragment.is_some()
245    }
246
247    /// Returns whether the URI reference has a password component.
248    ///
249    /// # Examples
250    ///
251    /// ```
252    /// use std::convert::TryFrom;
253    ///
254    /// use uriparse::URIReference;
255    ///
256    /// let reference = URIReference::try_from("http://user:pass@127.0.0.1").unwrap();
257    /// assert!(reference.has_password());
258    ///
259    /// let reference = URIReference::try_from("http://user@127.0.0.1").unwrap();
260    /// assert!(!reference.has_password());
261    /// ```
262    pub fn has_password(&self) -> bool {
263        if let Some(ref authority) = self.authority {
264            authority.has_password()
265        } else {
266            false
267        }
268    }
269
270    /// Returns whether the URI reference has a port.
271    ///
272    /// # Examples
273    ///
274    /// ```
275    /// use std::convert::TryFrom;
276    ///
277    /// use uriparse::URIReference;
278    ///
279    /// let reference = URIReference::try_from("http://127.0.0.1:8080").unwrap();
280    /// assert!(reference.has_port());
281    ///
282    /// let reference = URIReference::try_from("http://127.0.0.1").unwrap();
283    /// assert!(!reference.has_port());
284    /// ```
285    pub fn has_port(&self) -> bool {
286        if let Some(ref authority) = self.authority {
287            authority.has_port()
288        } else {
289            false
290        }
291    }
292
293    /// Returns whether the URI reference has a query component.
294    ///
295    /// # Examples
296    ///
297    /// ```
298    /// use std::convert::TryFrom;
299    ///
300    /// use uriparse::URIReference;
301    ///
302    /// let reference = URIReference::try_from("/?my=query").unwrap();
303    /// assert!(reference.has_query());
304    ///
305    /// let reference = URIReference::try_from("http://example.com/my/path").unwrap();
306    /// assert!(!reference.has_query());
307    /// ```
308    pub fn has_query(&self) -> bool {
309        self.query.is_some()
310    }
311
312    /// Returns whether the URI reference has a scheme component.
313    ///
314    /// # Examples
315    ///
316    /// ```
317    /// use std::convert::TryFrom;
318    ///
319    /// use uriparse::URIReference;
320    ///
321    /// let reference = URIReference::try_from("http://example.com?my=query").unwrap();
322    /// assert!(reference.has_scheme());
323    ///
324    /// let reference = URIReference::try_from("/my/path").unwrap();
325    /// assert!(!reference.has_scheme());
326    /// ```
327    pub fn has_scheme(&self) -> bool {
328        self.scheme.is_some()
329    }
330
331    /// Returns whether the URI reference has a username component.
332    ///
333    /// # Examples
334    ///
335    /// ```
336    /// use std::convert::TryFrom;
337    ///
338    /// use uriparse::URIReference;
339    ///
340    /// let reference = URIReference::try_from("//username@example.com").unwrap();
341    /// assert!(reference.has_username());
342    ///
343    /// let reference = URIReference::try_from("http://example.com").unwrap();
344    /// assert!(!reference.has_username());
345    /// ```
346    pub fn has_username(&self) -> bool {
347        if let Some(ref authority) = self.authority {
348            authority.has_username()
349        } else {
350            false
351        }
352    }
353
354    /// Returns the host, if present, of the URI reference.
355    ///
356    /// # Examples
357    ///
358    /// ```
359    /// use std::convert::TryFrom;
360    ///
361    /// use uriparse::URIReference;
362    ///
363    /// let reference = URIReference::try_from("http://username@example.com").unwrap();
364    /// assert_eq!(reference.host().unwrap().to_string(), "example.com");
365    /// ```
366    pub fn host(&self) -> Option<&Host<'uri>> {
367        if let Some(ref authority) = self.authority {
368            Some(authority.host())
369        } else {
370            None
371        }
372    }
373
374    /// Consumes the URI reference and converts it into a builder with the same values.
375    ///
376    /// # Examples
377    ///
378    /// ```
379    /// use std::convert::TryFrom;
380    ///
381    /// use uriparse::{Fragment, Query, URIReference};
382    ///
383    /// let reference = URIReference::try_from("//example.com/path?query#fragment").unwrap();
384    /// let mut builder = reference.into_builder();
385    /// builder.query(None::<Query>).fragment(None::<Fragment>);
386    /// let reference = builder.build().unwrap();
387    /// assert_eq!(reference.to_string(), "//example.com/path");
388    /// ```
389    pub fn into_builder(self) -> URIReferenceBuilder<'uri> {
390        let mut builder = URIReferenceBuilder::new();
391        builder
392            .scheme(self.scheme)
393            .authority(self.authority)
394            .path(self.path)
395            .query(self.query)
396            .fragment(self.fragment);
397        builder
398    }
399
400    /// Converts the [`URIReference`] into an owned copy.
401    ///
402    /// If you construct the URI reference from a source with a non-static lifetime, you may run
403    /// into lifetime problems due to the way the struct is designed. Calling this function will
404    /// ensure that the returned value has a static lifetime.
405    ///
406    /// This is different from just cloning. Cloning the URI reference will just copy the
407    /// references, and thus the lifetime will remain the same.
408    pub fn into_owned(self) -> URIReference<'static> {
409        let scheme = self.scheme.map(Scheme::into_owned);
410        let authority = self.authority.map(Authority::into_owned);
411        let path = self.path.into_owned();
412        let query = self.query.map(Query::into_owned);
413        let fragment = self.fragment.map(Fragment::into_owned);
414
415        URIReference {
416            authority,
417            fragment,
418            path,
419            query,
420            scheme,
421        }
422    }
423
424    /// Consumes the [`URIReference`] and returns its parts: scheme, authority, path, query, and
425    /// fragment.
426    ///
427    /// # Examples
428    ///
429    /// ```
430    /// use std::convert::TryFrom;
431    ///
432    /// use uriparse::URIReference;
433    ///
434    /// let reference = URIReference::try_from(
435    ///     "http://username:password@example.com:80/my/path?my=query#fragment",
436    /// ).unwrap();
437    /// let (scheme, authority, path, query, fragment) = reference.into_parts();
438    ///
439    /// assert_eq!(scheme.unwrap(), "http");
440    /// assert_eq!(authority.unwrap().to_string(), "username:password@example.com:80");
441    /// assert_eq!(path, "/my/path");
442    /// assert_eq!(query.unwrap(), "my=query");
443    /// assert_eq!(fragment.unwrap(), "fragment");
444    /// ```
445    pub fn into_parts(
446        self,
447    ) -> (
448        Option<Scheme<'uri>>,
449        Option<Authority<'uri>>,
450        Path<'uri>,
451        Option<Query<'uri>>,
452        Option<Fragment<'uri>>,
453    ) {
454        (
455            self.scheme,
456            self.authority,
457            self.path,
458            self.query,
459            self.fragment,
460        )
461    }
462
463    /// Returns whether the URI reference is an absolute path reference.
464    ///
465    /// A URI reference is an absolute path reference if it is a relative reference that begins with
466    /// a single `'/'`.
467    ///
468    /// # Examples
469    ///
470    /// ```
471    /// use std::convert::TryFrom;
472    ///
473    /// use uriparse::URIReference;
474    ///
475    /// let reference = URIReference::try_from("/my/path").unwrap();
476    /// assert!(reference.is_absolute_path_reference());
477    /// ```
478    pub fn is_absolute_path_reference(&self) -> bool {
479        self.scheme.is_none() && self.authority.is_none() && self.path.is_absolute()
480    }
481
482    /// Returns whether the URI reference is a network path reference.
483    ///
484    /// A URI reference is a network path reference if it is a relative reference that begins with
485    /// two `'/'`.
486    ///
487    /// # Examples
488    ///
489    /// ```
490    /// use std::convert::TryFrom;
491    ///
492    /// use uriparse::URIReference;
493    ///
494    /// let reference = URIReference::try_from("//example.com").unwrap();
495    /// assert!(reference.is_network_path_reference());
496    /// ```
497    pub fn is_network_path_reference(&self) -> bool {
498        self.scheme.is_none() && self.authority.is_some()
499    }
500
501    /// Returns whether the URI reference is normalized.
502    ///
503    /// A normalized URI reference will have all of its components normalized.
504    ///
505    /// # Examples
506    ///
507    /// ```
508    /// use std::convert::TryFrom;
509    ///
510    /// use uriparse::URIReference;
511    ///
512    /// let reference = URIReference::try_from("http://example.com/?a=b").unwrap();
513    /// assert!(reference.is_normalized());
514    ///
515    /// let mut reference = URIReference::try_from("http://EXAMPLE.com/?a=b").unwrap();
516    /// assert!(!reference.is_normalized());
517    /// reference.normalize();
518    /// assert!(reference.is_normalized());
519    /// ```
520    pub fn is_normalized(&self) -> bool {
521        if let Some(scheme) = self.scheme.as_ref() {
522            if !scheme.is_normalized() {
523                return false;
524            }
525        }
526
527        if let Some(authority) = self.authority.as_ref() {
528            if !authority.is_normalized() {
529                return false;
530            }
531        }
532
533        if !self.path.is_normalized(self.scheme.is_none()) {
534            return false;
535        }
536
537        if let Some(query) = self.query.as_ref() {
538            if !query.is_normalized() {
539                return false;
540            }
541        }
542
543        if let Some(fragment) = self.fragment.as_ref() {
544            if !fragment.is_normalized() {
545                return false;
546            }
547        }
548
549        true
550    }
551
552    /// Returns whether the URI reference is a relative path reference.
553    ///
554    /// A URI reference is a relative path reference if it is a relative reference that does not
555    /// begin with a `'/'`.
556    ///
557    /// # Examples
558    ///
559    /// ```
560    /// use std::convert::TryFrom;
561    ///
562    /// use uriparse::URIReference;
563    ///
564    /// let reference = URIReference::try_from("my/path").unwrap();
565    /// assert!(reference.is_relative_path_reference());
566    /// ```
567    pub fn is_relative_path_reference(&self) -> bool {
568        self.scheme.is_none() && self.authority.is_none() && !self.path.is_absolute()
569    }
570
571    /// Returns whether the URI reference is a relative reference.
572    ///
573    /// A URI reference is a relative reference if it has no scheme.
574    ///
575    /// # Examples
576    ///
577    /// ```
578    /// use std::convert::TryFrom;
579    ///
580    /// use uriparse::URIReference;
581    ///
582    /// let reference = URIReference::try_from("/my/path").unwrap();
583    /// assert!(reference.is_relative_reference());
584    /// ```
585    pub fn is_relative_reference(&self) -> bool {
586        self.scheme.is_none()
587    }
588
589    /// Returns whether the URI reference is a URI.
590    ///
591    /// A URI reference is a URI if it has a scheme.
592    ///
593    /// # Examples
594    ///
595    /// ```
596    /// use std::convert::TryFrom;
597    ///
598    /// use uriparse::URIReference;
599    ///
600    /// let reference = URIReference::try_from("http://example.com").unwrap();
601    /// assert!(reference.is_uri());
602    /// ```
603    pub fn is_uri(&self) -> bool {
604        self.scheme.is_some()
605    }
606
607    /// Maps the authority using the given map function.
608    ///
609    /// This function will panic if, as a result of the authority change, the URI reference becomes
610    /// invalid.
611    ///
612    /// # Examples
613    ///
614    /// ```
615    /// use std::convert::TryFrom;
616    ///
617    /// use uriparse::{Authority, URIReference};
618    ///
619    /// let mut reference = URIReference::try_from("http://example.com").unwrap();
620    /// reference.map_authority(|_| Some(Authority::try_from("127.0.0.1").unwrap()));
621    /// assert_eq!(reference.to_string(), "http://127.0.0.1/");
622    /// ```
623    pub fn map_authority<TMapper>(&mut self, mapper: TMapper) -> Option<&Authority<'uri>>
624    where
625        TMapper: FnOnce(Option<Authority<'uri>>) -> Option<Authority<'uri>>,
626    {
627        let authority = mapper(self.authority.take());
628        self.set_authority(authority)
629            .expect("mapped authority resulted in invalid state")
630    }
631
632    /// Maps the fragment using the given map function.
633    ///
634    /// # Examples
635    ///
636    /// ```
637    /// use std::convert::TryFrom;
638    ///
639    /// use uriparse::{Fragment, URIReference};
640    ///
641    /// let mut reference = URIReference::try_from("http://example.com").unwrap();
642    /// reference.map_fragment(|_| Some(Fragment::try_from("fragment").unwrap()));
643    /// assert_eq!(reference.to_string(), "http://example.com/#fragment");
644    /// ```
645    pub fn map_fragment<TMapper>(&mut self, mapper: TMapper) -> Option<&Fragment<'uri>>
646    where
647        TMapper: FnOnce(Option<Fragment<'uri>>) -> Option<Fragment<'uri>>,
648    {
649        let fragment = mapper(self.fragment.take());
650        self.set_fragment(fragment)
651            .expect("mapped fragment resulted in invalid state")
652    }
653
654    /// Maps the path using the given map function.
655    ///
656    /// This function will panic if, as a result of the path change, the URI reference becomes
657    /// invalid.
658    ///
659    /// # Examples
660    ///
661    /// ```
662    /// use std::convert::TryFrom;
663    ///
664    /// use uriparse::{Authority, URIReference};
665    ///
666    /// let mut reference = URIReference::try_from("http://example.com").unwrap();
667    /// reference.map_path(|mut path| {
668    ///     path.push("test").unwrap();
669    ///     path.push("path").unwrap();
670    ///     path
671    /// });
672    /// assert_eq!(reference.to_string(), "http://example.com/test/path");
673    /// ```
674    pub fn map_path<TMapper>(&mut self, mapper: TMapper) -> &Path<'uri>
675    where
676        TMapper: FnOnce(Path<'uri>) -> Path<'uri>,
677    {
678        // Unsafe: We're creating an invalid path just as a temporary sentinel value, but it is
679        // replaced shortly after.
680        let temp_path = unsafe { Path::new_with_no_segments(true) };
681        let path = mapper(mem::replace(&mut self.path, temp_path));
682        self.set_path(path)
683            .expect("mapped path resulted in invalid state")
684    }
685
686    /// Maps the query using the given map function.
687    ///
688    /// # Examples
689    ///
690    /// ```
691    /// use std::convert::TryFrom;
692    ///
693    /// use uriparse::{Query, URIReference};
694    ///
695    /// let mut reference = URIReference::try_from("http://example.com").unwrap();
696    /// reference.map_query(|_| Some(Query::try_from("query").unwrap()));
697    /// assert_eq!(reference.to_string(), "http://example.com/?query");
698    /// ```
699    pub fn map_query<TMapper>(&mut self, mapper: TMapper) -> Option<&Query<'uri>>
700    where
701        TMapper: FnOnce(Option<Query<'uri>>) -> Option<Query<'uri>>,
702    {
703        let query = mapper(self.query.take());
704        self.set_query(query)
705            .expect("mapped query resulted in invalid state")
706    }
707
708    /// Maps the scheme using the given map function.
709    ///
710    /// This function will panic if, as a result of the scheme change, the URI reference becomes
711    /// invalid.
712    ///
713    /// # Examples
714    ///
715    /// ```
716    /// use std::convert::TryFrom;
717    ///
718    /// use uriparse::{Scheme, URIReference};
719    ///
720    /// let mut reference = URIReference::try_from("http://example.com").unwrap();
721    /// reference.map_scheme(|_| Some(Scheme::try_from("https").unwrap()));
722    /// assert_eq!(reference.to_string(), "https://example.com/");
723    /// ```
724    pub fn map_scheme<TMapper>(&mut self, mapper: TMapper) -> Option<&Scheme<'uri>>
725    where
726        TMapper: FnOnce(Option<Scheme<'uri>>) -> Option<Scheme<'uri>>,
727    {
728        let scheme = mapper(self.scheme.take());
729        self.set_scheme(scheme)
730            .expect("mapped scheme resulted in invalid state")
731    }
732
733    /// Normalizes the URI reference.
734    ///
735    /// A normalized URI reference will have all of its components normalized.
736    ///
737    /// # Examples
738    ///
739    /// ```
740    /// use std::convert::TryFrom;
741    ///
742    /// use uriparse::URIReference;
743    ///
744    /// let mut reference = URIReference::try_from("http://example.com/?a=b").unwrap();
745    /// reference.normalize();
746    /// assert_eq!(reference.to_string(), "http://example.com/?a=b");
747    ///
748    /// let mut reference = URIReference::try_from("http://EXAMPLE.com/?a=b").unwrap();
749    /// assert_eq!(reference.to_string(), "http://EXAMPLE.com/?a=b");
750    /// reference.normalize();
751    /// assert_eq!(reference.to_string(), "http://example.com/?a=b");
752    /// ```
753    pub fn normalize(&mut self) {
754        if let Some(scheme) = self.scheme.as_mut() {
755            scheme.normalize();
756        }
757
758        if let Some(authority) = self.authority.as_mut() {
759            authority.normalize();
760        }
761
762        self.path.normalize(self.scheme.is_none());
763
764        if let Some(query) = self.query.as_mut() {
765            query.normalize();
766        }
767
768        if let Some(fragment) = self.fragment.as_mut() {
769            fragment.normalize();
770        }
771    }
772
773    /// Returns the path of the URI reference.
774    ///
775    /// # Examples
776    ///
777    /// ```
778    /// use std::convert::TryFrom;
779    ///
780    /// use uriparse::URIReference;
781    ///
782    /// let reference = URIReference::try_from("http://127.0.0.1/my/path").unwrap();
783    /// assert_eq!(reference.path(), "/my/path");
784    /// ```
785    pub fn path(&self) -> &Path<'uri> {
786        &self.path
787    }
788
789    /// Returns the password, if present, of the URI reference.
790    ///
791    /// Usage of a password in URI and URI references is deprecated.
792    ///
793    /// # Examples
794    ///
795    /// ```
796    /// use std::convert::TryFrom;
797    ///
798    /// use uriparse::URIReference;
799    ///
800    /// let reference = URIReference::try_from("http://user:pass@example.com").unwrap();
801    /// assert_eq!(reference.password().unwrap(), "pass");
802    /// ```
803    pub fn password(&self) -> Option<&Password<'uri>> {
804        if let Some(ref authority) = self.authority {
805            authority.password()
806        } else {
807            None
808        }
809    }
810
811    /// Returns the port, if present, of the URI reference.
812    ///
813    /// # Examples
814    ///
815    /// ```
816    /// use std::convert::TryFrom;
817    ///
818    /// use uriparse::URIReference;
819    ///
820    /// let reference = URIReference::try_from("http://example.com:8080/").unwrap();
821    /// assert_eq!(reference.port().unwrap(), 8080);
822    /// ```
823    pub fn port(&self) -> Option<u16> {
824        if let Some(ref authority) = self.authority {
825            authority.port()
826        } else {
827            None
828        }
829    }
830
831    /// Returns the query, if present, of the URI reference.
832    ///
833    /// # Examples
834    ///
835    /// ```
836    /// use std::convert::TryFrom;
837    ///
838    /// use uriparse::URIReference;
839    ///
840    /// let reference = URIReference::try_from("http://127.0.0.1?my=query").unwrap();
841    /// assert_eq!(reference.query().unwrap(), "my=query");
842    /// ```
843    pub fn query(&self) -> Option<&Query<'uri>> {
844        self.query.as_ref()
845    }
846
847    /// Returns the scheme, if present, of the URI reference.
848    ///
849    /// # Examples
850    ///
851    /// ```
852    /// use std::convert::TryFrom;
853    ///
854    /// use uriparse::URIReference;
855    ///
856    /// let reference = URIReference::try_from("http://127.0.0.1/").unwrap();
857    /// assert_eq!(reference.scheme().unwrap(), "http");
858    /// ```
859    pub fn scheme(&self) -> Option<&Scheme<'uri>> {
860        self.scheme.as_ref()
861    }
862
863    /// Sets the authority of the URI reference.
864    ///
865    /// An error will be returned if the conversion to an [`Authority`] fails.
866    ///
867    /// The existing path will be set to absolute (i.e. starts with a `'/'`).
868    ///
869    /// # Examples
870    ///
871    /// ```
872    /// use std::convert::TryFrom;
873    ///
874    /// use uriparse::URIReference;
875    ///
876    /// let mut reference = URIReference::try_from("http://example.com").unwrap();
877    /// reference.set_authority(Some("user@example.com:80"));
878    /// assert_eq!(reference.to_string(), "http://user@example.com:80/");
879    /// ```
880    pub fn set_authority<TAuthority, TAuthorityError>(
881        &mut self,
882        authority: Option<TAuthority>,
883    ) -> Result<Option<&Authority<'uri>>, URIReferenceError>
884    where
885        Authority<'uri>: TryFrom<TAuthority, Error = TAuthorityError>,
886        URIReferenceError: From<TAuthorityError>,
887    {
888        self.authority = match authority {
889            Some(authority) => {
890                self.path.set_absolute(true);
891                Some(Authority::try_from(authority)?)
892            }
893            None => {
894                validate_absolute_path(None, &self.path)?;
895                None
896            }
897        };
898        Ok(self.authority())
899    }
900
901    /// Sets the fragment of the URI reference.
902    ///
903    /// An error will be returned if the conversion to a [`Fragment`] fails.
904    ///
905    /// # Examples
906    ///
907    /// ```
908    /// use std::convert::TryFrom;
909    ///
910    /// use uriparse::URIReference;
911    ///
912    /// let mut reference = URIReference::try_from("http://example.com").unwrap();
913    /// reference.set_fragment(Some("fragment"));
914    /// assert_eq!(reference.to_string(), "http://example.com/#fragment");
915    /// ```
916    pub fn set_fragment<TFragment, TFragmentError>(
917        &mut self,
918        fragment: Option<TFragment>,
919    ) -> Result<Option<&Fragment<'uri>>, URIReferenceError>
920    where
921        Fragment<'uri>: TryFrom<TFragment, Error = TFragmentError>,
922        URIReferenceError: From<TFragmentError>,
923    {
924        self.fragment = match fragment {
925            Some(fragment) => Some(Fragment::try_from(fragment)?),
926            None => None,
927        };
928        Ok(self.fragment())
929    }
930
931    /// Sets the path of the URI reference.
932    ///
933    /// An error will be returned in one of two cases:
934    ///  - The conversion to [`Path`] failed.
935    ///  - The path was set to a value that resulted in an invalid URI reference.
936    ///
937    /// Regardless of whether the given path was set as absolute or relative, if the URI
938    /// reference currently has an authority, the path will be forced to be absolute.
939    ///
940    /// # Examples
941    ///
942    /// ```
943    /// use std::convert::TryFrom;
944    ///
945    /// use uriparse::URIReference;
946    ///
947    /// let mut reference = URIReference::try_from("http://example.com").unwrap();
948    /// reference.set_path("my/path");
949    /// assert_eq!(reference.to_string(), "http://example.com/my/path");
950    /// ```
951    pub fn set_path<TPath, TPathError>(
952        &mut self,
953        path: TPath,
954    ) -> Result<&Path<'uri>, URIReferenceError>
955    where
956        Path<'uri>: TryFrom<TPath, Error = TPathError>,
957        URIReferenceError: From<TPathError>,
958    {
959        let mut path = Path::try_from(path)?;
960        validate_absolute_path(self.authority.as_ref(), &path)?;
961        validate_schemeless_path(self.scheme.as_ref(), self.authority.as_ref(), &path)?;
962
963        if self.authority.is_some() {
964            path.set_absolute(true);
965        }
966
967        self.path = path;
968        Ok(self.path())
969    }
970
971    /// Sets the query of the URI reference.
972    ///
973    /// An error will be returned if the conversion to a [`Query`] fails.
974    ///
975    /// # Examples
976    ///
977    /// ```
978    /// use std::convert::TryFrom;
979    ///
980    /// use uriparse::URIReference;
981    ///
982    /// let mut reference = URIReference::try_from("http://example.com").unwrap();
983    /// reference.set_query(Some("myquery"));
984    /// assert_eq!(reference.to_string(), "http://example.com/?myquery");
985    /// ```
986    pub fn set_query<TQuery, TQueryError>(
987        &mut self,
988        query: Option<TQuery>,
989    ) -> Result<Option<&Query<'uri>>, URIReferenceError>
990    where
991        Query<'uri>: TryFrom<TQuery, Error = TQueryError>,
992        URIReferenceError: From<TQueryError>,
993    {
994        self.query = match query {
995            Some(query) => Some(Query::try_from(query)?),
996            None => None,
997        };
998        Ok(self.query())
999    }
1000
1001    /// Sets the scheme of the URI reference.
1002    ///
1003    /// An error will be returned in one of two cases:
1004    ///  - The conversion to [`Scheme`] failed.
1005    ///  - The scheme was set to `None`, but the resulting URI reference has an invalid schemeless
1006    ///    path.
1007    ///
1008    /// # Examples
1009    ///
1010    /// ```
1011    /// use std::convert::TryFrom;
1012    ///
1013    /// use uriparse::URIReference;
1014    ///
1015    /// let mut reference = URIReference::try_from("http://example.com").unwrap();
1016    /// reference.set_scheme(Some("https"));
1017    /// assert_eq!(reference.to_string(), "https://example.com/");
1018    /// ```
1019    pub fn set_scheme<TScheme, TSchemeError>(
1020        &mut self,
1021        scheme: Option<TScheme>,
1022    ) -> Result<Option<&Scheme<'uri>>, URIReferenceError>
1023    where
1024        Scheme<'uri>: TryFrom<TScheme, Error = TSchemeError>,
1025        URIReferenceError: From<TSchemeError>,
1026    {
1027        self.scheme = match scheme {
1028            Some(scheme) => Some(Scheme::try_from(scheme)?),
1029            None => {
1030                validate_schemeless_path(None, self.authority.as_ref(), &self.path)?;
1031                None
1032            }
1033        };
1034        Ok(self.scheme())
1035    }
1036
1037    /// Returns a new URI reference which is identical but has a lifetime tied to this URI
1038    /// reference.
1039    ///
1040    /// This function will perform a memory allocation.
1041    pub fn to_borrowed(&self) -> URIReference {
1042        let scheme = self.scheme.as_ref().map(Scheme::as_borrowed);
1043        let authority = self.authority.as_ref().map(Authority::as_borrowed);
1044        let path = self.path.to_borrowed();
1045        let query = self.query.as_ref().map(Query::as_borrowed);
1046        let fragment = self.fragment.as_ref().map(Fragment::as_borrowed);
1047
1048        URIReference {
1049            authority,
1050            fragment,
1051            path,
1052            query,
1053            scheme,
1054        }
1055    }
1056
1057    /// Returns the username, if present, of the URI reference.
1058    ///
1059    /// # Examples
1060    ///
1061    /// ```
1062    /// use std::convert::TryFrom;
1063    ///
1064    /// use uriparse::URIReference;
1065    ///
1066    /// let reference = URIReference::try_from("http://username@example.com").unwrap();
1067    /// assert_eq!(reference.username().unwrap(), "username");
1068    /// ```
1069    pub fn username(&self) -> Option<&Username<'uri>> {
1070        if let Some(ref authority) = self.authority {
1071            authority.username()
1072        } else {
1073            None
1074        }
1075    }
1076}
1077
1078impl Display for URIReference<'_> {
1079    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1080        if let Some(ref scheme) = self.scheme {
1081            formatter.write_str(scheme.as_str())?;
1082            formatter.write_char(':')?;
1083        }
1084
1085        if let Some(ref authority) = self.authority {
1086            formatter.write_str("//")?;
1087            formatter.write_str(&authority.to_string())?;
1088        }
1089
1090        formatter.write_str(&self.path.to_string())?;
1091
1092        if let Some(ref query) = self.query {
1093            formatter.write_char('?')?;
1094            formatter.write_str(query.as_str())?;
1095        }
1096
1097        if let Some(ref fragment) = self.fragment {
1098            formatter.write_char('#')?;
1099            formatter.write_str(fragment.as_str())?;
1100        }
1101
1102        Ok(())
1103    }
1104}
1105
1106impl<'uri> From<URIReference<'uri>> for String {
1107    fn from(value: URIReference<'uri>) -> Self {
1108        value.to_string()
1109    }
1110}
1111
1112impl<'uri> TryFrom<&'uri [u8]> for URIReference<'uri> {
1113    type Error = URIReferenceError;
1114
1115    fn try_from(value: &'uri [u8]) -> Result<Self, Self::Error> {
1116        let (scheme, value) = match parse_scheme(value) {
1117            Ok((scheme, rest)) => {
1118                if rest.starts_with(b":") {
1119                    (Some(scheme), &rest[1..])
1120                } else {
1121                    (None, value)
1122                }
1123            }
1124            _ => (None, value),
1125        };
1126
1127        let (authority, value) = match value.get(0..2) {
1128            Some(b"//") => {
1129                let (authority, value) = parse_authority(&value[2..])?;
1130                (Some(authority), value)
1131            }
1132            _ => (None, value),
1133        };
1134
1135        let (mut path, value) = parse_path(value)?;
1136
1137        if authority.is_some() {
1138            path.set_absolute(true);
1139        }
1140
1141        validate_schemeless_path(scheme.as_ref(), authority.as_ref(), &path)?;
1142
1143        let (query, value) = if value.starts_with(b"?") {
1144            let (query, value) = parse_query(&value[1..])?;
1145            (Some(query), value)
1146        } else {
1147            (None, value)
1148        };
1149
1150        let fragment = if value.starts_with(b"#") {
1151            Some(Fragment::try_from(&value[1..])?)
1152        } else {
1153            None
1154        };
1155
1156        Ok(URIReference {
1157            authority,
1158            fragment,
1159            path,
1160            query,
1161            scheme,
1162        })
1163    }
1164}
1165
1166impl<'uri> TryFrom<&'uri str> for URIReference<'uri> {
1167    type Error = URIReferenceError;
1168
1169    fn try_from(value: &'uri str) -> Result<Self, Self::Error> {
1170        URIReference::try_from(value.as_bytes())
1171    }
1172}
1173
1174/// A builder type for [`URIReference]`.
1175///
1176/// You must use the [`URIReference::path`] function before building as URI references always have
1177/// have a path. Everything else is optional.
1178#[derive(Clone, Debug, Default, Eq, PartialEq)]
1179pub struct URIReferenceBuilder<'uri> {
1180    /// The authority component of the URI reference as defined in
1181    /// [[RFC3986, Section 3.2]](https://tools.ietf.org/html/rfc3986#section-3.2).
1182    authority: Option<Authority<'uri>>,
1183
1184    /// The fragment component of the URI reference as defined in
1185    /// [[RFC3986, Section 3.5]](https://tools.ietf.org/html/rfc3986#section-3.5).
1186    fragment: Option<Fragment<'uri>>,
1187
1188    /// The path component of the URI reference as defined in
1189    /// [[RFC3986, Section 3.3]](https://tools.ietf.org/html/rfc3986#section-3.3).
1190    path: Option<Path<'uri>>,
1191
1192    /// The query component of the URI reference as defined in
1193    /// [[RFC3986, Section 3.4]](https://tools.ietf.org/html/rfc3986#section-3.4).
1194    query: Option<Query<'uri>>,
1195
1196    /// The scheme component of the URI reference as defined in
1197    /// [[RFC3986, Section 3.1]](https://tools.ietf.org/html/rfc3986#section-3.1).
1198    scheme: Option<Scheme<'uri>>,
1199}
1200
1201impl<'uri> URIReferenceBuilder<'uri> {
1202    /// Sets the authority part of the URI reference.
1203    ///
1204    /// It is optional to specify a authority.
1205    ///
1206    /// # Examples
1207    ///
1208    /// ```
1209    /// use std::convert::TryFrom;
1210    ///
1211    /// use uriparse::{Authority, Path, URIReferenceBuilder};
1212    ///
1213    /// let mut builder = URIReferenceBuilder::new();
1214    /// builder
1215    ///     .authority(Some(Authority::try_from("example.com").unwrap()))
1216    ///     .path(Path::try_from("/my/path").unwrap());
1217    /// let reference = builder.build().unwrap();
1218    /// assert_eq!(reference.to_string(), "//example.com/my/path");
1219    /// ```
1220    pub fn authority(&mut self, authority: Option<Authority<'uri>>) -> &mut Self {
1221        self.authority = authority;
1222        self
1223    }
1224
1225    /// Consumes the builder and tries to build a [`URIReference`].
1226    ///
1227    /// This function will error in one of two situations:
1228    ///  - A path was not specified in the builder.
1229    ///  - While all individual components were valid, their combination as a URI reference was
1230    ///    invalid.
1231    ///
1232    /// # Examples
1233    ///
1234    /// First error type (path not specified):
1235    ///
1236    /// ```
1237    /// use uriparse::URIReferenceBuilder;
1238    ///
1239    /// let result = URIReferenceBuilder::new().build();
1240    /// assert!(result.is_err());
1241    /// ```
1242    ///
1243    /// Second error type (first segment in schemeless path cannot contain a `':'`):
1244    ///
1245    /// ```
1246    /// use std::convert::TryFrom;
1247    ///
1248    /// use uriparse::{Path, URIReferenceBuilder};
1249    ///
1250    /// let result = URIReferenceBuilder::new()
1251    ///     .with_path(Path::try_from("my:/path").unwrap())
1252    ///     .build();
1253    /// assert!(result.is_err());
1254    /// ```
1255    pub fn build(self) -> Result<URIReference<'uri>, URIReferenceError> {
1256        let path = match self.path {
1257            Some(path) => path,
1258            None => return Err(URIReferenceError::MissingPath),
1259        };
1260
1261        URIReference::from_parts(self.scheme, self.authority, path, self.query, self.fragment)
1262    }
1263
1264    /// Sets the fragment part of the URI reference.
1265    ///
1266    /// It is optional to specify a fragment.
1267    ///
1268    /// # Examples
1269    ///
1270    /// ```
1271    /// use std::convert::TryFrom;
1272    ///
1273    /// use uriparse::{Fragment, Path, URIReferenceBuilder};
1274    ///
1275    /// let mut builder = URIReferenceBuilder::new();
1276    /// builder
1277    ///     .path(Path::try_from("/my/path").unwrap())
1278    ///     .fragment(Some(Fragment::try_from("fragment").unwrap()));
1279    /// let reference = builder.build().unwrap();
1280    /// assert_eq!(reference.to_string(), "/my/path#fragment");
1281    /// ```
1282    pub fn fragment(&mut self, fragment: Option<Fragment<'uri>>) -> &mut Self {
1283        self.fragment = fragment;
1284        self
1285    }
1286
1287    /// Constructs a new builder with nothing set.
1288    pub fn new() -> Self {
1289        URIReferenceBuilder::default()
1290    }
1291
1292    /// Sets the path part of the URI reference.
1293    ///
1294    /// It is required to specify a path. Not doing so will result in an error during the
1295    /// [`URIReferenceBuilder::build`] function.
1296    ///
1297    /// # Examples
1298    ///
1299    /// ```
1300    /// use std::convert::TryFrom;
1301    ///
1302    /// use uriparse::{Path, URIReferenceBuilder};
1303    ///
1304    /// let mut builder = URIReferenceBuilder::new();
1305    /// builder
1306    ///     .path(Path::try_from("/my/path").unwrap());
1307    /// let reference = builder.build().unwrap();
1308    /// assert_eq!(reference.to_string(), "/my/path");
1309    /// ```
1310    pub fn path(&mut self, path: Path<'uri>) -> &mut Self {
1311        self.path = Some(path);
1312        self
1313    }
1314
1315    /// Sets the query part of the URI reference.
1316    ///
1317    /// It is optional to specify a query.
1318    ///
1319    /// # Examples
1320    ///
1321    /// ```
1322    /// use std::convert::TryFrom;
1323    ///
1324    /// use uriparse::{Path, Query, URIReferenceBuilder};
1325    ///
1326    /// let mut builder = URIReferenceBuilder::new();
1327    /// builder
1328    ///     .path(Path::try_from("/my/path").unwrap())
1329    ///     .query(Some(Query::try_from("query").unwrap()));
1330    /// let reference = builder.build().unwrap();
1331    /// assert_eq!(reference.to_string(), "/my/path?query");
1332    /// ```
1333    pub fn query(&mut self, query: Option<Query<'uri>>) -> &mut Self {
1334        self.query = query;
1335        self
1336    }
1337
1338    /// Sets the scheme part of the URI reference.
1339    ///
1340    /// It is optional to specify a scheme.
1341    ///
1342    /// # Examples
1343    ///
1344    /// ```
1345    /// use std::convert::TryFrom;
1346    ///
1347    /// use uriparse::{Authority, Path, Scheme, URIReferenceBuilder};
1348    ///
1349    /// let mut builder = URIReferenceBuilder::new();
1350    /// builder
1351    ///     .scheme(Some(Scheme::HTTP))
1352    ///     .authority(Some(Authority::try_from("example.com").unwrap()))
1353    ///     .path(Path::try_from("/my/path").unwrap());
1354    /// let reference = builder.build().unwrap();
1355    /// assert_eq!(reference.to_string(), "http://example.com/my/path");
1356    /// ```
1357    pub fn scheme(&mut self, scheme: Option<Scheme<'uri>>) -> &mut Self {
1358        self.scheme = scheme;
1359        self
1360    }
1361
1362    /// Sets the authority part of the URI reference.
1363    ///
1364    /// If the given authority is not a valid authority (i.e. the conversion fails), an error is
1365    /// return.
1366    ///
1367    /// It is optional to specify an authority.
1368    ///
1369    /// # Examples
1370    ///
1371    /// ```
1372    /// use uriparse::URIReferenceBuilder;
1373    ///
1374    /// let mut builder = URIReferenceBuilder::new();
1375    /// builder
1376    ///     .try_authority(Some("example.com"))
1377    ///     .unwrap()
1378    ///     .try_path("/my/path")
1379    ///     .unwrap();
1380    /// let reference = builder.build().unwrap();
1381    /// assert_eq!(reference.to_string(), "//example.com/my/path");
1382    /// ```
1383    pub fn try_authority<TAuthority, TAuthorityError>(
1384        &mut self,
1385        authority: Option<TAuthority>,
1386    ) -> Result<&mut Self, TAuthorityError>
1387    where
1388        Authority<'uri>: TryFrom<TAuthority, Error = TAuthorityError>,
1389        AuthorityError: From<TAuthorityError>,
1390    {
1391        self.authority = match authority {
1392            Some(authority) => Some(Authority::try_from(authority).map_err(|error| error)?),
1393            None => None,
1394        };
1395        Ok(self)
1396    }
1397
1398    /// Sets the fragment part of the URI reference.
1399    ///
1400    /// If the given fragment is not a valid fragment (i.e. the conversion fails), an error is
1401    /// returned.
1402    ///
1403    /// It is optional to specify a fragment.
1404    ///
1405    /// # Examples
1406    ///
1407    /// ```
1408    /// use uriparse::URIReferenceBuilder;
1409    ///
1410    /// let mut builder = URIReferenceBuilder::new();
1411    /// builder
1412    ///     .try_path("/my/path")
1413    ///     .unwrap()
1414    ///     .try_fragment(Some("fragment"))
1415    ///     .unwrap();
1416    /// let reference = builder.build().unwrap();
1417    /// assert_eq!(reference.to_string(), "/my/path#fragment");
1418    /// ```
1419    pub fn try_fragment<TFragment, TFragmentError>(
1420        &mut self,
1421        fragment: Option<TFragment>,
1422    ) -> Result<&mut Self, FragmentError>
1423    where
1424        Fragment<'uri>: TryFrom<TFragment, Error = TFragmentError>,
1425        FragmentError: From<TFragmentError>,
1426    {
1427        self.fragment = match fragment {
1428            Some(fragment) => Some(Fragment::try_from(fragment).map_err(|error| error)?),
1429            None => None,
1430        };
1431        Ok(self)
1432    }
1433
1434    /// Sets the path part of the URI reference.
1435    ///
1436    /// If the given path is not a valid path (i.e. the conversion fails), an error is returned.
1437    ///
1438    /// It is required to specify a path. Not doing so will result in an error during the
1439    /// [`URIReferenceBuilder::build`] function.
1440    ///
1441    /// # Examples
1442    ///
1443    /// ```
1444    /// use uriparse::URIReferenceBuilder;
1445    ///
1446    /// let mut builder = URIReferenceBuilder::new();
1447    /// builder
1448    ///     .try_path("/my/path")
1449    ///     .unwrap();
1450    /// let reference = builder.build().unwrap();
1451    /// assert_eq!(reference.to_string(), "/my/path");
1452    /// ```
1453    pub fn try_path<TPath, TPathError>(&mut self, path: TPath) -> Result<&mut Self, PathError>
1454    where
1455        Path<'uri>: TryFrom<TPath, Error = TPathError>,
1456        PathError: From<TPathError>,
1457    {
1458        self.path = Some(Path::try_from(path).map_err(|error| error)?);
1459        Ok(self)
1460    }
1461
1462    /// Sets the query part of the URI reference.
1463    ///
1464    /// If the given query is not a valid query (i.e. the conversion fails), an error is returned.
1465    ///
1466    /// It is optional to specify a query.
1467    ///
1468    /// # Examples
1469    ///
1470    /// ```
1471    /// use uriparse::URIReferenceBuilder;
1472    ///
1473    /// let mut builder = URIReferenceBuilder::new();
1474    /// builder
1475    ///     .try_path("/my/path")
1476    ///     .unwrap()
1477    ///     .try_query(Some("query"))
1478    ///     .unwrap();
1479    /// let reference = builder.build().unwrap();
1480    /// assert_eq!(reference.to_string(), "/my/path?query");
1481    /// ```
1482    pub fn try_query<TQuery, TQueryError>(
1483        &mut self,
1484        query: Option<TQuery>,
1485    ) -> Result<&mut Self, QueryError>
1486    where
1487        Query<'uri>: TryFrom<TQuery, Error = TQueryError>,
1488        QueryError: From<TQueryError>,
1489    {
1490        self.query = match query {
1491            Some(query) => Some(Query::try_from(query).map_err(|error| error)?),
1492            None => None,
1493        };
1494        Ok(self)
1495    }
1496
1497    /// Sets the scheme part of the URI reference.
1498    ///
1499    /// If the given scheme is not a valid scheme (i.e. the conversion fails), an error is returned.
1500    ///
1501    /// It is optional to specify a scheme.
1502    ///
1503    /// # Examples
1504    ///
1505    /// ```
1506    /// use uriparse::URIReferenceBuilder;
1507    ///
1508    /// let mut builder = URIReferenceBuilder::new();
1509    /// builder
1510    ///     .try_scheme(Some("urn"))
1511    ///     .unwrap()
1512    ///     .try_path("path")
1513    ///     .unwrap();
1514    /// let uri = builder.build().unwrap();
1515    /// assert_eq!(uri.to_string(), "urn:path");
1516    /// ```
1517    pub fn try_scheme<TScheme, TSchemeError>(
1518        &mut self,
1519        scheme: Option<TScheme>,
1520    ) -> Result<&mut Self, SchemeError>
1521    where
1522        Scheme<'uri>: TryFrom<TScheme, Error = TSchemeError>,
1523        SchemeError: From<TSchemeError>,
1524    {
1525        self.scheme = match scheme {
1526            Some(scheme) => Some(Scheme::try_from(scheme).map_err(|error| error)?),
1527            None => None,
1528        };
1529        Ok(self)
1530    }
1531
1532    /// Consumes the builder and sets the authority part of the URI reference.
1533    ///
1534    /// It is optional to specify an authority.
1535    ///
1536    /// # Examples
1537    ///
1538    /// ```
1539    /// use std::convert::TryFrom;
1540    ///
1541    /// use uriparse::{Authority, Path, URIReferenceBuilder};
1542    ///
1543    /// let reference = URIReferenceBuilder::new()
1544    ///     .with_authority(Some(Authority::try_from("example.com").unwrap()))
1545    ///     .with_path(Path::try_from("/").unwrap())
1546    ///     .build()
1547    ///     .unwrap();
1548    /// assert_eq!(reference.to_string(), "//example.com/")
1549    /// ```
1550    pub fn with_authority(mut self, authority: Option<Authority<'uri>>) -> Self {
1551        self.authority(authority);
1552        self
1553    }
1554
1555    /// Consumes the builder and sets the fragment part of the URI reference.
1556    ///
1557    /// It is optional to specify a fragment.
1558    ///
1559    /// # Examples
1560    ///
1561    /// ```
1562    /// use std::convert::TryFrom;
1563    ///
1564    /// use uriparse::{Fragment, Path, URIReferenceBuilder};
1565    ///
1566    /// let reference = URIReferenceBuilder::new()
1567    ///     .with_path(Path::try_from("/").unwrap())
1568    ///     .with_fragment(Some(Fragment::try_from("fragment").unwrap()))
1569    ///     .build()
1570    ///     .unwrap();
1571    /// assert_eq!(reference.to_string(), "/#fragment")
1572    /// ```
1573    pub fn with_fragment(mut self, fragment: Option<Fragment<'uri>>) -> Self {
1574        self.fragment(fragment);
1575        self
1576    }
1577
1578    /// Consumes the builder and sets the path part of the URI reference.
1579    ///
1580    /// It is required to specify a path. Not doing so will result in an error during the
1581    /// [`URIReferenceBuilder::build`] function.
1582    ///
1583    /// # Examples
1584    ///
1585    /// ```
1586    /// use std::convert::TryFrom;
1587    ///
1588    /// use uriparse::{Path, URIReferenceBuilder};
1589    ///
1590    /// let reference = URIReferenceBuilder::new()
1591    ///     .with_path(Path::try_from("/").unwrap())
1592    ///     .build()
1593    ///     .unwrap();
1594    /// assert_eq!(reference.to_string(), "/")
1595    /// ```
1596    pub fn with_path(mut self, path: Path<'uri>) -> Self {
1597        self.path(path);
1598        self
1599    }
1600
1601    /// Consumes the builder and sets the query part of the URI reference.
1602    ///
1603    /// It is optional to specify a query.
1604    ///
1605    /// # Examples
1606    ///
1607    /// ```
1608    /// use std::convert::TryFrom;
1609    ///
1610    /// use uriparse::{Path, Query, URIReferenceBuilder};
1611    ///
1612    /// let reference = URIReferenceBuilder::new()
1613    ///     .with_path(Path::try_from("/").unwrap())
1614    ///     .with_query(Some(Query::try_from("query").unwrap()))
1615    ///     .build()
1616    ///     .unwrap();
1617    /// assert_eq!(reference.to_string(), "/?query")
1618    /// ```
1619    pub fn with_query(mut self, query: Option<Query<'uri>>) -> Self {
1620        self.query(query);
1621        self
1622    }
1623
1624    /// Consumes the builder and sets the scheme part of the URI reference.
1625    ///
1626    /// It is optional to specify a scheme.
1627    ///
1628    /// # Examples
1629    ///
1630    /// ```
1631    /// use std::convert::TryFrom;
1632    ///
1633    /// use uriparse::{Authority, Path, Scheme, URIReferenceBuilder};
1634    ///
1635    /// let reference = URIReferenceBuilder::new()
1636    ///     .with_scheme(Some(Scheme::HTTP))
1637    ///     .with_authority(Some(Authority::try_from("example.com").unwrap()))
1638    ///     .with_path(Path::try_from("/").unwrap())
1639    ///     .build()
1640    ///     .unwrap();
1641    /// assert_eq!(reference.to_string(), "http://example.com/")
1642    /// ```
1643    pub fn with_scheme(mut self, scheme: Option<Scheme<'uri>>) -> Self {
1644        self.scheme(scheme);
1645        self
1646    }
1647}
1648
1649/// An error representing an invalid URI reference.
1650#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1651#[non_exhaustive]
1652pub enum URIReferenceError {
1653    /// Represents the case when there is no authority, but the first path segment starts with
1654    /// `"//"`. This is not allowed because it would be interpreted as an authority component.
1655    ///
1656    /// This can only occur when using creation functions that act on individual parts (e.g.
1657    /// [`URIReference::from_parts`]).
1658    AbsolutePathStartsWithTwoSlashes,
1659
1660    /// The authority component of the relative reference was invalid.
1661    Authority(AuthorityError),
1662
1663    /// The fragment component of the relative reference was invalid.
1664    Fragment(FragmentError),
1665
1666    /// This error occurs when you do not specify a path component on the builder.
1667    ///
1668    /// This can only occur when using [`URIReferenceBuilder`].
1669    MissingPath,
1670
1671    /// The path component of the relative reference was invalid.
1672    Path(PathError),
1673
1674    /// The query component of the relative reference was invalid.
1675    Query(QueryError),
1676
1677    /// The scheme component of the relative reference was invalid.
1678    Scheme(SchemeError),
1679
1680    /// Represents the case when there is no authority, but the first path segment starts with
1681    /// `"//"`. This is not allowed because it would be interpreted as an authority component.
1682    ///
1683    /// This can only occur when using creation functions that act on individual parts (e.g.
1684    /// [`URIReference::from_parts`]).
1685    SchemelessPathStartsWithColonSegment,
1686}
1687
1688impl Display for URIReferenceError {
1689    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1690        use self::URIReferenceError::*;
1691
1692        match self {
1693            AbsolutePathStartsWithTwoSlashes => write!(
1694                formatter,
1695                "absolute path URI reference starts with two slashes"
1696            ),
1697            Authority(error) => error.fmt(formatter),
1698            Fragment(error) => error.fmt(formatter),
1699            Path(error) => error.fmt(formatter),
1700            Query(error) => error.fmt(formatter),
1701            Scheme(error) => error.fmt(formatter),
1702            MissingPath => write!(formatter, "URI reference missing path"),
1703            SchemelessPathStartsWithColonSegment => write!(
1704                formatter,
1705                "schemeless path URI reference starts with colon segment"
1706            ),
1707        }
1708    }
1709}
1710
1711impl Error for URIReferenceError {}
1712
1713impl From<Infallible> for URIReferenceError {
1714    fn from(_: Infallible) -> Self {
1715        URIReferenceError::AbsolutePathStartsWithTwoSlashes
1716    }
1717}
1718
1719impl From<AuthorityError> for URIReferenceError {
1720    fn from(value: AuthorityError) -> Self {
1721        URIReferenceError::Authority(value)
1722    }
1723}
1724
1725impl From<FragmentError> for URIReferenceError {
1726    fn from(value: FragmentError) -> Self {
1727        URIReferenceError::Fragment(value)
1728    }
1729}
1730
1731impl From<PathError> for URIReferenceError {
1732    fn from(value: PathError) -> Self {
1733        URIReferenceError::Path(value)
1734    }
1735}
1736
1737impl From<QueryError> for URIReferenceError {
1738    fn from(value: QueryError) -> Self {
1739        URIReferenceError::Query(value)
1740    }
1741}
1742
1743impl From<SchemeError> for URIReferenceError {
1744    fn from(value: SchemeError) -> Self {
1745        URIReferenceError::Scheme(value)
1746    }
1747}
1748
1749fn validate_absolute_path(
1750    authority: Option<&Authority>,
1751    path: &Path,
1752) -> Result<(), URIReferenceError> {
1753    if authority.is_some()
1754        || path.is_relative()
1755        || path.segments().len() == 1
1756        || !path.segments().first().unwrap().is_empty()
1757    {
1758        Ok(())
1759    } else {
1760        Err(URIReferenceError::AbsolutePathStartsWithTwoSlashes)
1761    }
1762}
1763
1764fn validate_schemeless_path(
1765    scheme: Option<&Scheme>,
1766    authority: Option<&Authority>,
1767    path: &Path,
1768) -> Result<(), URIReferenceError> {
1769    if scheme.is_some()
1770        || authority.is_some()
1771        || !path
1772            .segments()
1773            .first()
1774            .unwrap()
1775            .bytes()
1776            .any(|byte| byte == b':')
1777    {
1778        Ok(())
1779    } else {
1780        Err(URIReferenceError::SchemelessPathStartsWithColonSegment)
1781    }
1782}
1783
1784#[cfg(test)]
1785mod test {
1786    use super::*;
1787
1788    #[test]
1789    fn test_parse_uri_reference() {
1790        let actual = URIReference::try_from("http://example.com").unwrap();
1791        let expected = URIReference::from_parts(
1792            Some(Scheme::HTTP),
1793            Some("example.com"),
1794            "/",
1795            None::<Query>,
1796            None::<Fragment>,
1797        )
1798        .unwrap();
1799        assert_eq!(actual, expected);
1800
1801        let actual = URIReference::try_from("http://example.com/").unwrap();
1802        let expected = URIReference::from_parts(
1803            Some(Scheme::HTTP),
1804            Some("example.com"),
1805            "/",
1806            None::<Query>,
1807            None::<Fragment>,
1808        )
1809        .unwrap();
1810        assert_eq!(actual, expected);
1811
1812        let actual = URIReference::try_from("http://example.com").unwrap();
1813        let expected = URIReference::from_parts(
1814            Some(Scheme::HTTP),
1815            Some("example.com"),
1816            "",
1817            None::<Query>,
1818            None::<Fragment>,
1819        )
1820        .unwrap();
1821        assert_eq!(actual, expected);
1822
1823        let actual = URIReference::try_from("http://example.com/").unwrap();
1824        let expected = URIReference::from_parts(
1825            Some(Scheme::HTTP),
1826            Some("example.com"),
1827            "",
1828            None::<Query>,
1829            None::<Fragment>,
1830        )
1831        .unwrap();
1832        assert_eq!(actual, expected);
1833
1834        let actual = URIReference::try_from("http:").unwrap();
1835        let expected = URIReference::from_parts(
1836            Some(Scheme::HTTP),
1837            None::<Authority>,
1838            "",
1839            None::<Query>,
1840            None::<Fragment>,
1841        )
1842        .unwrap();
1843        assert_eq!(actual, expected);
1844
1845        let actual = URIReference::try_from("http:/").unwrap();
1846        let expected = URIReference::from_parts(
1847            Some(Scheme::HTTP),
1848            None::<Authority>,
1849            "/",
1850            None::<Query>,
1851            None::<Fragment>,
1852        )
1853        .unwrap();
1854        assert_eq!(actual, expected);
1855
1856        let actual = URIReference::try_from("http:/path").unwrap();
1857        let expected = URIReference::from_parts(
1858            Some(Scheme::HTTP),
1859            None::<Authority>,
1860            "/path",
1861            None::<Query>,
1862            None::<Fragment>,
1863        )
1864        .unwrap();
1865        assert_eq!(actual, expected);
1866
1867        let actual = URIReference::try_from("//example.com/").unwrap();
1868        let expected = URIReference::from_parts(
1869            None::<Scheme>,
1870            Some("example.com"),
1871            "/",
1872            None::<Query>,
1873            None::<Fragment>,
1874        )
1875        .unwrap();
1876        assert_eq!(actual, expected);
1877
1878        let actual = URIReference::try_from("").unwrap();
1879        let expected = URIReference::from_parts(
1880            None::<Scheme>,
1881            None::<Authority>,
1882            "",
1883            None::<Query>,
1884            None::<Fragment>,
1885        )
1886        .unwrap();
1887        assert_eq!(actual, expected);
1888
1889        let actual = URIReference::try_from("*").unwrap();
1890        let expected = URIReference::from_parts(
1891            None::<Scheme>,
1892            None::<Authority>,
1893            "*",
1894            None::<Query>,
1895            None::<Fragment>,
1896        )
1897        .unwrap();
1898        assert_eq!(actual, expected);
1899
1900        let actual = URIReference::try_from("/").unwrap();
1901        let expected = URIReference::from_parts(
1902            None::<Scheme>,
1903            None::<Authority>,
1904            "/",
1905            None::<Query>,
1906            None::<Fragment>,
1907        )
1908        .unwrap();
1909        assert_eq!(actual, expected);
1910
1911        let actual = URIReference::try_from("test/path").unwrap();
1912        let expected = URIReference::from_parts(
1913            None::<Scheme>,
1914            None::<Authority>,
1915            "test/path",
1916            None::<Query>,
1917            None::<Fragment>,
1918        )
1919        .unwrap();
1920        assert_eq!(actual, expected);
1921    }
1922
1923    #[test]
1924    fn test_parse_uri_reference_error() {
1925        assert_eq!(
1926            URIReference::try_from("://www.example.com/"),
1927            Err(URIReferenceError::SchemelessPathStartsWithColonSegment)
1928        );
1929    }
1930}