diff options
Diffstat (limited to 'src/uri.rs')
| -rw-r--r-- | src/uri.rs | 814 | 
1 files changed, 550 insertions, 264 deletions
@@ -1,15 +1,20 @@  use std::collections::HashSet; -use super::authority::Authority; -use super::codec::{decode_element, encode_element}; -use super::context::Context; -use super::error::Error; -use super::character_classes::{ -    ALPHA, -    SCHEME_NOT_FIRST, -    PCHAR_NOT_PCT_ENCODED, -    QUERY_OR_FRAGMENT_NOT_PCT_ENCODED, -    QUERY_NOT_PCT_ENCODED_WITHOUT_PLUS, +use super::{ +    authority::Authority, +    character_classes::{ +        ALPHA, +        PCHAR_NOT_PCT_ENCODED, +        QUERY_NOT_PCT_ENCODED_WITHOUT_PLUS, +        QUERY_OR_FRAGMENT_NOT_PCT_ENCODED, +        SCHEME_NOT_FIRST, +    }, +    codec::{ +        decode_element, +        encode_element, +    }, +    context::Context, +    error::Error,  };  /// This type is used to parse and generate URI strings to and from their @@ -55,7 +60,10 @@ use super::character_classes::{  ///  /// ```rust  /// # extern crate rhymuri; -/// use rhymuri::{Authority, Uri}; +/// use rhymuri::{ +///     Authority, +///     Uri, +/// };  ///  /// let mut uri = Uri::default();  /// assert!(uri.set_scheme(String::from("http")).is_ok()); @@ -96,7 +104,8 @@ impl Uri {      }      fn can_navigate_path_up_one_level<T>(path: T) -> bool -        where T: AsRef<[Vec<u8>]> +    where +        T: AsRef<[Vec<u8>]>,      {          let path = path.as_ref();          match path.first() { @@ -107,19 +116,18 @@ impl Uri {              // Otherwise, we can navigate up as long as there is at least one              // segment.              Some(_) => true, -            None => false +            None => false,          }      }      fn check_scheme<T>(scheme: T) -> Result<T, Error> -        where T: AsRef<str> +    where +        T: AsRef<str>,      {          match scheme.as_ref() {              "" => return Err(Error::EmptyScheme), -            scheme => scheme -                .chars() -                .enumerate() -                .try_fold((), |_, (i, c)| { +            scheme => { +                scheme.chars().enumerate().try_fold((), |_, (i, c)| {                      let valid_characters: &HashSet<char> = if i == 0 {                          &ALPHA                      } else { @@ -130,7 +138,8 @@ impl Uri {                      } else {                          Err(Error::IllegalCharacter(Context::Scheme))                      } -                })?, +                })? +            },          };          Ok(scheme)      } @@ -146,12 +155,13 @@ impl Uri {          query_or_fragment: T,          context: Context,      ) -> Result<Vec<u8>, Error> -        where T: AsRef<str> +    where +        T: AsRef<str>,      {          decode_element(              query_or_fragment,              &QUERY_OR_FRAGMENT_NOT_PCT_ENCODED, -            context +            context,          )      } @@ -166,13 +176,13 @@ impl Uri {      /// # Errors      ///      /// Since fragments may contain non-UTF8 byte sequences, this function may -    /// return [`Error::CannotExpressAsUtf8`](enum.Error.html#variant.CannotExpressAsUtf8). +    /// return [`Error::CannotExpressAsUtf8`](enum.Error.html#variant. +    /// CannotExpressAsUtf8).      #[must_use = "use the fragment return value silly programmer"]      pub fn fragment_to_string(&self) -> Result<Option<String>, Error> {          self.fragment()              .map(|fragment| { -                String::from_utf8(fragment.to_vec()) -                    .map_err(Into::into) +                String::from_utf8(fragment.to_vec()).map_err(Into::into)              })              .transpose()      } @@ -180,9 +190,7 @@ impl Uri {      /// Borrow the host portion of the Authority (if any) of the URI.      #[must_use = "why u no use host return value?"]      pub fn host(&self) -> Option<&[u8]> { -        self.authority -            .as_ref() -            .map(Authority::host) +        self.authority.as_ref().map(Authority::host)      }      /// Convert the host portion of the Authority (if any) into a string. @@ -191,19 +199,18 @@ impl Uri {      ///      /// Since host names may contain non-UTF8 byte sequences, this function may      /// return -    /// [`Error::CannotExpressAsUtf8`](enum.Error.html#variant.CannotExpressAsUtf8). +    /// [`Error::CannotExpressAsUtf8`](enum.Error.html#variant. +    /// CannotExpressAsUtf8).      #[must_use = "I made that host field into a string for you; don't you want it?"]      pub fn host_to_string(&self) -> Result<Option<String>, Error> {          self.host() -            .map(|host| { -                String::from_utf8(host.to_vec()) -                    .map_err(Into::into) -            }) +            .map(|host| String::from_utf8(host.to_vec()).map_err(Into::into))              .transpose()      }      fn is_path_absolute<T>(path: T) -> bool -        where T: AsRef<[Vec<u8>]> +    where +        T: AsRef<[Vec<u8>]>,      {          matches!(path.as_ref(), [segment, ..] if segment.is_empty())      } @@ -241,7 +248,8 @@ impl Uri {      }      fn normalize_path<T>(original_path: T) -> Vec<Vec<u8>> -        where T: AsRef<[Vec<u8>]> +    where +        T: AsRef<[Vec<u8>]>,      {          // Rebuild the path one segment          // at a time, removing and applying special @@ -257,8 +265,7 @@ impl Uri {              } else if segment == b".." {                  // Remove last path element                  // if we can navigate up a level. -                if -                    !normalized_path.is_empty() +                if !normalized_path.is_empty()                      && Self::can_navigate_path_up_one_level(&normalized_path)                  {                      normalized_path.pop(); @@ -286,7 +293,7 @@ impl Uri {              (true, Some(segment)) if !segment.is_empty() => {                  normalized_path.push(vec![]);              }, -            _ => () +            _ => (),          }          normalized_path      } @@ -300,46 +307,45 @@ impl Uri {      /// let you know what's up by returning a variant of the      /// [`Error`](enum.Error.html) type.      pub fn parse<T>(uri_string: T) -> Result<Self, Error> -        where T: AsRef<str> +    where +        T: AsRef<str>,      {          let (scheme, rest) = Self::parse_scheme(uri_string.as_ref())?; -        let path_end = rest -            .find(&['?', '#'][..]) -            .unwrap_or_else(|| rest.len()); +        let path_end = rest.find(&['?', '#'][..]).unwrap_or_else(|| rest.len());          let authority_and_path_string = &rest[0..path_end];          let query_and_or_fragment = &rest[path_end..]; -        let (authority, path) = Self::split_authority_from_path_and_parse_them(authority_and_path_string)?; -        let (fragment, possible_query) = Self::parse_fragment(query_and_or_fragment)?; +        let (authority, path) = Self::split_authority_from_path_and_parse_them( +            authority_and_path_string, +        )?; +        let (fragment, possible_query) = +            Self::parse_fragment(query_and_or_fragment)?;          let query = Self::parse_query(possible_query)?; -        Ok(Self{ +        Ok(Self {              scheme,              authority,              path,              query, -            fragment +            fragment,          })      } -    fn parse_fragment(query_and_or_fragment: &str) -> Result<(Option<Vec<u8>>, &str), Error> { +    fn parse_fragment( +        query_and_or_fragment: &str +    ) -> Result<(Option<Vec<u8>>, &str), Error> {          if let Some(fragment_delimiter) = query_and_or_fragment.find('#') {              let fragment = Self::decode_query_or_fragment( -                &query_and_or_fragment[fragment_delimiter+1..], -                Context::Fragment +                &query_and_or_fragment[fragment_delimiter + 1..], +                Context::Fragment,              )?; -            Ok(( -                Some(fragment), -                &query_and_or_fragment[0..fragment_delimiter] -            )) +            Ok((Some(fragment), &query_and_or_fragment[0..fragment_delimiter]))          } else { -            Ok(( -                None, -                query_and_or_fragment -            )) +            Ok((None, query_and_or_fragment))          }      }      fn parse_path<T>(path_string: T) -> Result<Vec<Vec<u8>>, Error> -        where T: AsRef<str> +    where +        T: AsRef<str>,      {          match path_string.as_ref() {              "/" => { @@ -355,23 +361,24 @@ impl Uri {                  Ok(vec![])              }, -            path_string => { -                path_string -                    .split('/') -                    .map(|segment| { -                        decode_element( -                            &segment, -                            &PCHAR_NOT_PCT_ENCODED, -                            Context::Path -                        ) -                    }) -                    .collect() -            } +            path_string => path_string +                .split('/') +                .map(|segment| { +                    decode_element( +                        &segment, +                        &PCHAR_NOT_PCT_ENCODED, +                        Context::Path, +                    ) +                }) +                .collect(),          }      } -    fn parse_query<T>(query_and_or_fragment: T) -> Result<Option<Vec<u8>>, Error> -        where T: AsRef<str> +    fn parse_query<T>( +        query_and_or_fragment: T +    ) -> Result<Option<Vec<u8>>, Error> +    where +        T: AsRef<str>,      {          let query_and_or_fragment = query_and_or_fragment.as_ref();          if query_and_or_fragment.is_empty() { @@ -379,7 +386,7 @@ impl Uri {          } else {              let query = Self::decode_query_or_fragment(                  &query_and_or_fragment[1..], -                Context::Query +                Context::Query,              )?;              Ok(Some(query))          } @@ -390,12 +397,14 @@ impl Uri {          // or path elements, because these may have the colon          // character as well, which we might misinterpret          // as the scheme delimiter. -        let authority_or_path_delimiter_start = uri_string.find('/') -            .unwrap_or_else(|| uri_string.len()); -        if let Some(scheme_end) = &uri_string[0..authority_or_path_delimiter_start].find(':') { -            let scheme = Self::check_scheme(&uri_string[0..*scheme_end])? -                .to_lowercase(); -            Ok((Some(scheme), &uri_string[*scheme_end+1..])) +        let authority_or_path_delimiter_start = +            uri_string.find('/').unwrap_or_else(|| uri_string.len()); +        if let Some(scheme_end) = +            &uri_string[0..authority_or_path_delimiter_start].find(':') +        { +            let scheme = +                Self::check_scheme(&uri_string[0..*scheme_end])?.to_lowercase(); +            Ok((Some(scheme), &uri_string[*scheme_end + 1..]))          } else {              Ok((None, uri_string))          } @@ -437,17 +446,13 @@ impl Uri {      ///      /// Since path segments may contain non-UTF8 byte sequences, this function      /// may return -    /// [`Error::CannotExpressAsUtf8`](enum.Error.html#variant.CannotExpressAsUtf8). +    /// [`Error::CannotExpressAsUtf8`](enum.Error.html#variant. +    /// CannotExpressAsUtf8).      #[must_use = "we went through all that trouble to put the path into a string, and you don't want it?"]      pub fn path_to_string(&self) -> Result<String, Error> {          match &*self.path {              [segment] if segment.is_empty() => Ok("/".to_string()), -            path => Ok( -                String::from_utf8( -                    path -                        .join(&b"/"[..]) -                )? -            ), +            path => Ok(String::from_utf8(path.join(&b"/"[..]))?),          }      } @@ -468,14 +473,12 @@ impl Uri {      /// # Errors      ///      /// Since queries may contain non-UTF8 byte sequences, this function may -    /// return [`Error::CannotExpressAsUtf8`](enum.Error.html#variant.CannotExpressAsUtf8). +    /// return [`Error::CannotExpressAsUtf8`](enum.Error.html#variant. +    /// CannotExpressAsUtf8).      #[must_use = "use the query return value silly programmer"]      pub fn query_to_string(&self) -> Result<Option<String>, Error> {          self.query() -            .map(|query| { -                String::from_utf8(query.to_vec()) -                    .map_err(Into::into) -            }) +            .map(|query| String::from_utf8(query.to_vec()).map_err(Into::into))              .transpose()      } @@ -498,75 +501,79 @@ impl Uri {      /// # }      /// ```      #[must_use = "why go through all that effort to resolve the URI, when you're not going to use it?!"] -    pub fn resolve(&self, relative_reference: &Self) -> Self { -        let (scheme, authority, path, query) = if relative_reference.scheme.is_some() { -            ( -                relative_reference.scheme.clone(), -                relative_reference.authority.clone(), -                Self::normalize_path(&relative_reference.path), -                relative_reference.query.clone() -            ) -        } else { -            relative_reference.authority.as_ref().map_or_else( -                || { -                    let scheme = self.scheme.clone(); -                    let authority = self.authority.clone(); -                    if relative_reference.path.is_empty() { -                        let path = self.path.clone(); -                        let query = if relative_reference.query.is_none() { -                            self.query.clone() -                        } else { -                            relative_reference.query.clone() -                        }; -                        ( -                            scheme, -                            authority, -                            path, -                            query -                        ) -                    } else { -                        let query = relative_reference.query.clone(); - -                        // RFC describes this as: -                        // "if (R.path starts-with "/") then" -                        if Self::is_path_absolute(&relative_reference.path) { -                            ( -                                scheme, -                                authority, -                                relative_reference.path.clone(), -                                query -                            ) +    pub fn resolve( +        &self, +        relative_reference: &Self, +    ) -> Self { +        let (scheme, authority, path, query) = +            if relative_reference.scheme.is_some() { +                ( +                    relative_reference.scheme.clone(), +                    relative_reference.authority.clone(), +                    Self::normalize_path(&relative_reference.path), +                    relative_reference.query.clone(), +                ) +            } else { +                relative_reference.authority.as_ref().map_or_else( +                    || { +                        let scheme = self.scheme.clone(); +                        let authority = self.authority.clone(); +                        if relative_reference.path.is_empty() { +                            let path = self.path.clone(); +                            let query = if relative_reference.query.is_none() { +                                self.query.clone() +                            } else { +                                relative_reference.query.clone() +                            }; +                            (scheme, authority, path, query)                          } else { +                            let query = relative_reference.query.clone(); +                              // RFC describes this as: -                            // "T.path = merge(Base.path, R.path);" -                            let mut path = self.path.clone(); -                            if path.len() > 1 { -                                path.pop(); +                            // "if (R.path starts-with "/") then" +                            if Self::is_path_absolute(&relative_reference.path) +                            { +                                ( +                                    scheme, +                                    authority, +                                    relative_reference.path.clone(), +                                    query, +                                ) +                            } else { +                                // RFC describes this as: +                                // "T.path = merge(Base.path, R.path);" +                                let mut path = self.path.clone(); +                                if path.len() > 1 { +                                    path.pop(); +                                } +                                path.extend( +                                    relative_reference.path.iter().cloned(), +                                ); +                                ( +                                    scheme, +                                    authority, +                                    Self::normalize_path(&path), +                                    query, +                                )                              } -                            path.extend(relative_reference.path.iter().cloned()); -                            ( -                                scheme, -                                authority, -                                Self::normalize_path(&path), -                                query -                            )                          } -                    } -                }, -                |authority| ( -                    self.scheme.clone(), -                    Some(authority.clone()), -                    Self::normalize_path(&relative_reference.path), -                    relative_reference.query.clone() +                    }, +                    |authority| { +                        ( +                            self.scheme.clone(), +                            Some(authority.clone()), +                            Self::normalize_path(&relative_reference.path), +                            relative_reference.query.clone(), +                        ) +                    },                  ) -            ) -        }; -        Self{ +            }; +        Self {              scheme,              authority,              path,              query, -            fragment: relative_reference.fragment.clone() +            fragment: relative_reference.fragment.clone(),          }      } @@ -584,15 +591,21 @@ impl Uri {      }      /// Change the authority of the URI. -    pub fn set_authority<T>(&mut self, authority: T) -        where T: Into<Option<Authority>> +    pub fn set_authority<T>( +        &mut self, +        authority: T, +    ) where +        T: Into<Option<Authority>>,      {          self.authority = authority.into();      }      /// Change the fragment of the URI. -    pub fn set_fragment<T>(&mut self, fragment: T) -        where T: Into<Option<Vec<u8>>> +    pub fn set_fragment<T>( +        &mut self, +        fragment: T, +    ) where +        T: Into<Option<Vec<u8>>>,      {          self.fragment = fragment.into();      } @@ -601,8 +614,11 @@ impl Uri {      ///      /// Note: See [`path`](#method.path) for special notes about what the      /// segments of the path mean. -    pub fn set_path<T>(&mut self, path: T) -        where T: Into<Vec<Vec<u8>>> +    pub fn set_path<T>( +        &mut self, +        path: T, +    ) where +        T: Into<Vec<Vec<u8>>>,      {          self.path = path.into();      } @@ -612,23 +628,28 @@ impl Uri {      ///      /// Note: See [`path`](#method.path) for special notes about what the      /// segments of the path mean. -    pub fn set_path_from_str<T>(&mut self, path: T) -        where T: AsRef<str> +    pub fn set_path_from_str<T>( +        &mut self, +        path: T, +    ) where +        T: AsRef<str>,      {          match path.as_ref() {              "" => self.set_path(vec![]),              path => self.set_path( -                path -                    .split('/') +                path.split('/')                      .map(|segment| segment.as_bytes().to_vec()) -                    .collect::<Vec<Vec<u8>>>() +                    .collect::<Vec<Vec<u8>>>(),              ),          }      }      /// Change the query of the URI. -    pub fn set_query<T>(&mut self, query: T) -        where T: Into<Option<Vec<u8>>> +    pub fn set_query<T>( +        &mut self, +        query: T, +    ) where +        T: Into<Option<Vec<u8>>>,      {          self.query = query.into();      } @@ -640,14 +661,18 @@ impl Uri {      /// The set of characters allowed in the scheme of a URI is limited.      /// [`Error::IllegalCharacter`](enum.Error.html#variant.IllegalCharacter)      /// is returned if you try to use a character that isn't allowed. -    pub fn set_scheme<T>(&mut self, scheme: T) -> Result<(), Error> -        where T: Into<Option<String>> +    pub fn set_scheme<T>( +        &mut self, +        scheme: T, +    ) -> Result<(), Error> +    where +        T: Into<Option<String>>,      {          self.scheme = match scheme.into() {              Some(scheme) => {                  Self::check_scheme(&scheme)?;                  Some(scheme) -            } +            },              None => None,          };          Ok(()) @@ -656,7 +681,8 @@ impl Uri {      fn split_authority_from_path_and_parse_them<T>(          authority_and_path_string: T      ) -> Result<(Option<Authority>, Vec<Vec<u8>>), Error> -        where T: AsRef<str> +    where +        T: AsRef<str>,      {          // Split authority from path.  If there is an authority, parse it.          let authority_and_path_string = authority_and_path_string.as_ref(); @@ -665,7 +691,8 @@ impl Uri {              let authority_and_path_string = &authority_and_path_string[2..];              // First separate the authority from the path. -            let authority_end = authority_and_path_string.find('/') +            let authority_end = authority_and_path_string +                .find('/')                  .unwrap_or_else(|| authority_and_path_string.len());              let authority_string = &authority_and_path_string[0..authority_end];              let path_string = &authority_and_path_string[authority_end..]; @@ -723,20 +750,23 @@ impl Uri {      /// # Errors      ///      /// Since fragments may contain non-UTF8 byte sequences, this function may -    /// return [`Error::CannotExpressAsUtf8`](enum.Error.html#variant.CannotExpressAsUtf8). +    /// return [`Error::CannotExpressAsUtf8`](enum.Error.html#variant. +    /// CannotExpressAsUtf8).      #[must_use = "come on, you intended to use that userinfo return value, didn't you?"]      pub fn userinfo_to_string(&self) -> Result<Option<String>, Error> {          self.userinfo()              .map(|userinfo| { -                String::from_utf8(userinfo.to_vec()) -                    .map_err(Into::into) +                String::from_utf8(userinfo.to_vec()).map_err(Into::into)              })              .transpose()      }  }  impl std::fmt::Display for Uri { -    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +    fn fmt( +        &self, +        f: &mut std::fmt::Formatter<'_>, +    ) -> std::fmt::Result {          if let Some(scheme) = &self.scheme {              write!(f, "{}:", scheme)?;          } @@ -744,10 +774,7 @@ impl std::fmt::Display for Uri {              write!(f, "//{}", authority)?;          }          // Special case: absolute but otherwise empty path. -        if -            Self::is_path_absolute(&self.path) -            && self.path.len() == 1 -        { +        if Self::is_path_absolute(&self.path) && self.path.len() == 1 {              write!(f, "/")?;          }          for (i, segment) in self.path.iter().enumerate() { @@ -757,10 +784,18 @@ impl std::fmt::Display for Uri {              }          }          if let Some(query) = &self.query { -            write!(f, "?{}", encode_element(query, &QUERY_NOT_PCT_ENCODED_WITHOUT_PLUS))?; +            write!( +                f, +                "?{}", +                encode_element(query, &QUERY_NOT_PCT_ENCODED_WITHOUT_PLUS) +            )?;          }          if let Some(fragment) = &self.fragment { -            write!(f, "#{}", encode_element(fragment, &QUERY_OR_FRAGMENT_NOT_PCT_ENCODED))?; +            write!( +                f, +                "#{}", +                encode_element(fragment, &QUERY_OR_FRAGMENT_NOT_PCT_ENCODED) +            )?;          }          Ok(())      } @@ -788,7 +823,10 @@ mod tests {          let uri = uri.unwrap();          assert_eq!(Some("http"), uri.scheme());          assert_eq!(Some(&b"www.example.com"[..]), uri.host()); -        assert_eq!(Some("www.example.com"), uri.host_to_string().unwrap().as_deref()); +        assert_eq!( +            Some("www.example.com"), +            uri.host_to_string().unwrap().as_deref() +        );          assert_eq!(uri.path_to_string().unwrap(), "/foo/bar");      } @@ -835,7 +873,7 @@ mod tests {          named_tuple!(              struct TestVector {                  uri_string: &'static str, -                is_relative_reference: bool +                is_relative_reference: bool,              }          );          let test_vectors: &[TestVector] = &[ @@ -860,7 +898,7 @@ mod tests {          named_tuple!(              struct TestVector {                  uri_string: &'static str, -                contains_relative_path: bool +                contains_relative_path: bool,              }          );          let test_vectors: &[TestVector] = &[ @@ -868,7 +906,6 @@ mod tests {              ("http://www.example.com", false).into(),              ("/", false).into(),              ("foo", true).into(), -              // This is only a valid test vector if we understand              // correctly that an empty string IS a valid              // "relative reference" URI with an empty path. @@ -881,7 +918,8 @@ mod tests {              assert_eq!(                  *test_vector.contains_relative_path(),                  uri.contains_relative_path(), -                "{}", test_index +                "{}", +                test_index              );          }      } @@ -893,27 +931,56 @@ mod tests {                  uri_string: &'static str,                  host: &'static str,                  query: Option<&'static str>, -                fragment: Option<&'static str> +                fragment: Option<&'static str>,              }          );          let test_vectors: &[TestVector] = &[              ("http://www.example.com/", "www.example.com", None, None).into(),              ("http://example.com?foo", "example.com", Some("foo"), None).into(), -            ("http://www.example.com#foo", "www.example.com", None, Some("foo")).into(), -            ("http://www.example.com?foo#bar", "www.example.com", Some("foo"), Some("bar")).into(), -            ("http://www.example.com?earth?day#bar", "www.example.com", Some("earth?day"), Some("bar")).into(), -            ("http://www.example.com/spam?foo#bar", "www.example.com", Some("foo"), Some("bar")).into(), -            ("http://www.example.com/?", "www.example.com", Some(""), None).into(), +            ( +                "http://www.example.com#foo", +                "www.example.com", +                None, +                Some("foo"), +            ) +                .into(), +            ( +                "http://www.example.com?foo#bar", +                "www.example.com", +                Some("foo"), +                Some("bar"), +            ) +                .into(), +            ( +                "http://www.example.com?earth?day#bar", +                "www.example.com", +                Some("earth?day"), +                Some("bar"), +            ) +                .into(), +            ( +                "http://www.example.com/spam?foo#bar", +                "www.example.com", +                Some("foo"), +                Some("bar"), +            ) +                .into(), +            ("http://www.example.com/?", "www.example.com", Some(""), None) +                .into(),          ];          for (test_index, test_vector) in test_vectors.iter().enumerate() {              let uri = Uri::parse(test_vector.uri_string());              assert!(uri.is_ok());              let uri = uri.unwrap(); -            assert_eq!(Some(*test_vector.host()), uri.host_to_string().unwrap().as_deref()); +            assert_eq!( +                Some(*test_vector.host()), +                uri.host_to_string().unwrap().as_deref() +            );              assert_eq!(                  *test_vector.query(),                  uri.query_to_string().unwrap().as_deref(), -                "{}", test_index +                "{}", +                test_index              );              assert_eq!(                  *test_vector.fragment(), @@ -943,7 +1010,7 @@ mod tests {          named_tuple!(              struct TestVector {                  uri_string: &'static str, -                scheme: &'static str +                scheme: &'static str,              }          );          let test_vectors: &[TestVector] = &[ @@ -963,7 +1030,7 @@ mod tests {      }      #[test] -    fn scheme_mixed_case () { +    fn scheme_mixed_case() {          let test_vectors = [              "http://www.example.com/",              "hTtp://www.example.com/", @@ -1032,7 +1099,7 @@ mod tests {          named_tuple!(              struct TestVector {                  uri_string: &'static str, -                path: Vec<&'static [u8]> +                path: Vec<&'static [u8]>,              }          );          let test_vectors: &[TestVector] = &[ @@ -1040,7 +1107,13 @@ mod tests {              ("bob@/foo", vec![&b"bob@"[..], &b"foo"[..]]).into(),              ("hello!", vec![&b"hello!"[..]]).into(),              ("urn:hello,%20w%6Frld", vec![&b"hello, world"[..]]).into(), -            ("//example.com/foo/(bar)/", vec![&b""[..], &b"foo"[..], &b"(bar)"[..], &b""[..]]).into(), +            ("//example.com/foo/(bar)/", vec![ +                &b""[..], +                &b"foo"[..], +                &b"(bar)"[..], +                &b""[..], +            ]) +                .into(),          ];          for test_vector in test_vectors {              let uri = Uri::parse(test_vector.uri_string()); @@ -1085,7 +1158,7 @@ mod tests {          named_tuple!(              struct TestVector {                  uri_string: &'static str, -                query: &'static str +                query: &'static str,              }          );          let test_vectors: &[TestVector] = &[ @@ -1103,7 +1176,8 @@ mod tests {              assert_eq!(                  Some(*test_vector.query()),                  uri.query_to_string().unwrap().as_deref(), -                "{}", test_index +                "{}", +                test_index              );          }      } @@ -1143,7 +1217,7 @@ mod tests {          named_tuple!(              struct TestVector {                  uri_string: &'static str, -                fragment: &'static str +                fragment: &'static str,              }          );          let test_vectors: &[TestVector] = &[ @@ -1170,7 +1244,7 @@ mod tests {          named_tuple!(              struct TestVector {                  uri_string: &'static str, -                path_first_segment: &'static [u8] +                path_first_segment: &'static [u8],              }          );          let test_vectors: &[TestVector] = &[ @@ -1253,7 +1327,8 @@ mod tests {              assert_eq!(                  *test_vector.normalized_path(),                  uri.path_to_string().unwrap(), -                "{}", test_vector.uri_string() +                "{}", +                test_vector.uri_string()              );          }      } @@ -1279,7 +1354,7 @@ mod tests {              struct TestVector {                  base_string: &'static str,                  relative_reference_string: &'static str, -                target_string: &'static str +                target_string: &'static str,              }          );          let test_vectors: &[TestVector] = &[ @@ -1307,7 +1382,6 @@ mod tests {              ("http://a/b/c/d;p?q", "../..", "http://a").into(),              ("http://a/b/c/d;p?q", "../../", "http://a").into(),              ("http://a/b/c/d;p?q", "../../g", "http://a/g").into(), -              // Here are some examples of our own.              ("http://example.com", "foo", "http://example.com/foo").into(),              ("http://example.com/", "foo", "http://example.com/foo").into(), @@ -1322,9 +1396,12 @@ mod tests {          ];          for test_vector in test_vectors {              let base_uri = Uri::parse(test_vector.base_string()).unwrap(); -            let relative_reference_uri = Uri::parse(test_vector.relative_reference_string()).unwrap(); -            let expected_target_uri = Uri::parse(test_vector.target_string()).unwrap(); -            let actual_target_uri = dbg!(base_uri.resolve(&relative_reference_uri)); +            let relative_reference_uri = +                Uri::parse(test_vector.relative_reference_string()).unwrap(); +            let expected_target_uri = +                Uri::parse(test_vector.target_string()).unwrap(); +            let actual_target_uri = +                dbg!(base_uri.resolve(&relative_reference_uri));              assert_eq!(expected_target_uri, actual_target_uri);          }      } @@ -1362,56 +1439,278 @@ mod tests {                  path: &'static str,                  query: Option<&'static str>,                  fragment: Option<&'static str>, -                expected_uri_string: &'static str +                expected_uri_string: &'static str,              }          );          let test_vectors: &[TestVector] = &[              // general test vectors -            // scheme      userinfo     host                     port        path         query           fragment     expected_uri_string -            (Some("http"), Some("bob"), Some("www.example.com"), Some(8080), "/abc/def",  Some("foobar"), Some("ch2"), "http://bob@www.example.com:8080/abc/def?foobar#ch2").into(), -            (Some("http"), Some("bob"), Some("www.example.com"), Some(0),    "",          Some("foobar"), Some("ch2"), "http://bob@www.example.com:0?foobar#ch2").into(), -            (Some("http"), Some("bob"), Some("www.example.com"), Some(0),    "",          Some("foobar"), Some(""),    "http://bob@www.example.com:0?foobar#").into(), -            (None,         None,        Some("example.com"),     None,       "",          Some("bar"),    None,        "//example.com?bar").into(), -            (None,         None,        Some("example.com"),     None,       "",          Some(""),       None,        "//example.com?").into(), -            (None,         None,        Some("example.com"),     None,       "",          None,           None,        "//example.com").into(), -            (None,         None,        Some("example.com"),     None,       "/",         None,           None,        "//example.com/").into(), -            (None,         None,        Some("example.com"),     None,       "/xyz",      None,           None,        "//example.com/xyz").into(), -            (None,         None,        Some("example.com"),     None,       "/xyz/",     None,           None,        "//example.com/xyz/").into(), -            (None,         None,        None,                    None,       "/",         None,           None,        "/").into(), -            (None,         None,        None,                    None,       "/xyz",      None,           None,        "/xyz").into(), -            (None,         None,        None,                    None,       "/xyz/",     None,           None,        "/xyz/").into(), -            (None,         None,        None,                    None,       "",          None,           None,        "").into(), -            (None,         None,        None,                    None,       "xyz",       None,           None,        "xyz").into(), -            (None,         None,        None,                    None,       "xyz/",      None,           None,        "xyz/").into(), -            (None,         None,        None,                    None,       "",          Some("bar"),    None,        "?bar").into(), -            (Some("http"), None,        None,                    None,       "",          Some("bar"),    None,        "http:?bar").into(), -            (Some("http"), None,        None,                    None,       "",          None,           None,        "http:").into(), -            (Some("http"), None,        Some("::1"),             None,       "",          None,           None,        "http://[::1]").into(), -            (Some("http"), None,        Some("::1.2.3.4"),       None,       "",          None,           None,        "http://[::1.2.3.4]").into(), -            (Some("http"), None,        Some("1.2.3.4"),         None,       "",          None,           None,        "http://1.2.3.4").into(), -            (None,         None,        None,                    None,       "",          None,           None,        "").into(), -            (Some("http"), Some("bob"), None,                    None,       "",          Some("foobar"), None,        "http://bob@?foobar").into(), -            (None,         Some("bob"), None,                    None,       "",          Some("foobar"), None,        "//bob@?foobar").into(), -            (None,         Some("bob"), None,                    None,       "",          None,           None,        "//bob@").into(), - +            // scheme      userinfo     host                     port +            // path         query           fragment     expected_uri_string +            ( +                Some("http"), +                Some("bob"), +                Some("www.example.com"), +                Some(8080), +                "/abc/def", +                Some("foobar"), +                Some("ch2"), +                "http://bob@www.example.com:8080/abc/def?foobar#ch2", +            ) +                .into(), +            ( +                Some("http"), +                Some("bob"), +                Some("www.example.com"), +                Some(0), +                "", +                Some("foobar"), +                Some("ch2"), +                "http://bob@www.example.com:0?foobar#ch2", +            ) +                .into(), +            ( +                Some("http"), +                Some("bob"), +                Some("www.example.com"), +                Some(0), +                "", +                Some("foobar"), +                Some(""), +                "http://bob@www.example.com:0?foobar#", +            ) +                .into(), +            ( +                None, +                None, +                Some("example.com"), +                None, +                "", +                Some("bar"), +                None, +                "//example.com?bar", +            ) +                .into(), +            ( +                None, +                None, +                Some("example.com"), +                None, +                "", +                Some(""), +                None, +                "//example.com?", +            ) +                .into(), +            ( +                None, +                None, +                Some("example.com"), +                None, +                "", +                None, +                None, +                "//example.com", +            ) +                .into(), +            ( +                None, +                None, +                Some("example.com"), +                None, +                "/", +                None, +                None, +                "//example.com/", +            ) +                .into(), +            ( +                None, +                None, +                Some("example.com"), +                None, +                "/xyz", +                None, +                None, +                "//example.com/xyz", +            ) +                .into(), +            ( +                None, +                None, +                Some("example.com"), +                None, +                "/xyz/", +                None, +                None, +                "//example.com/xyz/", +            ) +                .into(), +            (None, None, None, None, "/", None, None, "/").into(), +            (None, None, None, None, "/xyz", None, None, "/xyz").into(), +            (None, None, None, None, "/xyz/", None, None, "/xyz/").into(), +            (None, None, None, None, "", None, None, "").into(), +            (None, None, None, None, "xyz", None, None, "xyz").into(), +            (None, None, None, None, "xyz/", None, None, "xyz/").into(), +            (None, None, None, None, "", Some("bar"), None, "?bar").into(), +            ( +                Some("http"), +                None, +                None, +                None, +                "", +                Some("bar"), +                None, +                "http:?bar", +            ) +                .into(), +            (Some("http"), None, None, None, "", None, None, "http:").into(), +            ( +                Some("http"), +                None, +                Some("::1"), +                None, +                "", +                None, +                None, +                "http://[::1]", +            ) +                .into(), +            ( +                Some("http"), +                None, +                Some("::1.2.3.4"), +                None, +                "", +                None, +                None, +                "http://[::1.2.3.4]", +            ) +                .into(), +            ( +                Some("http"), +                None, +                Some("1.2.3.4"), +                None, +                "", +                None, +                None, +                "http://1.2.3.4", +            ) +                .into(), +            (None, None, None, None, "", None, None, "").into(), +            ( +                Some("http"), +                Some("bob"), +                None, +                None, +                "", +                Some("foobar"), +                None, +                "http://bob@?foobar", +            ) +                .into(), +            ( +                None, +                Some("bob"), +                None, +                None, +                "", +                Some("foobar"), +                None, +                "//bob@?foobar", +            ) +                .into(), +            (None, Some("bob"), None, None, "", None, None, "//bob@").into(),              // percent-encoded character test vectors -            // scheme      userinfo      host                     port        path        query            fragment     expected_uri_string -            (Some("http"), Some("b b"),  Some("www.example.com"), Some(8080), "/abc/def", Some("foobar"),  Some("ch2"), "http://b%20b@www.example.com:8080/abc/def?foobar#ch2").into(), -            (Some("http"), Some("bob"),  Some("www.e ample.com"), Some(8080), "/abc/def", Some("foobar"),  Some("ch2"), "http://bob@www.e%20ample.com:8080/abc/def?foobar#ch2").into(), -            (Some("http"), Some("bob"),  Some("www.example.com"), Some(8080), "/a c/def", Some("foobar"),  Some("ch2"), "http://bob@www.example.com:8080/a%20c/def?foobar#ch2").into(), -            (Some("http"), Some("bob"),  Some("www.example.com"), Some(8080), "/abc/def", Some("foo ar"),  Some("ch2"), "http://bob@www.example.com:8080/abc/def?foo%20ar#ch2").into(), -            (Some("http"), Some("bob"),  Some("www.example.com"), Some(8080), "/abc/def", Some("foobar"),  Some("c 2"), "http://bob@www.example.com:8080/abc/def?foobar#c%202").into(), -            (Some("http"), Some("bob"),  Some("ሴ.example.com"),   Some(8080), "/abc/def", Some("foobar"),  None,        "http://bob@%E1%88%B4.example.com:8080/abc/def?foobar").into(), - +            // scheme      userinfo      host                     port +            // path        query            fragment     expected_uri_string +            ( +                Some("http"), +                Some("b b"), +                Some("www.example.com"), +                Some(8080), +                "/abc/def", +                Some("foobar"), +                Some("ch2"), +                "http://b%20b@www.example.com:8080/abc/def?foobar#ch2", +            ) +                .into(), +            ( +                Some("http"), +                Some("bob"), +                Some("www.e ample.com"), +                Some(8080), +                "/abc/def", +                Some("foobar"), +                Some("ch2"), +                "http://bob@www.e%20ample.com:8080/abc/def?foobar#ch2", +            ) +                .into(), +            ( +                Some("http"), +                Some("bob"), +                Some("www.example.com"), +                Some(8080), +                "/a c/def", +                Some("foobar"), +                Some("ch2"), +                "http://bob@www.example.com:8080/a%20c/def?foobar#ch2", +            ) +                .into(), +            ( +                Some("http"), +                Some("bob"), +                Some("www.example.com"), +                Some(8080), +                "/abc/def", +                Some("foo ar"), +                Some("ch2"), +                "http://bob@www.example.com:8080/abc/def?foo%20ar#ch2", +            ) +                .into(), +            ( +                Some("http"), +                Some("bob"), +                Some("www.example.com"), +                Some(8080), +                "/abc/def", +                Some("foobar"), +                Some("c 2"), +                "http://bob@www.example.com:8080/abc/def?foobar#c%202", +            ) +                .into(), +            ( +                Some("http"), +                Some("bob"), +                Some("ሴ.example.com"), +                Some(8080), +                "/abc/def", +                Some("foobar"), +                None, +                "http://bob@%E1%88%B4.example.com:8080/abc/def?foobar", +            ) +                .into(),              // normalization of IPv6 address hex digits -            // scheme      userinfo     host                   port        path        query           fragment     expected_uri_string -            (Some("http"), Some("bob"), Some("fFfF::1"),       Some(8080), "/abc/def", Some("foobar"), Some("c 2"), "http://bob@[ffff::1]:8080/abc/def?foobar#c%202").into(), +            // scheme      userinfo     host                   port        path +            // query           fragment     expected_uri_string +            ( +                Some("http"), +                Some("bob"), +                Some("fFfF::1"), +                Some(8080), +                "/abc/def", +                Some("foobar"), +                Some("c 2"), +                "http://bob@[ffff::1]:8080/abc/def?foobar#c%202", +            ) +                .into(),          ];          for test_vector in test_vectors {              let mut uri = Uri::default(); -            assert!(uri.set_scheme(test_vector.scheme().map(ToString::to_string)).is_ok()); -            if -                test_vector.userinfo().is_some() +            assert!(uri +                .set_scheme(test_vector.scheme().map(ToString::to_string)) +                .is_ok()); +            if test_vector.userinfo().is_some()                  || test_vector.host().is_some()                  || test_vector.port().is_some()              { @@ -1426,10 +1725,7 @@ mod tests {              uri.set_path_from_str(test_vector.path());              uri.set_query(test_vector.query().map(Into::into));              uri.set_fragment(test_vector.fragment().map(Into::into)); -            assert_eq!( -                *test_vector.expected_uri_string(), -                uri.to_string() -            ); +            assert_eq!(*test_vector.expected_uri_string(), uri.to_string());          }      } @@ -1513,23 +1809,13 @@ mod tests {          for ci in 0_u8..31_u8 {              let mut uri = Uri::default();              uri.set_query(Some(vec![ci])); -            assert_eq!( -                uri.to_string(), -                format!("?%{:02X}", ci) -            ); +            assert_eq!(uri.to_string(), format!("?%{:02X}", ci));          }      }      #[test]      fn set_illegal_schemes() { -        let test_vectors = [ -            "ab_de", -            "ab/de", -            "ab:de", -            "", -            "&", -            "foo&bar", -        ]; +        let test_vectors = ["ab_de", "ab/de", "ab:de", "", "&", "foo&bar"];          for test_vector in &test_vectors {              let mut uri = Uri::default();              assert!(uri.set_scheme(Some((*test_vector).to_string())).is_err()); @@ -1538,7 +1824,8 @@ mod tests {      #[test]      fn take_parts() { -        let mut uri = Uri::parse("https://www.example.com/foo?bar#baz").unwrap(); +        let mut uri = +            Uri::parse("https://www.example.com/foo?bar#baz").unwrap();          assert_eq!(Some("https"), uri.take_scheme().as_deref());          assert_eq!("//www.example.com/foo?bar#baz", uri.to_string());          assert!(matches!( @@ -1554,5 +1841,4 @@ mod tests {          assert_eq!("/foo", uri.to_string());          assert_eq!(None, uri.take_fragment().as_deref());      } -  }  | 
