1 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 2 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 3 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 4 // option. This file may not be copied, modified, or distributed 5 // except according to those terms. 6 7 #![allow(clippy::module_name_repetitions)] 8 9 use std::fmt::{Debug, Formatter}; 10 use url::{ParseError, Url}; 11 12 pub trait RequestTarget: Debug { scheme(&self) -> &str13 fn scheme(&self) -> &str; authority(&self) -> &str14 fn authority(&self) -> &str; path(&self) -> &str15 fn path(&self) -> &str; 16 } 17 18 pub struct RefRequestTarget<'s, 'a, 'p> { 19 scheme: &'s str, 20 authority: &'a str, 21 path: &'p str, 22 } 23 24 impl RequestTarget for RefRequestTarget<'_, '_, '_> { scheme(&self) -> &str25 fn scheme(&self) -> &str { 26 self.scheme 27 } 28 authority(&self) -> &str29 fn authority(&self) -> &str { 30 self.authority 31 } 32 path(&self) -> &str33 fn path(&self) -> &str { 34 self.path 35 } 36 } 37 38 impl<'s, 'a, 'p> RefRequestTarget<'s, 'a, 'p> { 39 #[must_use] new(scheme: &'s str, authority: &'a str, path: &'p str) -> Self40 pub fn new(scheme: &'s str, authority: &'a str, path: &'p str) -> Self { 41 Self { 42 scheme, 43 authority, 44 path, 45 } 46 } 47 } 48 49 impl Debug for RefRequestTarget<'_, '_, '_> { fmt(&self, f: &mut Formatter) -> ::std::fmt::Result50 fn fmt(&self, f: &mut Formatter) -> ::std::fmt::Result { 51 write!(f, "{}://{}{}", self.scheme, self.authority, self.path) 52 } 53 } 54 55 /// `AsRequestTarget` is a trait that produces a `RequestTarget` that 56 /// refers to the identified object. 57 pub trait AsRequestTarget<'x> { 58 type Target: RequestTarget; 59 type Error; 60 /// Produce a `RequestTarget` that refers to `self`. 61 /// # Errors 62 /// This method can generate an error of type `Self::Error` 63 /// if the conversion is unsuccessful. as_request_target(&'x self) -> Result<Self::Target, Self::Error>64 fn as_request_target(&'x self) -> Result<Self::Target, Self::Error>; 65 } 66 67 impl<'x, S, A, P> AsRequestTarget<'x> for (S, A, P) 68 where 69 S: AsRef<str> + 'x, 70 A: AsRef<str> + 'x, 71 P: AsRef<str> + 'x, 72 { 73 type Target = RefRequestTarget<'x, 'x, 'x>; 74 type Error = (); as_request_target(&'x self) -> Result<Self::Target, Self::Error>75 fn as_request_target(&'x self) -> Result<Self::Target, Self::Error> { 76 Ok(RefRequestTarget::new( 77 self.0.as_ref(), 78 self.1.as_ref(), 79 self.2.as_ref(), 80 )) 81 } 82 } 83 84 impl<'x> AsRequestTarget<'x> for Url { 85 type Target = RefRequestTarget<'x, 'x, 'x>; 86 type Error = (); as_request_target(&'x self) -> Result<Self::Target, Self::Error>87 fn as_request_target(&'x self) -> Result<Self::Target, Self::Error> { 88 Ok(RefRequestTarget::new( 89 self.scheme(), 90 self.host_str().unwrap_or(""), 91 self.path(), 92 )) 93 } 94 } 95 96 pub struct UrlRequestTarget { 97 url: Url, 98 } 99 100 impl RequestTarget for UrlRequestTarget { scheme(&self) -> &str101 fn scheme(&self) -> &str { 102 self.url.scheme() 103 } 104 authority(&self) -> &str105 fn authority(&self) -> &str { 106 self.url.host_str().unwrap_or("") 107 } 108 path(&self) -> &str109 fn path(&self) -> &str { 110 self.url.path() 111 } 112 } 113 114 impl Debug for UrlRequestTarget { fmt(&self, f: &mut Formatter) -> ::std::fmt::Result115 fn fmt(&self, f: &mut Formatter) -> ::std::fmt::Result { 116 self.url.fmt(f) 117 } 118 } 119 120 impl<'x> AsRequestTarget<'x> for str { 121 type Target = UrlRequestTarget; 122 type Error = ParseError; as_request_target(&'x self) -> Result<Self::Target, Self::Error>123 fn as_request_target(&'x self) -> Result<Self::Target, Self::Error> { 124 let url = Url::parse(self)?; 125 Ok(UrlRequestTarget { url }) 126 } 127 } 128