uriparse/
relative_reference.rs

1use std::convert::{Infallible, TryFrom};
2use std::error::Error;
3use std::fmt::{self, Display, Formatter};
4
5use crate::authority::{Authority, AuthorityError, Host, Password, Username};
6use crate::fragment::{Fragment, FragmentError};
7use crate::path::{Path, PathError};
8use crate::query::{Query, QueryError};
9use crate::scheme::Scheme;
10use crate::uri_reference::{URIReference, URIReferenceBuilder, URIReferenceError};
11
12/// A relative reference as defined in
13/// [[RFC3986, Section 4.1]](https://tools.ietf.org/html/rfc3986#section-4.1).
14///
15/// Specifically, a relative reference is a URI reference without a scheme.
16#[derive(Clone, Debug, Eq, Hash, PartialEq)]
17pub struct RelativeReference<'uri> {
18    /// All relative references are also URI references, so we just maintain a [`URIReference`]
19    /// underneath.
20    uri_reference: URIReference<'uri>,
21}
22
23impl<'uri> RelativeReference<'uri> {
24    pub fn as_uri_reference(&self) -> &URIReference<'uri> {
25        &self.uri_reference
26    }
27
28    /// Returns the authority, if present, of the relative reference.
29    ///
30    /// # Examples
31    ///
32    /// ```
33    /// use std::convert::TryFrom;
34    ///
35    /// use uriparse::RelativeReference;
36    ///
37    /// let reference = RelativeReference::try_from("//example.com/my/path").unwrap();
38    /// assert_eq!(reference.authority().unwrap().to_string(), "example.com");
39    /// ```
40    pub fn authority(&self) -> Option<&Authority<'uri>> {
41        self.uri_reference.authority()
42    }
43
44    /// Constructs a default builder for a relative reference.
45    ///
46    /// This provides an alternative means of constructing a relative reference besides parsing and
47    /// [`RelativeReference::from_parts`].
48    ///
49    /// # Examples
50    ///
51    /// ```
52    /// use std::convert::TryFrom;
53    ///
54    /// use uriparse::{Fragment, Path, RelativeReference};
55    ///
56    /// let reference = RelativeReference::builder()
57    ///     .with_path(Path::try_from("/my/path").unwrap())
58    ///     .with_fragment(Some(Fragment::try_from("fragment").unwrap()))
59    ///     .build()
60    ///     .unwrap();
61    /// assert_eq!(reference.to_string(), "/my/path#fragment");
62    /// ```
63    pub fn builder<'new_uri>() -> RelativeReferenceBuilder<'new_uri> {
64        RelativeReferenceBuilder::new()
65    }
66
67    /// Constructs a new [`RelativeReference`] from the individual parts: authority, path, query,
68    /// and fragment.
69    ///
70    /// The lifetime used by the resulting value will be the lifetime of the part that is most
71    /// restricted in scope.
72    ///
73    /// # Examples
74    ///
75    /// ```
76    /// use std::convert::TryFrom;
77    ///
78    /// use uriparse::{Scheme, RelativeReference};
79    ///
80    /// let reference = RelativeReference::from_parts(
81    ///     Some("example.com"),
82    ///     "/my/path",
83    ///     Some("query"),
84    ///     Some("fragment")
85    /// ).unwrap();
86    /// assert_eq!(reference.to_string(), "//example.com/my/path?query#fragment");
87    /// ```
88    pub fn from_parts<
89        'new_uri,
90        TAuthority,
91        TPath,
92        TQuery,
93        TFragment,
94        TAuthorityError,
95        TPathError,
96        TQueryError,
97        TFragmentError,
98    >(
99        authority: Option<TAuthority>,
100        path: TPath,
101        query: Option<TQuery>,
102        fragment: Option<TFragment>,
103    ) -> Result<RelativeReference<'new_uri>, RelativeReferenceError>
104    where
105        Authority<'new_uri>: TryFrom<TAuthority, Error = TAuthorityError>,
106        Path<'new_uri>: TryFrom<TPath, Error = TPathError>,
107        Query<'new_uri>: TryFrom<TQuery, Error = TQueryError>,
108        Fragment<'new_uri>: TryFrom<TFragment, Error = TFragmentError>,
109        URIReferenceError:
110            From<TAuthorityError> + From<TPathError> + From<TQueryError> + From<TFragmentError>,
111    {
112        let uri_reference =
113            URIReference::from_parts(None::<Scheme>, authority, path, query, fragment)
114                .map_err(|error| RelativeReferenceError::try_from(error).unwrap())?;
115        Ok(RelativeReference { uri_reference })
116    }
117
118    /// Returns the fragment, if present, of the relative reference.
119    ///
120    /// # Examples
121    ///
122    /// ```
123    /// use std::convert::TryFrom;
124    ///
125    /// use uriparse::RelativeReference;
126    ///
127    /// let reference = RelativeReference::try_from("//example.com#fragment").unwrap();
128    /// assert_eq!(reference.fragment().unwrap(), "fragment");
129    /// ```
130    pub fn fragment(&self) -> Option<&Fragment<'uri>> {
131        self.uri_reference.fragment()
132    }
133
134    /// Returns whether the relative reference has an authority component.
135    ///
136    /// # Examples
137    ///
138    /// ```
139    /// use std::convert::TryFrom;
140    ///
141    /// use uriparse::RelativeReference;
142    ///
143    /// let reference = RelativeReference::try_from("//example.com").unwrap();
144    /// assert!(reference.has_authority());
145    ///
146    /// let reference = RelativeReference::try_from("").unwrap();
147    /// assert!(!reference.has_authority());
148    /// ```
149    pub fn has_authority(&self) -> bool {
150        self.uri_reference.has_authority()
151    }
152
153    /// Returns whether the relative reference has a fragment component.
154    ///
155    /// # Examples
156    ///
157    /// ```
158    /// use std::convert::TryFrom;
159    ///
160    /// use uriparse::RelativeReference;
161    ///
162    /// let reference = RelativeReference::try_from("#test").unwrap();
163    /// assert!(reference.has_fragment());
164    ///
165    /// let reference = RelativeReference::try_from("/").unwrap();
166    /// assert!(!reference.has_fragment());
167    /// ```
168    pub fn has_fragment(&self) -> bool {
169        self.uri_reference.has_fragment()
170    }
171
172    /// Returns whether the relative reference has a password component.
173    ///
174    /// # Examples
175    ///
176    /// ```
177    /// use std::convert::TryFrom;
178    ///
179    /// use uriparse::RelativeReference;
180    ///
181    /// let reference = RelativeReference::try_from("//user:pass@127.0.0.1").unwrap();
182    /// assert!(reference.has_password());
183    ///
184    /// let reference = RelativeReference::try_from("//user@127.0.0.1").unwrap();
185    /// assert!(!reference.has_password());
186    /// ```
187    pub fn has_password(&self) -> bool {
188        self.uri_reference.has_password()
189    }
190
191    /// Returns whether the relative reference has a port.
192    ///
193    /// # Examples
194    ///
195    /// ```
196    /// use std::convert::TryFrom;
197    ///
198    /// use uriparse::RelativeReference;
199    ///
200    /// let reference = RelativeReference::try_from("//127.0.0.1:8080").unwrap();
201    /// assert!(reference.has_port());
202    ///
203    /// let reference = RelativeReference::try_from("//127.0.0.1").unwrap();
204    /// assert!(!reference.has_port());
205    /// ```
206    pub fn has_port(&self) -> bool {
207        self.uri_reference.has_port()
208    }
209
210    /// Returns whether the relative reference has a query component.
211    ///
212    /// # Examples
213    ///
214    /// ```
215    /// use std::convert::TryFrom;
216    ///
217    /// use uriparse::RelativeReference;
218    ///
219    /// let reference = RelativeReference::try_from("/?my=query").unwrap();
220    /// assert!(reference.has_query());
221    ///
222    /// let reference = RelativeReference::try_from("/my/path").unwrap();
223    /// assert!(!reference.has_query());
224    /// ```
225    pub fn has_query(&self) -> bool {
226        self.uri_reference.has_query()
227    }
228
229    /// Returns whether the relative reference has a username component.
230    ///
231    /// # Examples
232    ///
233    /// ```
234    /// use std::convert::TryFrom;
235    ///
236    /// use uriparse::RelativeReference;
237    ///
238    /// let reference = RelativeReference::try_from("//username@example.com").unwrap();
239    /// assert!(reference.has_username());
240    ///
241    /// let reference = RelativeReference::try_from("").unwrap();
242    /// assert!(!reference.has_username());
243    /// ```
244    pub fn has_username(&self) -> bool {
245        self.uri_reference.has_username()
246    }
247
248    /// Returns the host, if present, of the relative reference.
249    ///
250    /// # Examples
251    ///
252    /// ```
253    /// use std::convert::TryFrom;
254    ///
255    /// use uriparse::RelativeReference;
256    ///
257    /// let reference = RelativeReference::try_from("//username@example.com").unwrap();
258    /// assert_eq!(reference.host().unwrap().to_string(), "example.com");
259    /// ```
260    pub fn host(&self) -> Option<&Host<'uri>> {
261        self.uri_reference.host()
262    }
263
264    /// Consumes the relative reference and converts it into a builder with the same values.
265    ///
266    /// # Examples
267    ///
268    /// ```
269    /// use std::convert::TryFrom;
270    ///
271    /// use uriparse::{Fragment, Query, RelativeReference};
272    ///
273    /// let reference = RelativeReference::try_from("//example.com/path?query#fragment").unwrap();
274    /// let mut builder = reference.into_builder();
275    /// builder.query(None::<Query>).fragment(None::<Fragment>);
276    /// let reference = builder.build().unwrap();
277    /// assert_eq!(reference.to_string(), "//example.com/path");
278    /// ```
279    pub fn into_builder(self) -> RelativeReferenceBuilder<'uri> {
280        let (_, authority, path, query, fragment) = self.uri_reference.into_parts();
281        let mut builder = RelativeReferenceBuilder::new();
282
283        builder
284            .authority(authority)
285            .path(path)
286            .query(query)
287            .fragment(fragment);
288        builder
289    }
290
291    /// Converts the [`RelativeReference`] into an owned copy.
292    ///
293    /// If you construct the relative reference from a source with a non-static lifetime, you may
294    /// run into lifetime problems due to the way the struct is designed. Calling this function will
295    /// ensure that the returned value has a static lifetime.
296    ///
297    /// This is different from just cloning. Cloning the relative reference will just copy the
298    /// references, and thus the lifetime will remain the same.
299    pub fn into_owned(self) -> RelativeReference<'static> {
300        RelativeReference {
301            uri_reference: self.uri_reference.into_owned(),
302        }
303    }
304
305    /// Consumes the [`RelativeReference`] and returns its parts: authority, path, query, and
306    /// fragment.
307    ///
308    /// # Examples
309    ///
310    /// ```
311    /// use std::convert::TryFrom;
312    ///
313    /// use uriparse::RelativeReference;
314    ///
315    /// let reference = RelativeReference::try_from(
316    ///     "/my/path?my=query#fragment",
317    /// ).unwrap();
318    /// let (authority, path, query, fragment) = reference.into_parts();
319    ///
320    /// assert_eq!(authority, None);
321    /// assert_eq!(path, "/my/path");
322    /// assert_eq!(query.unwrap(), "my=query");
323    /// assert_eq!(fragment.unwrap(), "fragment");
324    /// ```
325    pub fn into_parts(
326        self,
327    ) -> (
328        Option<Authority<'uri>>,
329        Path<'uri>,
330        Option<Query<'uri>>,
331        Option<Fragment<'uri>>,
332    ) {
333        let (_, authority, path, query, fragment) = self.uri_reference.into_parts();
334        (authority, path, query, fragment)
335    }
336
337    /// Returns whether the relative reference is an absolute path reference.
338    ///
339    /// A URI reference is an absolute path reference if it is a relative reference that begins with
340    /// a single `'/'`.
341    ///
342    /// # Examples
343    ///
344    /// ```
345    /// use std::convert::TryFrom;
346    ///
347    /// use uriparse::RelativeReference;
348    ///
349    /// let reference = RelativeReference::try_from("/my/path").unwrap();
350    /// assert!(reference.is_absolute_path_reference());
351    /// ```
352    pub fn is_absolute_path_reference(&self) -> bool {
353        self.uri_reference.is_absolute_path_reference()
354    }
355
356    /// Returns whether the relative reference is a network path reference.
357    ///
358    /// A relative reference is a network path reference if it is a relative reference that begins
359    /// with two `'/'`.
360    ///
361    /// # Examples
362    ///
363    /// ```
364    /// use std::convert::TryFrom;
365    ///
366    /// use uriparse::RelativeReference;
367    ///
368    /// let reference = RelativeReference::try_from("//example.com").unwrap();
369    /// assert!(reference.is_network_path_reference());
370    /// ```
371    pub fn is_network_path_reference(&self) -> bool {
372        self.uri_reference.is_network_path_reference()
373    }
374
375    /// Returns whether the relative reference is normalized.
376    ///
377    /// A normalized relative reference will have all of its components normalized.
378    ///
379    /// # Examples
380    ///
381    /// ```
382    /// use std::convert::TryFrom;
383    ///
384    /// use uriparse::RelativeReference;
385    ///
386    /// let reference = RelativeReference::try_from("/?a=b").unwrap();
387    /// assert!(reference.is_normalized());
388    ///
389    /// let mut reference = RelativeReference::try_from("/././?a=b").unwrap();
390    /// assert!(!reference.is_normalized());
391    /// reference.normalize();
392    /// assert!(reference.is_normalized());
393    /// ```
394    pub fn is_normalized(&self) -> bool {
395        self.uri_reference.is_normalized()
396    }
397
398    /// Returns whether the relative reference is a relative path reference.
399    ///
400    /// A relative reference is a relative path reference if it is a relative reference that does
401    /// not begin with a `'/'`.
402    ///
403    /// # Examples
404    ///
405    /// ```
406    /// use std::convert::TryFrom;
407    ///
408    /// use uriparse::RelativeReference;
409    ///
410    /// let reference = RelativeReference::try_from("my/path").unwrap();
411    /// assert!(reference.is_relative_path_reference());
412    /// ```
413    pub fn is_relative_path_reference(&self) -> bool {
414        self.uri_reference.is_relative_path_reference()
415    }
416
417    /// Maps the authority using the given map function.
418    ///
419    /// This function will panic if, as a result of the authority change, the relative reference
420    /// becomes invalid.
421    ///
422    /// # Examples
423    ///
424    /// ```
425    /// use std::convert::TryFrom;
426    ///
427    /// use uriparse::{Authority, RelativeReference};
428    ///
429    /// let mut reference = RelativeReference::try_from("").unwrap();
430    /// reference.map_authority(|_| Some(Authority::try_from("127.0.0.1").unwrap()));
431    /// assert_eq!(reference.to_string(), "//127.0.0.1/");
432    /// ```
433    pub fn map_authority<TMapper>(&mut self, mapper: TMapper) -> Option<&Authority<'uri>>
434    where
435        TMapper: FnOnce(Option<Authority<'uri>>) -> Option<Authority<'uri>>,
436    {
437        self.uri_reference.map_authority(mapper)
438    }
439
440    /// Maps the fragment using the given map function.
441    ///
442    /// # Examples
443    ///
444    /// ```
445    /// use std::convert::TryFrom;
446    ///
447    /// use uriparse::{Fragment, RelativeReference};
448    ///
449    /// let mut reference = RelativeReference::try_from("/").unwrap();
450    /// reference.map_fragment(|_| Some(Fragment::try_from("fragment").unwrap()));
451    /// assert_eq!(reference.to_string(), "/#fragment");
452    /// ```
453    pub fn map_fragment<TMapper>(&mut self, mapper: TMapper) -> Option<&Fragment<'uri>>
454    where
455        TMapper: FnOnce(Option<Fragment<'uri>>) -> Option<Fragment<'uri>>,
456    {
457        self.uri_reference.map_fragment(mapper)
458    }
459
460    /// Maps the path using the given map function.
461    ///
462    /// This function will panic if, as a result of the path change, the relative reference becomes
463    /// invalid.
464    ///
465    /// # Examples
466    ///
467    /// ```
468    /// use std::convert::TryFrom;
469    ///
470    /// use uriparse::{Authority, URIReference};
471    ///
472    /// let mut reference = URIReference::try_from("").unwrap();
473    /// reference.map_path(|mut path| {
474    ///     path.push("test").unwrap();
475    ///     path.push("path").unwrap();
476    ///     path
477    /// });
478    /// assert_eq!(reference.to_string(), "test/path");
479    /// ```
480    pub fn map_path<TMapper>(&mut self, mapper: TMapper) -> &Path<'uri>
481    where
482        TMapper: FnOnce(Path<'uri>) -> Path<'uri>,
483    {
484        self.uri_reference.map_path(mapper)
485    }
486
487    /// Maps the query using the given map function.
488    ///
489    /// # Examples
490    ///
491    /// ```
492    /// use std::convert::TryFrom;
493    ///
494    /// use uriparse::{Query, RelativeReference};
495    ///
496    /// let mut reference = RelativeReference::try_from("/path").unwrap();
497    /// reference.map_query(|_| Some(Query::try_from("query").unwrap()));
498    /// assert_eq!(reference.to_string(), "/path?query");
499    /// ```
500    pub fn map_query<TMapper>(&mut self, mapper: TMapper) -> Option<&Query<'uri>>
501    where
502        TMapper: FnOnce(Option<Query<'uri>>) -> Option<Query<'uri>>,
503    {
504        self.uri_reference.map_query(mapper)
505    }
506
507    /// Normalizes the relative reference.
508    ///
509    /// A normalized relative reference will have all of its components normalized.
510    ///
511    /// # Examples
512    ///
513    /// ```
514    /// use std::convert::TryFrom;
515    ///
516    /// use uriparse::RelativeReference;
517    ///
518    /// let mut reference = RelativeReference::try_from("/?a=b").unwrap();
519    /// reference.normalize();
520    /// assert_eq!(reference.to_string(), "/?a=b");
521    ///
522    /// let mut reference = RelativeReference::try_from("/././?a=b").unwrap();
523    /// assert_eq!(reference.to_string(), "/././?a=b");
524    /// reference.normalize();
525    /// assert_eq!(reference.to_string(), "/?a=b");
526    /// ```
527    pub fn normalize(&mut self) {
528        self.uri_reference.normalize();
529    }
530
531    /// Returns the path of the relative reference.
532    ///
533    /// # Examples
534    ///
535    /// ```
536    /// use std::convert::TryFrom;
537    ///
538    /// use uriparse::RelativeReference;
539    ///
540    /// let reference = RelativeReference::try_from("/my/path").unwrap();
541    /// assert_eq!(reference.path(), "/my/path");
542    /// ```
543    pub fn path(&self) -> &Path<'uri> {
544        self.uri_reference.path()
545    }
546
547    /// Returns the password, if present, of the relative reference.
548    ///
549    /// Usage of a password in URI and URI references is deprecated.
550    ///
551    /// # Examples
552    ///
553    /// ```
554    /// use std::convert::TryFrom;
555    ///
556    /// use uriparse::RelativeReference;
557    ///
558    /// let reference = RelativeReference::try_from("//user:pass@example.com").unwrap();
559    /// assert_eq!(reference.password().unwrap(), "pass");
560    /// ```
561    pub fn password(&self) -> Option<&Password<'uri>> {
562        self.uri_reference.password()
563    }
564
565    /// Returns the port, if present, of the relative reference.
566    ///
567    /// # Examples
568    ///
569    /// ```
570    /// use std::convert::TryFrom;
571    ///
572    /// use uriparse::RelativeReference;
573    ///
574    /// let reference = RelativeReference::try_from("//example.com:8080/").unwrap();
575    /// assert_eq!(reference.port().unwrap(), 8080);
576    /// ```
577    pub fn port(&self) -> Option<u16> {
578        self.uri_reference.port()
579    }
580
581    /// Returns the query, if present, of the relative reference.
582    ///
583    /// # Examples
584    ///
585    /// ```
586    /// use std::convert::TryFrom;
587    ///
588    /// use uriparse::RelativeReference;
589    ///
590    /// let reference = RelativeReference::try_from("?my=query").unwrap();
591    /// assert_eq!(reference.query().unwrap(), "my=query");
592    /// ```
593    pub fn query(&self) -> Option<&Query<'uri>> {
594        self.uri_reference.query()
595    }
596
597    /// Sets the authority of the relative reference.
598    ///
599    /// An error will be returned if the conversion to an [`Authority`] fails.
600    ///
601    /// The existing path will be set to absolute (i.e. starts with a `'/'`).
602    ///
603    /// # Examples
604    ///
605    /// ```
606    /// use std::convert::TryFrom;
607    ///
608    /// use uriparse::RelativeReference;
609    ///
610    /// let mut reference = RelativeReference::try_from("//example.com").unwrap();
611    /// reference.set_authority(Some("user@example.com:80"));
612    /// assert_eq!(reference.to_string(), "//user@example.com:80/");
613    /// ```
614    pub fn set_authority<TAuthority, TAuthorityError>(
615        &mut self,
616        authority: Option<TAuthority>,
617    ) -> Result<Option<&Authority<'uri>>, RelativeReferenceError>
618    where
619        Authority<'uri>: TryFrom<TAuthority, Error = TAuthorityError>,
620        URIReferenceError: From<TAuthorityError>,
621    {
622        self.uri_reference
623            .set_authority(authority)
624            .map_err(|error| RelativeReferenceError::try_from(error).unwrap())
625    }
626
627    /// Sets the fragment of the relative reference.
628    ///
629    /// An error will be returned if the conversion to a [`Fragment`] fails.
630    ///
631    /// # Examples
632    ///
633    /// ```
634    /// use std::convert::TryFrom;
635    ///
636    /// use uriparse::RelativeReference;
637    ///
638    /// let mut reference = RelativeReference::try_from("/my/path").unwrap();
639    /// reference.set_fragment(Some("fragment"));
640    /// assert_eq!(reference.to_string(), "/my/path#fragment");
641    /// ```
642    pub fn set_fragment<TFragment, TFragmentError>(
643        &mut self,
644        fragment: Option<TFragment>,
645    ) -> Result<Option<&Fragment<'uri>>, RelativeReferenceError>
646    where
647        Fragment<'uri>: TryFrom<TFragment, Error = TFragmentError>,
648        URIReferenceError: From<TFragmentError>,
649    {
650        self.uri_reference
651            .set_fragment(fragment)
652            .map_err(|error| RelativeReferenceError::try_from(error).unwrap())
653    }
654
655    /// Sets the path of the relative reference.
656    ///
657    /// An error will be returned in one of two cases:
658    ///  - The conversion to [`Path`] failed.
659    ///  - The path was set to a value that resulted in an invalid URI reference.
660    ///
661    /// Regardless of whether the given path was set as absolute or relative, if the relative
662    /// reference currently has an authority, the path will be forced to be absolute.
663    ///
664    /// # Examples
665    ///
666    /// ```
667    /// use std::convert::TryFrom;
668    ///
669    /// use uriparse::RelativeReference;
670    ///
671    /// let mut reference = RelativeReference::try_from("").unwrap();
672    /// reference.set_path("my/path");
673    /// assert_eq!(reference.to_string(), "my/path");
674    /// ```
675    pub fn set_path<TPath, TPathError>(
676        &mut self,
677        path: TPath,
678    ) -> Result<&Path<'uri>, RelativeReferenceError>
679    where
680        Path<'uri>: TryFrom<TPath, Error = TPathError>,
681        URIReferenceError: From<TPathError>,
682    {
683        self.uri_reference
684            .set_path(path)
685            .map_err(|error| RelativeReferenceError::try_from(error).unwrap())
686    }
687
688    /// Sets the query of the relative reference.
689    ///
690    /// An error will be returned if the conversion to a [`Query`] fails.
691    ///
692    /// # Examples
693    ///
694    /// ```
695    /// use std::convert::TryFrom;
696    ///
697    /// use uriparse::RelativeReference;
698    ///
699    /// let mut reference = RelativeReference::try_from("").unwrap();
700    /// reference.set_query(Some("myquery"));
701    /// assert_eq!(reference.to_string(), "?myquery");
702    /// ```
703    pub fn set_query<TQuery, TQueryError>(
704        &mut self,
705        query: Option<TQuery>,
706    ) -> Result<Option<&Query<'uri>>, RelativeReferenceError>
707    where
708        Query<'uri>: TryFrom<TQuery, Error = TQueryError>,
709        URIReferenceError: From<TQueryError>,
710    {
711        self.uri_reference
712            .set_query(query)
713            .map_err(|error| RelativeReferenceError::try_from(error).unwrap())
714    }
715
716    /// Returns a new relative reference which is identical but has a lifetime tied to this relative
717    /// reference.
718    ///
719    /// This function will perform a memory allocation.
720    pub fn to_borrowed(&self) -> RelativeReference {
721        RelativeReference {
722            uri_reference: self.uri_reference.to_borrowed(),
723        }
724    }
725
726    /// Returns the username, if present, of the relative reference.
727    ///
728    /// # Examples
729    ///
730    /// ```
731    /// use std::convert::TryFrom;
732    ///
733    /// use uriparse::RelativeReference;
734    ///
735    /// let reference = RelativeReference::try_from("//username@example.com").unwrap();
736    /// assert_eq!(reference.username().unwrap(), "username");
737    /// ```
738    pub fn username(&self) -> Option<&Username<'uri>> {
739        self.uri_reference.username()
740    }
741}
742
743impl Display for RelativeReference<'_> {
744    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
745        self.uri_reference.fmt(formatter)
746    }
747}
748
749impl<'uri> From<RelativeReference<'uri>> for String {
750    fn from(value: RelativeReference<'uri>) -> Self {
751        value.to_string()
752    }
753}
754
755impl<'uri> From<RelativeReference<'uri>> for URIReference<'uri> {
756    fn from(value: RelativeReference<'uri>) -> Self {
757        value.uri_reference
758    }
759}
760
761impl<'uri> TryFrom<&'uri [u8]> for RelativeReference<'uri> {
762    type Error = RelativeReferenceError;
763
764    fn try_from(value: &'uri [u8]) -> Result<Self, Self::Error> {
765        let uri_reference = URIReference::try_from(value)
766            .map_err(|error| RelativeReferenceError::try_from(error).unwrap())?;
767
768        if uri_reference.is_uri() {
769            Err(RelativeReferenceError::NotRelativeReference)
770        } else {
771            Ok(RelativeReference { uri_reference })
772        }
773    }
774}
775
776impl<'uri> TryFrom<&'uri str> for RelativeReference<'uri> {
777    type Error = RelativeReferenceError;
778
779    fn try_from(value: &'uri str) -> Result<Self, Self::Error> {
780        RelativeReference::try_from(value.as_bytes())
781    }
782}
783
784impl<'uri> TryFrom<URIReference<'uri>> for RelativeReference<'uri> {
785    type Error = RelativeReferenceError;
786
787    fn try_from(value: URIReference<'uri>) -> Result<Self, Self::Error> {
788        if value.is_relative_reference() {
789            Ok(RelativeReference {
790                uri_reference: value,
791            })
792        } else {
793            Err(RelativeReferenceError::NotRelativeReference)
794        }
795    }
796}
797
798/// A builder type for [`RelativeReference]`.
799///
800/// You must use the [`RelativeReferenceBuilder::path`] function before building as relative
801/// references always have a path. Everything else is optional.
802#[derive(Clone, Debug, Default, Eq, PartialEq)]
803pub struct RelativeReferenceBuilder<'uri> {
804    /// All relative references are also URI references, so we just maintain a
805    /// [`URIReferenceBuilder`] underneath.
806    uri_reference_builder: URIReferenceBuilder<'uri>,
807}
808
809impl<'uri> RelativeReferenceBuilder<'uri> {
810    /// Sets the authority part of the relative reference.
811    ///
812    /// It is optional to specify a authority.
813    ///
814    /// # Examples
815    ///
816    /// ```
817    /// use std::convert::TryFrom;
818    ///
819    /// use uriparse::{Authority, Path, RelativeReferenceBuilder};
820    ///
821    /// let mut builder = RelativeReferenceBuilder::new();
822    /// builder
823    ///     .authority(Some(Authority::try_from("example.com").unwrap()))
824    ///     .path(Path::try_from("/my/path").unwrap());
825    /// let reference = builder.build().unwrap();
826    /// assert_eq!(reference.to_string(), "//example.com/my/path");
827    /// ```
828    pub fn authority(&mut self, authority: Option<Authority<'uri>>) -> &mut Self {
829        self.uri_reference_builder.authority(authority);
830        self
831    }
832
833    /// Consumes the builder and tries to build a [`RelativeReference`].
834    ///
835    /// This function will error in one of two situations:
836    ///  - A path was not specified in the builder.
837    ///  - While all individual components were valid, their combination as a relative reference was
838    ///    invalid.
839    ///
840    /// # Examples
841    ///
842    /// First error type (path not specified):
843    ///
844    /// ```
845    /// use uriparse::RelativeReferenceBuilder;
846    ///
847    /// let result = RelativeReferenceBuilder::new().build();
848    /// assert!(result.is_err());
849    /// ```
850    ///
851    /// Second error type (first segment in schemeless path cannot contain a `':'`):
852    ///
853    /// ```
854    /// use std::convert::TryFrom;
855    ///
856    /// use uriparse::{Path, RelativeReferenceBuilder};
857    ///
858    /// let result = RelativeReferenceBuilder::new()
859    ///     .with_path(Path::try_from("my:/path").unwrap())
860    ///     .build();
861    /// assert!(result.is_err());
862    /// ```
863    pub fn build(self) -> Result<RelativeReference<'uri>, RelativeReferenceError> {
864        Ok(RelativeReference {
865            uri_reference: self
866                .uri_reference_builder
867                .build()
868                .map_err(|error| RelativeReferenceError::try_from(error).unwrap())?,
869        })
870    }
871
872    /// Sets the fragment part of the relative reference.
873    ///
874    /// It is optional to specify a fragment.
875    ///
876    /// # Examples
877    ///
878    /// ```
879    /// use std::convert::TryFrom;
880    ///
881    /// use uriparse::{Fragment, Path, RelativeReferenceBuilder};
882    ///
883    /// let mut builder = RelativeReferenceBuilder::new();
884    /// builder
885    ///     .path(Path::try_from("/my/path").unwrap())
886    ///     .fragment(Some(Fragment::try_from("fragment").unwrap()));
887    /// let reference = builder.build().unwrap();
888    /// assert_eq!(reference.to_string(), "/my/path#fragment");
889    /// ```
890    pub fn fragment(&mut self, fragment: Option<Fragment<'uri>>) -> &mut Self {
891        self.uri_reference_builder.fragment(fragment);
892        self
893    }
894
895    /// Constructs a new builder with nothing set.
896    pub fn new() -> Self {
897        RelativeReferenceBuilder::default()
898    }
899
900    /// Sets the path part of the relative reference.
901    ///
902    /// It is required to specify a path. Not doing so will result in an error during the
903    /// [`RelativeReferenceBuilder::build`] function.
904    ///
905    /// # Examples
906    ///
907    /// ```
908    /// use std::convert::TryFrom;
909    ///
910    /// use uriparse::{Path, RelativeReferenceBuilder};
911    ///
912    /// let mut builder = RelativeReferenceBuilder::new();
913    /// builder
914    ///     .path(Path::try_from("/my/path").unwrap());
915    /// let reference = builder.build().unwrap();
916    /// assert_eq!(reference.to_string(), "/my/path");
917    /// ```
918    pub fn path(&mut self, path: Path<'uri>) -> &mut Self {
919        self.uri_reference_builder.path(path);
920        self
921    }
922
923    /// Sets the query part of the relative reference.
924    ///
925    /// It is optional to specify a query.
926    ///
927    /// # Examples
928    ///
929    /// ```
930    /// use std::convert::TryFrom;
931    ///
932    /// use uriparse::{Path, Query, RelativeReferenceBuilder};
933    ///
934    /// let mut builder = RelativeReferenceBuilder::new();
935    /// builder
936    ///     .path(Path::try_from("/my/path").unwrap())
937    ///     .query(Some(Query::try_from("query").unwrap()));
938    /// let reference = builder.build().unwrap();
939    /// assert_eq!(reference.to_string(), "/my/path?query");
940    /// ```
941    pub fn query(&mut self, query: Option<Query<'uri>>) -> &mut Self {
942        self.uri_reference_builder.query(query);
943        self
944    }
945
946    /// Sets the authority part of the relative reference.
947    ///
948    /// If the given authority is not a valid authority (i.e. the conversion fails), an error is
949    /// stored internally and checked during the [`RelativeReferenceBuilder::build`] function. The
950    /// error state will be rewritten for any following calls to this function.
951    ///
952    /// It is optional to specify an authority.
953    ///
954    /// # Examples
955    ///
956    /// ```
957    /// use uriparse::RelativeReferenceBuilder;
958    ///
959    /// let mut builder = RelativeReferenceBuilder::new();
960    /// builder
961    ///     .try_authority(Some("example.com"))
962    ///     .unwrap()    
963    ///     .try_path("/my/path")
964    ///     .unwrap();
965    /// let reference = builder.build().unwrap();
966    /// assert_eq!(reference.to_string(), "//example.com/my/path");
967    /// ```
968    pub fn try_authority<TAuthority, TAuthorityError>(
969        &mut self,
970        authority: Option<TAuthority>,
971    ) -> Result<&mut Self, TAuthorityError>
972    where
973        Authority<'uri>: TryFrom<TAuthority, Error = TAuthorityError>,
974        AuthorityError: From<TAuthorityError>,
975    {
976        self.uri_reference_builder.try_authority(authority)?;
977        Ok(self)
978    }
979
980    /// Sets the fragment part of the relative reference.
981    ///
982    /// If the given fragment is not a valid fragment (i.e. the conversion fails), an error is
983    /// stored internally and checked during the [`RelativeReferenceBuilder::build`] function. The
984    /// error state will be rewritten for any following calls to this function.
985    ///
986    /// It is optional to specify a fragment.
987    ///
988    /// # Examples
989    ///
990    /// ```
991    /// use uriparse::RelativeReferenceBuilder;
992    ///
993    /// let mut builder = RelativeReferenceBuilder::new();
994    /// builder
995    ///     .try_path("/my/path")
996    ///     .unwrap()
997    ///     .try_fragment(Some("fragment"))
998    ///     .unwrap();
999    /// let reference = builder.build().unwrap();
1000    /// assert_eq!(reference.to_string(), "/my/path#fragment");
1001    /// ```
1002    pub fn try_fragment<TFragment, TFragmentError>(
1003        &mut self,
1004        fragment: Option<TFragment>,
1005    ) -> Result<&mut Self, FragmentError>
1006    where
1007        Fragment<'uri>: TryFrom<TFragment, Error = TFragmentError>,
1008        FragmentError: From<TFragmentError>,
1009    {
1010        self.uri_reference_builder.try_fragment(fragment)?;
1011        Ok(self)
1012    }
1013
1014    /// Sets the path part of the relative reference.
1015    ///
1016    /// If the given path is not a valid path (i.e. the conversion fails), an error is stored
1017    /// internally and checked during the [`RelativeReferenceBuilder::build`] function. The error
1018    /// state will be rewritten for any following calls to this function.
1019    ///
1020    /// It is required to specify an path. Not doing so will result in an error during the
1021    /// [`RelativeReferenceBuilder::build`] function.
1022    ///
1023    /// # Examples
1024    ///
1025    /// ```
1026    /// use uriparse::RelativeReferenceBuilder;
1027    ///
1028    /// let mut builder = RelativeReferenceBuilder::new();
1029    /// builder
1030    ///     .try_path("/my/path")
1031    ///     .unwrap();
1032    /// let reference = builder.build().unwrap();
1033    /// assert_eq!(reference.to_string(), "/my/path");
1034    /// ```
1035    pub fn try_path<TPath, TPathError>(&mut self, path: TPath) -> Result<&mut Self, PathError>
1036    where
1037        Path<'uri>: TryFrom<TPath, Error = TPathError>,
1038        PathError: From<TPathError>,
1039    {
1040        self.uri_reference_builder.try_path(path)?;
1041        Ok(self)
1042    }
1043
1044    /// Sets the query part of the relative reference.
1045    ///
1046    /// If the given query is not a valid query (i.e. the conversion fails), an error is stored
1047    /// internally and checked during the [`RelativeReferenceBuilder::build`] function. The error
1048    /// state will be rewritten for any following calls to this function.
1049    ///
1050    /// It is optional to specify a query.
1051    ///
1052    /// # Examples
1053    ///
1054    /// ```
1055    /// use uriparse::RelativeReferenceBuilder;
1056    ///
1057    /// let mut builder = RelativeReferenceBuilder::new();
1058    /// builder
1059    ///     .try_path("/my/path")
1060    ///     .unwrap()
1061    ///     .try_query(Some("query"))
1062    ///     .unwrap();
1063    /// let reference = builder.build().unwrap();
1064    /// assert_eq!(reference.to_string(), "/my/path?query");
1065    /// ```
1066    pub fn try_query<TQuery, TQueryError>(
1067        &mut self,
1068        query: Option<TQuery>,
1069    ) -> Result<&mut Self, QueryError>
1070    where
1071        Query<'uri>: TryFrom<TQuery, Error = TQueryError>,
1072        QueryError: From<TQueryError>,
1073    {
1074        self.uri_reference_builder.try_query(query)?;
1075        Ok(self)
1076    }
1077
1078    /// Consumes the builder and sets the authority part of the relative reference.
1079    ///
1080    /// It is optional to specify an authority.
1081    ///
1082    /// # Examples
1083    ///
1084    /// ```
1085    /// use std::convert::TryFrom;
1086    ///
1087    /// use uriparse::{Authority, Path, RelativeReferenceBuilder};
1088    ///
1089    /// let reference = RelativeReferenceBuilder::new()
1090    ///     .with_authority(Some(Authority::try_from("example.com").unwrap()))
1091    ///     .with_path(Path::try_from("/").unwrap())
1092    ///     .build()
1093    ///     .unwrap();
1094    /// assert_eq!(reference.to_string(), "//example.com/")
1095    /// ```
1096    pub fn with_authority(mut self, authority: Option<Authority<'uri>>) -> Self {
1097        self.authority(authority);
1098        self
1099    }
1100
1101    /// Consumes the builder and sets the fragment part of the relative reference.
1102    ///
1103    /// It is optional to specify a fragment.
1104    ///
1105    /// # Examples
1106    ///
1107    /// ```
1108    /// use std::convert::TryFrom;
1109    ///
1110    /// use uriparse::{Fragment, Path, RelativeReferenceBuilder};
1111    ///
1112    /// let reference = RelativeReferenceBuilder::new()
1113    ///     .with_path(Path::try_from("/").unwrap())
1114    ///     .with_fragment(Some(Fragment::try_from("fragment").unwrap()))
1115    ///     .build()
1116    ///     .unwrap();
1117    /// assert_eq!(reference.to_string(), "/#fragment")
1118    /// ```
1119    pub fn with_fragment(mut self, fragment: Option<Fragment<'uri>>) -> Self {
1120        self.fragment(fragment);
1121        self
1122    }
1123
1124    /// Consumes the builder and sets the path part of the relative reference.
1125    ///
1126    /// It is required to specify a path. Not doing so will result in an error during the
1127    /// [`RelativeReferenceBuilder::build`] function.
1128    ///
1129    /// # Examples
1130    ///
1131    /// ```
1132    /// use std::convert::TryFrom;
1133    ///
1134    /// use uriparse::{Path, RelativeReferenceBuilder};
1135    ///
1136    /// let reference = RelativeReferenceBuilder::new()
1137    ///     .with_path(Path::try_from("/").unwrap())
1138    ///     .build()
1139    ///     .unwrap();
1140    /// assert_eq!(reference.to_string(), "/")
1141    /// ```
1142    pub fn with_path(mut self, path: Path<'uri>) -> Self {
1143        self.path(path);
1144        self
1145    }
1146
1147    /// Consumes the builder and sets the query part of the relative reference.
1148    ///
1149    /// It is optional to specify a query.
1150    ///
1151    /// # Examples
1152    ///
1153    /// ```
1154    /// use std::convert::TryFrom;
1155    ///
1156    /// use uriparse::{Path, Query, RelativeReferenceBuilder};
1157    ///
1158    /// let reference = RelativeReferenceBuilder::new()
1159    ///     .with_path(Path::try_from("/").unwrap())
1160    ///     .with_query(Some(Query::try_from("query").unwrap()))
1161    ///     .build()
1162    ///     .unwrap();
1163    /// assert_eq!(reference.to_string(), "/?query")
1164    /// ```
1165    pub fn with_query(mut self, query: Option<Query<'uri>>) -> Self {
1166        self.query(query);
1167        self
1168    }
1169}
1170
1171/// An error representing an invalid relative reference.
1172#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1173#[non_exhaustive]
1174pub enum RelativeReferenceError {
1175    /// Represents the case where there is no authority, but the first path segment starts with
1176    /// `"//"`. This is not allowed because it would be interpreted as an authority component.
1177    ///
1178    /// This can only occur when using creation functions that act on individual parts (e.g.
1179    /// [`RelativeReference::from_parts`]).
1180    AbsolutePathStartsWithTwoSlashes,
1181
1182    /// The authority component of the relative reference was invalid.
1183    Authority(AuthorityError),
1184
1185    /// The fragment component of the relative reference was invalid.
1186    Fragment(FragmentError),
1187
1188    /// The path component of the relative reference was invalid.
1189    Path(PathError),
1190
1191    /// The query component of the relative reference was invalid.
1192    Query(QueryError),
1193
1194    /// This error occurs when you do not specify a path component on the builder.
1195    ///
1196    /// This can only occur when using [`RelativeReferenceBuilder`].
1197    MissingPath,
1198
1199    /// When parsing from some byte string source, if the source ends up being a URI, then it is
1200    /// obviously not a relative reference.
1201    ///
1202    /// This can only occur when parsing from a byte string source.
1203    NotRelativeReference,
1204
1205    /// Represents the case where the first path segment contains a `':'`. This is not allowed
1206    /// because it would be interpreted as a scheme component.
1207    ///
1208    /// This can only occur when using creation functions that act on individual parts (e.g.
1209    /// [`RelativeReference::from_parts`]).
1210    SchemelessPathStartsWithColonSegment,
1211}
1212
1213impl Display for RelativeReferenceError {
1214    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1215        use self::RelativeReferenceError::*;
1216
1217        match self {
1218            AbsolutePathStartsWithTwoSlashes => {
1219                write!(formatter, "absolute path starts with two slashes")
1220            }
1221            Authority(error) => error.fmt(formatter),
1222            Fragment(error) => error.fmt(formatter),
1223            NotRelativeReference => write!(formatter, "not relative reference"),
1224            Path(error) => error.fmt(formatter),
1225            Query(error) => error.fmt(formatter),
1226            MissingPath => write!(formatter, "missing path"),
1227            SchemelessPathStartsWithColonSegment => write!(
1228                formatter,
1229                "relative reference schemeless path starts with colon segment"
1230            ),
1231        }
1232    }
1233}
1234
1235impl Error for RelativeReferenceError {}
1236
1237impl From<Infallible> for RelativeReferenceError {
1238    fn from(_: Infallible) -> Self {
1239        RelativeReferenceError::MissingPath
1240    }
1241}
1242
1243impl From<AuthorityError> for RelativeReferenceError {
1244    fn from(value: AuthorityError) -> Self {
1245        RelativeReferenceError::Authority(value)
1246    }
1247}
1248
1249impl From<FragmentError> for RelativeReferenceError {
1250    fn from(value: FragmentError) -> Self {
1251        RelativeReferenceError::Fragment(value)
1252    }
1253}
1254
1255impl From<PathError> for RelativeReferenceError {
1256    fn from(value: PathError) -> Self {
1257        RelativeReferenceError::Path(value)
1258    }
1259}
1260
1261impl From<QueryError> for RelativeReferenceError {
1262    fn from(value: QueryError) -> Self {
1263        RelativeReferenceError::Query(value)
1264    }
1265}
1266
1267impl TryFrom<URIReferenceError> for RelativeReferenceError {
1268    type Error = ();
1269
1270    fn try_from(value: URIReferenceError) -> Result<Self, Self::Error> {
1271        use self::RelativeReferenceError::*;
1272
1273        match value {
1274            URIReferenceError::AbsolutePathStartsWithTwoSlashes => {
1275                Ok(AbsolutePathStartsWithTwoSlashes)
1276            }
1277            URIReferenceError::Authority(error) => Ok(Authority(error)),
1278            URIReferenceError::Fragment(error) => Ok(Fragment(error)),
1279            URIReferenceError::Path(error) => Ok(Path(error)),
1280            URIReferenceError::Query(error) => Ok(Query(error)),
1281            URIReferenceError::MissingPath => Ok(MissingPath),
1282            URIReferenceError::SchemelessPathStartsWithColonSegment => {
1283                Ok(SchemelessPathStartsWithColonSegment)
1284            }
1285            URIReferenceError::Scheme(_) => Err(()),
1286        }
1287    }
1288}