Quellcode durchsuchen

Replace the c.len_utf8_bytes() hack by a custom string iterator.

Simon Sapin vor 12 Jahren
Ursprung
Commit
83f494b0f3
1 geänderte Dateien mit 44 neuen und 11 gelöschten Zeilen
  1. 44 11
      src/parser.rs

+ 44 - 11
src/parser.rs

@@ -8,6 +8,7 @@
 
 
 use std::ascii::StrAsciiExt;
+use std::str::CharRange;
 
 use encoding;
 use encoding::EncodingRef;
@@ -269,7 +270,7 @@ fn parse_userinfo<'a>(input: &'a str, parse_error: ErrorHandler)
 
     let mut username = String::new();
     let mut password = None;
-    for (i, c) in input.char_indices() {
+    for (i, c, next_i) in input.char_ranges() {
         match c {
             ':' => {
                 password = Some(try!(parse_password(input.slice_from(i + 1), parse_error)));
@@ -285,7 +286,7 @@ fn parse_userinfo<'a>(input: &'a str, parse_error: ErrorHandler)
                     try!(parse_error("Non-URL code point"));
                 }
 
-                utf8_percent_encode(input.slice(i, i + c.len_utf8_bytes()),
+                utf8_percent_encode(input.slice(i, next_i),
                                     USERINFO_ENCODE_SET, &mut username);
             }
         }
@@ -296,7 +297,7 @@ fn parse_userinfo<'a>(input: &'a str, parse_error: ErrorHandler)
 
 fn parse_password(input: &str, parse_error: ErrorHandler) -> ParseResult<String> {
     let mut password = String::new();
-    for (i, c) in input.char_indices() {
+    for (i, c, next_i) in input.char_ranges() {
         match c {
             '\t' | '\n' | '\r' => try!(parse_error("Invalid character")),
             _ => {
@@ -308,7 +309,7 @@ fn parse_password(input: &str, parse_error: ErrorHandler) -> ParseResult<String>
                     try!(parse_error("Non-URL code point"));
                 }
 
-                utf8_percent_encode(input.slice(i, i + c.len_utf8_bytes()),
+                utf8_percent_encode(input.slice(i, next_i),
                                     USERINFO_ENCODE_SET, &mut password);
             }
         }
@@ -437,13 +438,13 @@ fn parse_path<'a>(base_path: Vec<String>, input: &'a str, full_url: bool, in_fil
                   -> ParseResult<(Vec<String>, &'a str)> {
     // Relative path state
     let mut path = base_path;
-    let mut iter = input.char_indices();
+    let mut iter = input.char_ranges();
     let mut end;
     loop {
         let mut path_part = String::new();
         let mut ends_with_slash = false;
         end = input.len();
-        for (i, c) in iter {
+        for (i, c, next_i) in iter {
             match c {
                 '/' => {
                     ends_with_slash = true;
@@ -470,7 +471,7 @@ fn parse_path<'a>(base_path: Vec<String>, input: &'a str, full_url: bool, in_fil
                         try!(parse_error("Non-URL code point"));
                     }
 
-                    utf8_percent_encode(input.slice(i, i + c.len_utf8_bytes()),
+                    utf8_percent_encode(input.slice(i, next_i),
                                         DEFAULT_ENCODE_SET, &mut path_part);
                 }
             }
@@ -514,7 +515,7 @@ fn parse_scheme_data<'a>(input: &'a str, parse_error: ErrorHandler)
                          -> ParseResult<(String, &'a str)> {
     let mut scheme_data = String::new();
     let mut end = input.len();
-    for (i, c) in input.char_indices() {
+    for (i, c, next_i) in input.char_ranges() {
         match c {
             '?' | '#' => {
                 end = i;
@@ -530,7 +531,7 @@ fn parse_scheme_data<'a>(input: &'a str, parse_error: ErrorHandler)
                     try!(parse_error("Non-URL code point"));
                 }
 
-                utf8_percent_encode(input.slice(i, i + c.len_utf8_bytes()),
+                utf8_percent_encode(input.slice(i, next_i),
                                     SIMPLE_ENCODE_SET, &mut scheme_data);
             }
         }
@@ -603,7 +604,7 @@ pub fn parse_query<'a>(input: &'a str, encoding_override: EncodingRef, full_url:
 
 pub fn parse_fragment<'a>(input: &'a str, parse_error: ErrorHandler) -> ParseResult<String> {
     let mut fragment = String::new();
-    for (i, c) in input.char_indices() {
+    for (i, c, next_i) in input.char_ranges() {
         match c {
             '\t' | '\n' | '\r' => try!(parse_error("Invalid character")),
             _ => {
@@ -615,7 +616,7 @@ pub fn parse_fragment<'a>(input: &'a str, parse_error: ErrorHandler) -> ParseRes
                     try!(parse_error("Non-URL code point"));
                 }
 
-                utf8_percent_encode(input.slice(i, i + c.len_utf8_bytes()),
+                utf8_percent_encode(input.slice(i, next_i),
                                     SIMPLE_ENCODE_SET, &mut fragment);
             }
         }
@@ -680,3 +681,35 @@ fn is_url_code_point(c: char) -> bool {
 fn is_relative_scheme(scheme: &str) -> bool {
     is_match!(scheme, "ftp" | "file" | "gopher" | "http" | "https" | "ws" | "wss")
 }
+
+
+pub trait StrCharRanges<'a> {
+    fn char_ranges(&self) -> CharRanges<'a>;
+}
+
+
+impl<'a> StrCharRanges<'a> for &'a str {
+    #[inline]
+    fn char_ranges(&self) -> CharRanges<'a> {
+        CharRanges { slice: *self, position: 0 }
+    }
+}
+
+pub struct CharRanges<'a> {
+    slice: &'a str,
+    position: uint,
+}
+
+impl<'a> Iterator<(uint, char, uint)> for CharRanges<'a> {
+    #[inline]
+    fn next(&mut self) -> Option<(uint, char, uint)> {
+        if self.position == self.slice.len() {
+            None
+        } else {
+            let position = self.position;
+            let CharRange { ch, next } = self.slice.char_range_at(position);
+            self.position = next;
+            Some((position, ch, next))
+        }
+    }
+}