Просмотр исходного кода

Parse with char iterators instead of UTF-8 bytes.

Simon Sapin 12 лет назад
Родитель
Сommit
579895c93a
3 измененных файлов с 159 добавлено и 195 удалено
  1. 6 6
      src/form_urlencoded.rs
  2. 133 169
      src/parser.rs
  3. 20 20
      src/url.rs

+ 6 - 6
src/form_urlencoded.rs

@@ -30,19 +30,19 @@ pub fn parse_bytes(input: &[u8], encoding_override: Option<EncodingRef>,
                    mut use_charset: bool, mut isindex: bool) -> Option<Vec<(String, String)>> {
     let mut encoding_override = encoding_override.unwrap_or(UTF_8 as EncodingRef);
     let mut pairs = Vec::new();
-    for piece in input.split(|&b| b == '&' as u8) {
+    for piece in input.split(|&b| b == b'&') {
         if piece.is_empty() {
             if isindex {
                 pairs.push((Vec::new(), Vec::new()))
             }
         } else {
-            let (name, value) = match piece.position_elem(&('=' as u8)) {
+            let (name, value) = match piece.position_elem(&b'=') {
                 Some(position) => (piece.slice_to(position), piece.slice_from(position + 1)),
                 None => if isindex { (&[], piece) } else { (piece, &[]) }
             };
             let name = replace_plus(name);
             let value = replace_plus(value);
-            if use_charset && name.as_slice() == "_charset_".as_bytes() {
+            if use_charset && name.as_slice() == b"_charset_" {
                 // Non-UTF8 here is ok, encoding_from_whatwg_label only matches in the ASCII range.
                 match encoding_from_whatwg_label(unsafe { str::raw::from_utf8(value.as_slice()) }) {
                     Some(encoding) => encoding_override = encoding,
@@ -60,7 +60,7 @@ pub fn parse_bytes(input: &[u8], encoding_override: Option<EncodingRef>,
 
     #[inline]
     fn replace_plus(input: &[u8]) -> Vec<u8> {
-        input.iter().map(|&b| if b == '+' as u8 { ' ' as u8 } else { b }).collect()
+        input.iter().map(|&b| if b == b'+' { b' ' } else { b }).collect()
     }
 
     #[inline]
@@ -90,8 +90,8 @@ pub fn serialize(pairs: Vec<(String, String)>, encoding_override: Option<Encodin
 
         for &byte in input.iter() {
             match byte {
-                0x20 => output.push_str("+"),
-                0x2A | 0x2D | 0x2E | 0x30 .. 0x39 | 0x41 .. 0x5A | 0x5F | 0x61 .. 0x7A
+                b' ' => output.push_str("+"),
+                b'*' | b'-' | b'.' | b'0' .. b'9' | b'A' .. b'Z' | b'_' | b'a' .. b'z'
                 => unsafe { output.push_byte(byte) },
                 _ => percent_encode_byte(byte, output),
             }

+ 133 - 169
src/parser.rs

@@ -27,13 +27,6 @@ macro_rules! is_match(
 )
 
 
-macro_rules! ascii_nocheck(
-    ($value: expr) => {
-        unsafe { $value.to_ascii_nocheck() }
-    }
-)
-
-
 fn parse_error(_message: &str) {
     // TODO
 }
@@ -41,9 +34,8 @@ fn parse_error(_message: &str) {
 
 pub fn parse_url(input: &str, base_url: Option<&Url>) -> ParseResult<Url> {
     let input = input.trim_chars(&[' ', '\t', '\n', '\r', '\x0C']);
-    let (scheme_result, remaining) = parse_scheme(input);
-    match scheme_result {
-        Some(scheme) => {
+    match parse_scheme(input) {
+        Some((scheme, remaining)) => {
             if scheme.as_slice() == "file" {
                 // Relative state?
                 match base_url {
@@ -83,29 +75,26 @@ pub fn parse_url(input: &str, base_url: Option<&Url>) -> ParseResult<Url> {
         // No-scheme state
         None => match base_url {
             None => Err("Relative URL without a base"),
-            Some(base) => parse_relative_url(base.scheme.clone(), remaining, base)
+            Some(base) => parse_relative_url(base.scheme.clone(), input, base)
         }
     }
 }
 
 
-fn parse_scheme<'a>(input: &'a str) -> (Option<String>, &'a str) {
-    if input.is_empty() || !is_ascii_alpha(input.as_bytes()[0]) {
-        return (None, input)
-    }
-    let mut i = 1;
-    while i < input.len() {
-        match input.as_bytes()[i] as char {
-            'a'..'z' | 'A'..'Z' | '0'..'9' | '+' | '-' | '.' => (),
-            ':' => return (
-                Some(input.slice_to(i).to_ascii_lower()),
-                input.slice_from(i + 1),
-            ),
-            _ => return (None, input),
+fn parse_scheme<'a>(input: &'a str) -> Option<(String, &'a str)> {
+    if !input.is_empty() && starts_with_ascii_alpha(input) {
+        for (i, c) in input.char_indices() {
+            match c {
+                'a'..'z' | 'A'..'Z' | '0'..'9' | '+' | '-' | '.' => (),
+                ':' => return Some((
+                    input.slice_to(i).to_ascii_lower(),
+                    input.slice_from(i + 1),
+                )),
+                _ => break,
+            }
         }
-        i += 1;
     }
-    return (None, input)
+    None
 }
 
 
@@ -137,17 +126,17 @@ fn parse_relative_url<'a>(scheme: String, input: &'a str, base: &Url) -> ParseRe
                      query: base.query.clone(), fragment: None })
         } else {
             let in_file_scheme = scheme.as_slice() == "file";
-            match input.as_bytes()[0] as char {
+            match input.char_at(0) {
                 '/' | '\\' => {
                     // Relative slash state
-                    if input.len() > 1 && is_match!(input.as_bytes()[1] as char, '/' | '\\') {
+                    if input.len() > 1 && is_match!(input.char_at(1), '/' | '\\') {
                         if in_file_scheme {
                             let remaining = input.slice_from(2);
                             let (host, remaining) = if remaining.len() >= 2
-                               && is_ascii_alpha(remaining.as_bytes()[0])
-                               && is_match!(remaining.as_bytes()[1] as char, ':' | '|')
+                               && starts_with_ascii_alpha(remaining)
+                               && is_match!(remaining.char_at(1), ':' | '|')
                                && (remaining.len() == 2
-                                   || is_match!(remaining.as_bytes()[2] as char,
+                                   || is_match!(remaining.char_at(2),
                                                  '/' | '\\' | '?' | '#'))
                             {
                                 // Windows drive letter quirk
@@ -204,10 +193,10 @@ fn parse_relative_url<'a>(scheme: String, input: &'a str, base: &Url) -> ParseRe
                 _ => {
                     let (scheme_data, remaining) = if in_file_scheme
                        && input.len() >= 2
-                       && is_ascii_alpha(input.as_bytes()[0])
-                       && is_match!(input.as_bytes()[1] as char, ':' | '|')
+                       && starts_with_ascii_alpha(input)
+                       && is_match!(input.char_at(1), ':' | '|')
                        && (input.len() == 2
-                           || is_match!(input.as_bytes()[2] as char, '/' | '\\' | '?' | '#'))
+                           || is_match!(input.char_at(2), '/' | '\\' | '?' | '#'))
                     {
                         // Windows drive letter quirk
                         let (path, remaining) = parse_path(
@@ -244,33 +233,22 @@ fn parse_relative_url<'a>(scheme: String, input: &'a str, base: &Url) -> ParseRe
 
 
 fn skip_slashes<'a>(input: &'a str) -> &'a str {
-    let mut i = 0;
-    let mut has_backslashes = false;
-    while i < input.len() {
-        match input.as_bytes()[i] as char {
-            '/' => (),
-            '\\' => has_backslashes = true,
-            _ => break
-        }
-        i += 1;
-    }
-    if i != 2 || has_backslashes {
+    let first_non_slash = input.find(|c| !is_match!(c, '/' | '\\')).unwrap_or(input.len());
+    if input.slice_to(first_non_slash) != "//" {
         parse_error("Expected two slashes")
     }
-    input.slice_from(i)
+    input.slice_from(first_non_slash)
 }
 
 
 fn parse_userinfo<'a>(input: &'a str) -> (Option<UserInfo>, &'a str) {
-    let mut i = 0;
     let mut last_at = None;
-    while i < input.len() {
-        match input.as_bytes()[i] as char {
+    for (i, c) in input.char_indices() {
+        match c {
             '@' => last_at = Some(i),
             '/' | '\\' | '?' | '#' => break,
             _ => (),
         }
-        i += 1;
     }
     match last_at {
         None => (None, input),
@@ -280,56 +258,46 @@ fn parse_userinfo<'a>(input: &'a str) -> (Option<UserInfo>, &'a str) {
 }
 
 
-fn parse_userinfo_inner<'a>(input: &'a str) -> UserInfo {
+fn parse_userinfo_inner(input: &str) -> UserInfo {
     let mut username = String::new();
-    let mut i = 0;
-    loop {
-        if i >= input.len() {
-            return UserInfo { username: username, password: None }
-        }
-        match input.as_bytes()[i] as char {
-            ':' => {
-                i += 1;
-                break
-            },
-            '\t' | '\n' | '\r' => {
-                parse_error("Invalid character");
-                i += 1;
-            },
+    for (i, c) in input.char_indices() {
+        match c {
+            ':' => return parse_userinfo_password(input.slice_from(i + 1), username),
+            '\t' | '\n' | '\r' => parse_error("Invalid character"),
             _ => {
-                let range = input.char_range_at(i);
-                if range.ch == '%' {
+                if c == '%' {
                     if !starts_with_2_hex(input.slice_from(i + 1)) {
                         parse_error("Invalid percent-encoded sequence")
                     }
-                } else if !is_url_code_point(range.ch) {
+                } else if !is_url_code_point(c) {
                     parse_error("Non-URL code point")
                 }
 
-                utf8_percent_encode(input.slice(i, range.next), UserInfoEncodeSet, &mut username);
-                i = range.next;
+                utf8_percent_encode(input.slice(i, i + c.len_utf8_bytes()),
+                                    UserInfoEncodeSet, &mut username);
             }
         }
     }
+    UserInfo { username: username, password: None }
+}
+
+
+fn parse_userinfo_password(input: &str, username: String) -> UserInfo {
     let mut password = String::new();
-    while i < input.len() {
-        match input.as_bytes()[i] as char {
-            '\t' | '\n' | '\r' => {
-                parse_error("Invalid character");
-                i += 1;
-            },
+    for (i, c) in input.char_indices() {
+        match c {
+            '\t' | '\n' | '\r' => parse_error("Invalid character"),
             _ => {
-                let range = input.char_range_at(i);
-                if range.ch == '%' {
+                if c == '%' {
                     if !starts_with_2_hex(input.slice_from(i + 1)) {
                         parse_error("Invalid percent-encoded sequence")
                     }
-                } else if !is_url_code_point(range.ch) {
+                } else if !is_url_code_point(c) {
                     parse_error("Non-URL code point")
                 }
 
-                utf8_percent_encode(input.slice(i, range.next), UserInfoEncodeSet, &mut password);
-                i = range.next;
+                utf8_percent_encode(input.slice(i, i + c.len_utf8_bytes()),
+                                    UserInfoEncodeSet, &mut password);
             }
         }
     }
@@ -338,11 +306,11 @@ fn parse_userinfo_inner<'a>(input: &'a str) -> UserInfo {
 
 
 fn parse_hostname<'a>(input: &'a str, scheme: &str) -> ParseResult<(Host, String, &'a str)> {
-    let mut i = 0;
     let mut inside_square_brackets = false;
     let mut host_input = String::new();
-    while i < input.len() {
-        match input.as_bytes()[i] as char {
+    let mut end = input.len();
+    for (i, c) in input.char_indices() {
+        match c {
             ':' if !inside_square_brackets => return match Host::parse(host_input.as_slice()) {
                 Err(message) => Err(message),
                 Ok(host) => {
@@ -352,7 +320,10 @@ fn parse_hostname<'a>(input: &'a str, scheme: &str) -> ParseResult<(Host, String
                     }
                 }
             },
-            '/' | '\\' | '?' | '#' => break,
+            '/' | '\\' | '?' | '#' => {
+                end = i;
+                break
+            },
             '\t' | '\n' | '\r' => parse_error("Invalid character"),
             c => {
                 match c {
@@ -360,14 +331,13 @@ fn parse_hostname<'a>(input: &'a str, scheme: &str) -> ParseResult<(Host, String
                     ']' => inside_square_brackets = false,
                     _ => (),
                 }
-                unsafe { host_input.push_byte(input.as_bytes()[i]) }
+                host_input.push_char(c)
             }
         }
-        i += 1;
     }
     match Host::parse(host_input.as_slice()) {
         Err(message) => Err(message),
-        Ok(host) => Ok((host, String::new(), input.slice_from(i))),
+        Ok(host) => Ok((host, String::new(), input.slice_from(end))),
     }
 }
 
@@ -375,22 +345,24 @@ fn parse_hostname<'a>(input: &'a str, scheme: &str) -> ParseResult<(Host, String
 fn parse_port<'a>(input: &'a str, scheme: &str) -> ParseResult<(String, &'a str)> {
     let mut port = String::new();
     let mut has_initial_zero = false;
-    let mut i = 0;
-    while i < input.len() {
-        match input.as_bytes()[i] as char {
-            '1' .. '9' => unsafe { port.push_byte(input.as_bytes()[i]) },
+    let mut end = input.len();
+    for (i, c) in input.char_indices() {
+        match c {
+            '1'..'9' => port.push_char(c),
             '0' => {
                 if port.is_empty() {
                     has_initial_zero = true
                 } else {
-                    unsafe { port.push_byte(input.as_bytes()[i]) }
+                    port.push_char(c)
                 }
             },
-            '/' | '\\' | '?' | '#' => break,
+            '/' | '\\' | '?' | '#' => {
+                end = i;
+                break
+            },
             '\t' | '\n' | '\r' => parse_error("Invalid character"),
             _ => return Err("Invalid port number")
         }
-        i += 1;
     }
     if port.is_empty() && has_initial_zero {
         port.push_str("0")
@@ -398,23 +370,25 @@ fn parse_port<'a>(input: &'a str, scheme: &str) -> ParseResult<(String, &'a str)
     match (scheme, port.as_slice()) {
         ("ftp", "21") | ("gopher", "70") | ("http", "80") |
         ("https", "443") | ("ws", "80") | ("wss", "443")
-        => port.truncate(0),
+        => port = String::new(),
         _ => (),
     }
-    return Ok((port, input.slice_from(i)))
+    return Ok((port, input.slice_from(end)))
 }
 
 
 fn parse_file_host<'a>(input: &'a str) -> ParseResult<(Host, &'a str)> {
-    let mut i = 0;
     let mut host_input = String::new();
-    while i < input.len() {
-        match input.as_bytes()[i] as char {
-            '/' | '\\' | '?' | '#' => break,
+    let mut end = input.len();
+    for (i, c) in input.char_indices() {
+        match c {
+            '/' | '\\' | '?' | '#' => {
+                end = i;
+                break
+            },
             '\t' | '\n' | '\r' => parse_error("Invalid character"),
-            _ => unsafe { host_input.push_byte(input.as_bytes()[i]) }
+            _ => host_input.push_char(c)
         }
-        i += 1;
     }
     let host = if host_input.is_empty() {
         Domain(Vec::new())
@@ -424,7 +398,7 @@ fn parse_file_host<'a>(input: &'a str) -> ParseResult<(Host, &'a str)> {
             Ok(host) => host,
         }
     };
-    Ok((host, input.slice_from(i)))
+    Ok((host, input.slice_from(end)))
 }
 
 
@@ -433,7 +407,7 @@ fn parse_path_start<'a>(input: &'a str, full_url: bool, in_file_scheme: bool)
     let mut i = 0;
     // Relative path start state
     if !input.is_empty() {
-        match input.as_bytes()[0] as char {
+        match input.char_at(0) {
             '/' => i = 1,
             '\\' => {
                 parse_error("Backslash");
@@ -450,52 +424,55 @@ fn parse_path<'a>(base_path: Vec<String>, input: &'a str, full_url: bool, in_fil
            -> (Vec<String>, &'a str) {
     // Relative path state
     let mut path = base_path;
-    let mut i = 0;
+    let mut iter = input.char_indices();
+    let mut end;
     loop {
         let mut path_part = String::new();
         let mut ends_with_slash = false;
-        while i < input.len() {
-            match input.as_bytes()[i] as char {
+        end = input.len();
+        for (i, c) in iter {
+            match c {
                 '/' => {
-                    i += 1;
                     ends_with_slash = true;
+                    end = i;
                     break
                 },
                 '\\' => {
                     parse_error("Backslash");
-                    i += 1;
                     ends_with_slash = true;
+                    end = i;
+                    break
+                },
+                '?' | '#' if full_url => {
+                    end = i;
                     break
                 },
-                '?' | '#' if full_url => break,
                 '\t' | '\n' | '\r' => {
-                    i += 1;
                     parse_error("Invalid character")
                 },
                 _ => {
-                    let range = input.char_range_at(i);
-                    if range.ch == '%' {
+                    if c == '%' {
                         if !starts_with_2_hex(input.slice_from(i + 1)) {
                             parse_error("Invalid percent-encoded sequence")
                         }
-                    } else if !is_url_code_point(range.ch) {
+                    } else if !is_url_code_point(c) {
                         parse_error("Non-URL code point")
                     }
 
-                    utf8_percent_encode(input.slice(i, range.next), DefaultEncodeSet, &mut path_part);
-                    i = range.next;
+                    utf8_percent_encode(input.slice(i, i + c.len_utf8_bytes()),
+                                        DefaultEncodeSet, &mut path_part);
                 }
             }
         }
-        let lower = path_part.as_slice().to_ascii_lower();
-        match lower.as_slice() {
-            ".." | ".%2e" | "%2e." | "%2e%2e" => {
+        match path_part.as_slice() {
+            ".." | ".%2e" | ".%2E" | "%2e." | "%2E." |
+            "%2e%2e" | "%2E%2e" | "%2e%2E" | "%2E%2E" => {
                 path.pop();
                 if !ends_with_slash {
                     path.push(String::new());
                 }
             },
-            "." | "%2e" => {
+            "." | "%2e" | "%2E" => {
                 if !ends_with_slash {
                     path.push(String::new());
                 }
@@ -504,11 +481,11 @@ fn parse_path<'a>(base_path: Vec<String>, input: &'a str, full_url: bool, in_fil
                 if in_file_scheme
                    && path.is_empty()
                    && path_part.len() == 2
-                   && is_ascii_alpha(path_part.as_bytes()[0])
-                   && path_part.as_bytes()[1] == ('|' as u8) {
+                   && starts_with_ascii_alpha(path_part.as_slice())
+                   && path_part.as_slice().char_at(1) == '|' {
                     // Windows drive letter quirk
                     unsafe {
-                        *path_part.as_mut_vec().get_mut(1) = ':' as u8
+                        *path_part.as_mut_vec().get_mut(1) = b':'
                     }
                 }
                 path.push(path_part)
@@ -518,36 +495,35 @@ fn parse_path<'a>(base_path: Vec<String>, input: &'a str, full_url: bool, in_fil
             break
         }
     }
-    (path, input.slice_from(i))
+    (path, input.slice_from(end))
 }
 
 
 fn parse_scheme_data<'a>(input: &'a str) -> (String, &'a str) {
     let mut scheme_data = String::new();
-    let mut i = 0;
-    while i < input.len() {
-        match input.as_bytes()[i] as char {
-            '?' | '#' => break,
-            '\t' | '\n' | '\r' => {
-                parse_error("Invalid character");
-                i += 1;
+    let mut end = input.len();
+    for (i, c) in input.char_indices() {
+        match c {
+            '?' | '#' => {
+                end = i;
+                break
             },
+            '\t' | '\n' | '\r' => parse_error("Invalid character"),
             _ => {
-                let range = input.char_range_at(i);
-                if range.ch == '%' {
+                if c == '%' {
                     if !starts_with_2_hex(input.slice_from(i + 1)) {
                         parse_error("Invalid percent-encoded sequence")
                     }
-                } else if !is_url_code_point(range.ch) {
+                } else if !is_url_code_point(c) {
                     parse_error("Non-URL code point")
                 }
 
-                utf8_percent_encode(input.slice(i, range.next), SimpleEncodeSet, &mut scheme_data);
-                i = range.next;
+                utf8_percent_encode(input.slice(i, i + c.len_utf8_bytes()),
+                                    SimpleEncodeSet, &mut scheme_data);
             }
         }
     }
-    (scheme_data, input.slice_from(i))
+    (scheme_data, input.slice_from(end))
 }
 
 
@@ -555,7 +531,7 @@ fn parse_query_and_fragment(input: &str) -> (Option<String>, Option<String>) {
     if input.is_empty() {
         (None, None)
     } else {
-        match input.as_bytes()[0] as char {
+        match input.char_at(0) {
             '#' => (None, Some(parse_fragment(input.slice_from(1)))),
             '?' => {
                 let (query, remaining) = parse_query(
@@ -573,30 +549,23 @@ fn parse_query_and_fragment(input: &str) -> (Option<String>, Option<String>) {
 fn parse_query<'a>(input: &'a str, encoding_override: EncodingRef, full_url: bool)
                -> (String, Option<&'a str>) {
     let mut query = String::new();
-    let mut i = 0;
     let mut remaining = None;
-    while i < input.len() {
-        match input.as_bytes()[i] as char {
+    for (i, c) in input.char_indices() {
+        match c {
             '#' if full_url => {
                 remaining = Some(input.slice_from(i + 1));
                 break
             },
-            '\t' | '\n' | '\r' => {
-                parse_error("Invalid character");
-                i += 1;
-            },
+            '\t' | '\n' | '\r' => parse_error("Invalid character"),
             _ => {
-                let range = input.char_range_at(i);
-                if range.ch == '%' {
+                if c == '%' {
                     if !starts_with_2_hex(input.slice_from(i + 1)) {
                         parse_error("Invalid percent-encoded sequence")
                     }
-                } else if !is_url_code_point(range.ch) {
+                } else if !is_url_code_point(c) {
                     parse_error("Non-URL code point")
                 }
-
-                query.push_char(range.ch);
-                i = range.next;
+                query.push_char(c);
             }
         }
     }
@@ -604,7 +573,7 @@ fn parse_query<'a>(input: &'a str, encoding_override: EncodingRef, full_url: boo
     let mut query_encoded = String::new();
     for &byte in query_bytes.iter() {
         match byte {
-            0x00 .. 0x20 | 0x22 | 0x23 | 0x3C | 0x3E | 0x60 | 0x7E .. 0xFF
+            b'\x00'.. b' ' | b'"' | b'#' | b'<' | b'>' | b'`' | b'~'..b'\xFF'
             => percent_encode_byte(byte, &mut query_encoded),
             _
             => unsafe { query_encoded.push_byte(byte) }
@@ -616,25 +585,20 @@ fn parse_query<'a>(input: &'a str, encoding_override: EncodingRef, full_url: boo
 
 fn parse_fragment<'a>(input: &'a str) -> String {
     let mut fragment = String::new();
-    let mut i = 0;
-    while i < input.len() {
-        match input.as_bytes()[i] as char {
-            '\t' | '\n' | '\r' => {
-                parse_error("Invalid character");
-                i += 1;
-            },
+    for (i, c) in input.char_indices() {
+        match c {
+            '\t' | '\n' | '\r' => parse_error("Invalid character"),
             _ => {
-                let range = input.char_range_at(i);
-                if range.ch == '%' {
+                if c == '%' {
                     if !starts_with_2_hex(input.slice_from(i + 1)) {
                         parse_error("Invalid percent-encoded sequence")
                     }
-                } else if !is_url_code_point(range.ch) {
+                } else if !is_url_code_point(c) {
                     parse_error("Non-URL code point")
                 }
 
-                utf8_percent_encode(input.slice(i, range.next), SimpleEncodeSet, &mut fragment);
-                i = range.next;
+                utf8_percent_encode(input.slice(i, i + c.len_utf8_bytes()),
+                                    SimpleEncodeSet, &mut fragment);
             }
         }
     }
@@ -643,8 +607,8 @@ fn parse_fragment<'a>(input: &'a str) -> String {
 
 
 #[inline]
-fn is_ascii_alpha(byte: u8) -> bool {
-    match byte as char {
+fn starts_with_ascii_alpha(string: &str) -> bool {
+    match string.char_at(0) {
         'a'..'z' | 'A'..'Z' => true,
         _ => false,
     }
@@ -652,8 +616,8 @@ fn is_ascii_alpha(byte: u8) -> bool {
 
 #[inline]
 fn is_ascii_hex_digit(byte: u8) -> bool {
-    match byte as char {
-        'a'..'f' | 'A'..'F' | '0'..'9' => true,
+    match byte {
+        b'a'..b'f' | b'A'..b'F' | b'0'..b'9' => true,
         _ => false,
     }
 }

+ 20 - 20
src/url.rs

@@ -211,8 +211,8 @@ impl Ipv6Address {
         let mut piece_pointer = 0u;
         let mut compress_pointer = None;
         let mut i = 0u;
-        if input[0] == ':' as u8 {
-            if input[1] != ':' as u8 {
+        if input[0] == b':' {
+            if input[1] != b':' {
                 return Err("Invalid IPv6 address")
             }
             i = 2;
@@ -224,7 +224,7 @@ impl Ipv6Address {
             if piece_pointer == 8 {
                 return Err("Invalid IPv6 address")
             }
-            if input[i] == ':' as u8 {
+            if input[i] == b':' {
                 if compress_pointer.is_some() {
                     return Err("Invalid IPv6 address")
                 }
@@ -246,15 +246,15 @@ impl Ipv6Address {
                 }
             }
             if i < len {
-                match input[i] as char {
-                    '.' => {
+                match input[i] {
+                    b'.' => {
                         if i == start {
                             return Err("Invalid IPv6 address")
                         }
                         i = start;
                         is_ip_v4 = true;
                     },
-                    ':' => {
+                    b':' => {
                         i += 1;
                         if i == len {
                             return Err("Invalid IPv6 address")
@@ -279,7 +279,7 @@ impl Ipv6Address {
                 let mut value = 0u16;
                 while i < len {
                     let digit = match input[i] {
-                        c @ 0x30 .. 0x39 => c - 0x30,  // 0..9
+                        c @ b'0' .. b'9' => c - b'0',
                         _ => break
                     };
                     value = value * 10 + digit as u16;
@@ -287,7 +287,7 @@ impl Ipv6Address {
                         return Err("Invalid IPv6 address")
                     }
                 }
-                if dots_seen < 3 && !(i < len && input[i] == '.' as u8) {
+                if dots_seen < 3 && !(i < len && input[i] == b'.') {
                     return Err("Invalid IPv6 address")
                 }
                 pieces[piece_pointer] = pieces[piece_pointer] * 0x100 + value;
@@ -380,9 +380,9 @@ fn longest_zero_sequence(pieces: &[u16, ..8]) -> (int, int) {
 #[inline]
 fn from_hex(byte: u8) -> Option<u8> {
     match byte {
-        0x30 .. 0x39 => Some(byte - 0x30),  // 0..9
-        0x41 .. 0x46 => Some(byte + 10 - 0x41),  // A..F
-        0x61 .. 0x66 => Some(byte + 10 - 0x61),  // a..f
+        b'0' .. b'9' => Some(byte - b'0'),  // 0..9
+        b'A' .. b'F' => Some(byte + 10 - b'A'),  // A..F
+        b'a' .. b'f' => Some(byte + 10 - b'a'),  // a..f
         _ => None
     }
 }
@@ -390,8 +390,8 @@ fn from_hex(byte: u8) -> Option<u8> {
 #[inline]
 fn to_hex_upper(value: u8) -> u8 {
     match value {
-        0 .. 9 => value + 0x30,
-        10 .. 15 => value - 10 + 0x41,
+        0 .. 9 => b'0' + value,
+        10 .. 15 => b'A' + value - 10,
         _ => fail!()
     }
 }
@@ -413,14 +413,14 @@ fn utf8_percent_encode(input: &str, encode_set: EncodeSet, output: &mut String)
     use Password = self::PasswordEncodeSet;
     use Username = self::UsernameEncodeSet;
     for byte in input.bytes() {
-        if byte < 0x20 || byte > 0x7E || match byte as char {
-            ' ' | '"' | '#' | '<' | '>' | '?' | '`'
+        if byte < 0x20 || byte > 0x7E || match byte {
+            b' ' | b'"' | b'#' | b'<' | b'>' | b'?' | b'`'
             => is_match!(encode_set, Default | UserInfo | Password | Username),
-            '@'
+            b'@'
             => is_match!(encode_set, UserInfo | Password | Username),
-            '/' | '\\'
+            b'/' | b'\\'
             => is_match!(encode_set, Password | Username),
-            ':'
+            b':'
             => is_match!(encode_set, Username),
             _ => false,
         } {
@@ -436,7 +436,7 @@ fn utf8_percent_encode(input: &str, encode_set: EncodeSet, output: &mut String)
 fn percent_encode_byte(byte: u8, output: &mut String) {
     unsafe {
         output.push_bytes([
-            '%' as u8, to_hex_upper(byte >> 4), to_hex_upper(byte & 0x0F)
+            b'%', to_hex_upper(byte >> 4), to_hex_upper(byte & 0x0F)
         ])
     }
 }
@@ -448,7 +448,7 @@ fn percent_decode(input: &[u8]) -> Vec<u8> {
     let mut i = 0u;
     while i < input.len() {
         let c = input[i];
-        if c == ('%' as u8) && i + 2 < input.len() {
+        if c == b'%' && i + 2 < input.len() {
             match (from_hex(input[i + 1]), from_hex(input[i + 2])) {
                 (Some(h), Some(l)) => {
                     output.push(h * 0x10 + l);