about summary refs log tree commit diff
path: root/src/libcore/char.rs
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2014-10-31 16:20:41 -0700
committerBrian Anderson <banderson@mozilla.com>2014-11-21 13:18:08 -0800
commitaad246160451aacc2f7a707c028bdf44e77ad38d (patch)
tree0caee1d89bc0703990a241775aae0bff49d84b01 /src/libcore/char.rs
parentca1820b1fce5aa803ccc757e79dd659f599d1516 (diff)
core: Convert Char::escape_default, escape_unicode to iterators
[breaking-change]
Diffstat (limited to 'src/libcore/char.rs')
-rw-r--r--src/libcore/char.rs129
1 files changed, 95 insertions, 34 deletions
diff --git a/src/libcore/char.rs b/src/libcore/char.rs
index 55d2424eba6..1210465098a 100644
--- a/src/libcore/char.rs
+++ b/src/libcore/char.rs
@@ -17,7 +17,7 @@
 
 use mem::transmute;
 use option::{None, Option, Some};
-use iter::range_step;
+use iter::{range_step, Iterator, RangeStep};
 use slice::SlicePrelude;
 
 // UTF-8 ranges and tags for encoding characters
@@ -165,7 +165,9 @@ pub fn from_digit(num: uint, radix: uint) -> Option<char> {
 ///
 #[deprecated = "use the Char::escape_unicode method"]
 pub fn escape_unicode(c: char, f: |char|) {
-    c.escape_unicode(f)
+    for char in c.escape_unicode() {
+        f(char);
+    }
 }
 
 ///
@@ -182,7 +184,9 @@ pub fn escape_unicode(c: char, f: |char|) {
 ///
 #[deprecated = "use the Char::escape_default method"]
 pub fn escape_default(c: char, f: |char|) {
-    c.escape_default(f)
+    for c in c.escape_default() {
+        f(c);
+    }
 }
 
 /// Returns the amount of bytes this `char` would need if encoded in UTF-8
@@ -266,7 +270,7 @@ pub trait Char {
     /// * Characters in [0x100,0xffff] get 4-digit escapes: `\\uNNNN`.
     /// * Characters above 0x10000 get 8-digit escapes: `\\UNNNNNNNN`.
     #[unstable = "pending error conventions, trait organization"]
-    fn escape_unicode(self, f: |char|);
+    fn escape_unicode(self) -> UnicodeEscapedChars;
 
     /// Returns a 'default' ASCII and C++11-like literal escape of a
     /// character.
@@ -281,7 +285,7 @@ pub trait Char {
     /// * Any other chars in the range [0x20,0x7e] are not escaped.
     /// * Any other chars are given hex Unicode escapes; see `escape_unicode`.
     #[unstable = "pending error conventions, trait organization"]
-    fn escape_default(self, f: |char|);
+    fn escape_default(self) -> DefaultEscapedChars;
 
     /// Returns the amount of bytes this character would need if encoded in
     /// UTF-8.
@@ -351,38 +355,23 @@ impl Char for char {
     fn from_u32(i: u32) -> Option<char> { from_u32(i) }
 
     #[unstable = "pending error conventions, trait organization"]
-    fn escape_unicode(self, f: |char|) {
-        // avoid calling str::to_str_radix because we don't really need to allocate
-        // here.
-        f('\\');
-        let pad = match () {
-            _ if self <= '\xff'    => { f('x'); 2 }
-            _ if self <= '\uffff'  => { f('u'); 4 }
-            _                   => { f('U'); 8 }
-        };
-        for offset in range_step::<i32>(4 * (pad - 1), -1, -4) {
-            let offset = offset as uint;
-            unsafe {
-                match ((self as i32) >> offset) & 0xf {
-                    i @ 0 ... 9 => { f(transmute('0' as i32 + i)); }
-                    i => { f(transmute('a' as i32 + (i - 10))); }
-                }
-            }
-        }
+    fn escape_unicode(self) -> UnicodeEscapedChars {
+        UnicodeEscapedChars { c: self, state: UnicodeEscapedCharsState::Backslash }
     }
 
     #[unstable = "pending error conventions, trait organization"]
-    fn escape_default(self, f: |char|) {
-        match self {
-            '\t' => { f('\\'); f('t'); }
-            '\r' => { f('\\'); f('r'); }
-            '\n' => { f('\\'); f('n'); }
-            '\\' => { f('\\'); f('\\'); }
-            '\'' => { f('\\'); f('\''); }
-            '"'  => { f('\\'); f('"'); }
-            '\x20' ... '\x7e' => { f(self); }
-            _ => self.escape_unicode(f),
-        }
+    fn escape_default(self) -> DefaultEscapedChars {
+        let init_state = match self {
+            '\t' => DefaultEscapedCharsState::Backslash('t'),
+            '\r' => DefaultEscapedCharsState::Backslash('r'),
+            '\n' => DefaultEscapedCharsState::Backslash('n'),
+            '\\' => DefaultEscapedCharsState::Backslash('\\'),
+            '\'' => DefaultEscapedCharsState::Backslash('\''),
+            '"'  => DefaultEscapedCharsState::Backslash('"'),
+            '\x20' ... '\x7e' => DefaultEscapedCharsState::Char(self),
+            _ => DefaultEscapedCharsState::Unicode(self.escape_unicode())
+        };
+        DefaultEscapedChars { state: init_state }
     }
 
     #[inline]
@@ -456,3 +445,75 @@ impl Char for char {
         }
     }
 }
+
+/// An iterator over the characters that represent a `char`, as escaped by
+/// Rust's unicode escaping rules.
+pub struct UnicodeEscapedChars {
+    c: char,
+    state: UnicodeEscapedCharsState
+}
+
+enum UnicodeEscapedCharsState {
+    Backslash,
+    Type,
+    Value(RangeStep<i32>),
+}
+
+impl Iterator<char> for UnicodeEscapedChars {
+    fn next(&mut self) -> Option<char> {
+        match self.state {
+            UnicodeEscapedCharsState::Backslash => {
+                self.state = UnicodeEscapedCharsState::Type;
+                Some('\\')
+            }
+            UnicodeEscapedCharsState::Type => {
+                let (typechar, pad) = if self.c <= '\x7f' { ('x', 2) }
+                                      else if self.c <= '\uffff' { ('u', 4) }
+                                      else { ('U', 8) };
+                self.state = UnicodeEscapedCharsState::Value(range_step(4 * (pad - 1), -1, -4i32));
+                Some(typechar)
+            }
+            UnicodeEscapedCharsState::Value(ref mut range_step) => match range_step.next() {
+                Some(offset) => {
+                    let offset = offset as uint;
+                    let v = match ((self.c as i32) >> offset) & 0xf {
+                        i @ 0 ... 9 => '0' as i32 + i,
+                        i => 'a' as i32 + (i - 10)
+                    };
+                    Some(unsafe { transmute(v) })
+                }
+                None => None
+            }
+        }
+    }
+}
+
+/// An iterator over the characters that represent a `char`, escaped
+/// for maximum portability.
+pub struct DefaultEscapedChars {
+    state: DefaultEscapedCharsState
+}
+
+enum DefaultEscapedCharsState {
+    Backslash(char),
+    Char(char),
+    Done,
+    Unicode(UnicodeEscapedChars),
+}
+
+impl Iterator<char> for DefaultEscapedChars {
+    fn next(&mut self) -> Option<char> {
+        match self.state {
+            DefaultEscapedCharsState::Backslash(c) => {
+                self.state = DefaultEscapedCharsState::Char(c);
+                Some('\\')
+            }
+            DefaultEscapedCharsState::Char(c) => {
+                self.state = DefaultEscapedCharsState::Done;
+                Some(c)
+            }
+            DefaultEscapedCharsState::Done => None,
+            DefaultEscapedCharsState::Unicode(ref mut iter) => iter.next()
+        }
+    }
+}