From 9082d329da57d96a55f519454d1b82b9c3e7f72e Mon Sep 17 00:00:00 2001
From: Richard Walters <rwalters@digitalstirling.com>
Date: Mon, 12 Oct 2020 15:31:25 -0700
Subject: Make functions accepting references more generic using AsRef

---
 src/lib.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 51 insertions(+), 21 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 554a4a2..54c31e4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -263,7 +263,9 @@ fn encode_element(
 }
 
 
-fn validate_ipv4_address(address: &str) -> Result<(), Error> {
+fn validate_ipv4_address<T>(address: T) -> Result<(), Error>
+    where T: AsRef<str>
+{
     #[derive(PartialEq)]
     enum State {
         NotInOctet,
@@ -276,7 +278,7 @@ fn validate_ipv4_address(address: &str) -> Result<(), Error> {
     //
     // Validation of the octet_buffer is done in two places; consider
     // how to remove the redundant code.
-    for c in address.chars() {
+    for c in address.as_ref().chars() {
         state = match state {
             State::NotInOctet if DIGIT.contains(&c) => {
                 octet_buffer.push(c);
@@ -328,7 +330,9 @@ fn validate_ipv4_address(address: &str) -> Result<(), Error> {
 // TODO: Clippy correctly advises us that this function needs refactoring
 // because it has too many lines.  We'll get back to that.
 #[allow(clippy::too_many_lines)]
-fn validate_ipv6_address(address: &str) -> Result<(), Error> {
+fn validate_ipv6_address<T>(address: T) -> Result<(), Error>
+    where T: AsRef<str>
+{
     #[derive(PartialEq)]
     enum ValidationState {
         NoGroupsYet,
@@ -344,6 +348,7 @@ fn validate_ipv6_address(address: &str) -> Result<(), Error> {
     let mut double_colon_encountered = false;
     let mut potential_ipv4_address_start = 0;
     let mut ipv4_address_encountered = false;
+    let address = address.as_ref();
     for (i, c) in address.char_indices() {
         state = match state {
             ValidationState::NoGroupsYet => {
@@ -577,7 +582,10 @@ impl Uri {
         !Self::is_path_absolute(&self.path)
     }
 
-    fn can_navigate_path_up_one_level(path: &[Vec<u8>]) -> bool {
+    fn can_navigate_path_up_one_level<T>(path: T) -> bool
+        where T: AsRef<[Vec<u8>]>
+    {
+        let path = path.as_ref();
         match path.first() {
             // First segment empty means path has leading slash,
             // so we can only navigate up if there are two or more segments.
@@ -624,10 +632,12 @@ impl Uri {
             .collect()
     }
 
-    fn decode_query_or_fragment(
-        query_or_fragment: &str,
+    fn decode_query_or_fragment<T>(
+        query_or_fragment: T,
         context: Context,
-    ) -> Result<Vec<u8>, Error> {
+    ) -> Result<Vec<u8>, Error>
+        where T: AsRef<str>
+    {
         Self::decode_element(
             query_or_fragment,
             &QUERY_OR_FRAGMENT_NOT_PCT_ENCODED,
@@ -647,8 +657,10 @@ impl Uri {
             .map(Authority::host)
     }
 
-    fn is_path_absolute(path: &[Vec<u8>]) -> bool {
-        match path {
+    fn is_path_absolute<T>(path: T) -> bool
+        where T: AsRef<[Vec<u8>]>
+    {
+        match path.as_ref() {
             [segment, ..] if segment.is_empty() => true,
             _ => false
         }
@@ -667,7 +679,9 @@ impl Uri {
     // in RFC 3986 (https://tools.ietf.org/html/rfc3986) to the path
     // segments of the URI, in order to normalize the path
     // (apply and remove "." and ".." segments).
-    fn normalize_path(original_path: &[Vec<u8>]) -> Vec<Vec<u8>> {
+    fn normalize_path<T>(original_path: T) -> Vec<Vec<u8>>
+        where T: AsRef<[Vec<u8>]>
+    {
         // Rebuild the path one segment
         // at a time, removing and applying special
         // navigation segments ("." and "..") as we go.
@@ -679,7 +693,7 @@ impl Uri {
         // empty segments.  Conclusion: We should refactor this.
         let mut at_directory_level = false;
         let mut normalized_path = Vec::new();
-        for segment in original_path {
+        for segment in original_path.as_ref() {
             if segment == b"." {
                 at_directory_level = true;
             } else if segment == b".." {
@@ -716,8 +730,10 @@ impl Uri {
         normalized_path
     }
 
-    pub fn parse(uri_string: &str) -> Result<Uri, Error> {
-        let (scheme, rest) = Self::parse_scheme(uri_string)?;
+    pub fn parse<T>(uri_string: T) -> Result<Uri, Error>
+        where T: AsRef<str>
+    {
+        let (scheme, rest) = Self::parse_scheme(uri_string.as_ref())?;
         let path_end = rest
             .find(&['?', '#'][..])
             .unwrap_or_else(|| rest.len());
@@ -737,7 +753,9 @@ impl Uri {
 
     // TODO: Needs refactoring, as Clippy dutifully told us.
     #[allow(clippy::too_many_lines)]
-    fn parse_authority(authority_string: &str) -> Result<Authority, Error> {
+    fn parse_authority<T>(authority_string: T) -> Result<Authority, Error>
+        where T: AsRef<str>
+    {
         // These are the various states for the state machine implemented
         // below to correctly split up and validate the URI substring
         // containing the host and potentially a port number as well.
@@ -753,6 +771,7 @@ impl Uri {
         };
 
         // First, check if there is a UserInfo, and if so, extract it.
+        let authority_string = authority_string.as_ref();
         let (userinfo, mut host_port_string) = match authority_string.find('@') {
             Some(user_info_delimiter) => (
                 Some(
@@ -915,8 +934,10 @@ impl Uri {
         }
     }
 
-    fn parse_path(path_string: &str) -> Result<Vec<Vec<u8>>, Error> {
-        match path_string {
+    fn parse_path<T>(path_string: T) -> Result<Vec<Vec<u8>>, Error>
+        where T: AsRef<str>
+    {
+        match path_string.as_ref() {
             "/" => {
                 // Special case of an empty absolute path, which we want to
                 // represent as single empty-string element to indicate that it
@@ -945,7 +966,10 @@ impl Uri {
         }
     }
 
-    fn parse_query(query_and_or_fragment: &str) -> Result<Option<Vec<u8>>, Error> {
+    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() {
             Ok(None)
         } else {
@@ -1106,7 +1130,10 @@ impl Uri {
         self.path = path.map(std::borrow::ToOwned::to_owned).collect();
     }
 
-    pub fn set_path_from_str<'a>(&mut self, path: &'a str) {
+    pub fn set_path_from_str<'a, T>(&mut self, path: T)
+        where T: AsRef<str> + 'a
+    {
+        let path = path.as_ref();
         if path.is_empty() {
             self.set_path(std::iter::empty());
         } else {
@@ -1131,10 +1158,13 @@ impl Uri {
         Ok(())
     }
 
-    fn split_authority_from_path_and_parse_them(
-        authority_and_path_string: &str
-    ) -> Result<(Option<Authority>, Vec<Vec<u8>>), Error> {
+    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>
+    {
         // Split authority from path.  If there is an authority, parse it.
+        let authority_and_path_string = authority_and_path_string.as_ref();
         if authority_and_path_string.starts_with("//") {
             // Strip off authority marker.
             let authority_and_path_string = &authority_and_path_string[2..];
-- 
cgit v1.2.3