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}