about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorHuon Wilson <dbau.pp+github@gmail.com>2014-02-17 09:57:56 +1100
committerHuon Wilson <dbau.pp+github@gmail.com>2014-02-18 00:00:38 +1100
commit4f841ee1509fafdf688a3898e01560ae29ee7836 (patch)
tree109fd76eab98758829ab5ebde99d8a8477b1853e /src/libstd
parent35b1b62ddfc31c2e52b65c2f908c0fcbc6465de5 (diff)
downloadrust-4f841ee1509fafdf688a3898e01560ae29ee7836.tar.gz
rust-4f841ee1509fafdf688a3898e01560ae29ee7836.zip
std: make str::from_utf16 return an Option.
The rest of the codebase is moving toward avoiding `fail!` so we do it
here too!
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/os.rs15
-rw-r--r--src/libstd/str.rs54
2 files changed, 46 insertions, 23 deletions
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index 719ed62d03d..31e88905b30 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -88,7 +88,7 @@ pub fn getcwd() -> Path {
             fail!();
         }
     }
-    Path::new(str::from_utf16(buf))
+    Path::new(str::from_utf16(buf).expect("GetCurrentDirectoryW returned invalid UTF-16"))
 }
 
 #[cfg(windows)]
@@ -124,7 +124,12 @@ pub mod win32 {
                 }
                 if k != 0 && done {
                     let sub = buf.slice(0, k as uint);
-                    res = option::Some(str::from_utf16(sub));
+                    // We want to explicitly catch the case when the
+                    // closure returned invalid UTF-16, rather than
+                    // set `res` to None and continue.
+                    let s = str::from_utf16(sub)
+                        .expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
+                    res = option::Some(s)
                 }
             }
             return res;
@@ -739,7 +744,7 @@ pub fn last_os_error() -> ~str {
                 fail!("[{}] FormatMessage failure", errno());
             }
 
-            str::from_utf16(buf)
+            str::from_utf16(buf).expect("FormatMessageW returned invalid UTF-16")
         }
     }
 
@@ -828,8 +833,8 @@ fn real_args() -> ~[~str] {
             while *ptr.offset(len as int) != 0 { len += 1; }
 
             // Push it onto the list.
-            args.push(vec::raw::buf_as_slice(ptr, len,
-                                             str::from_utf16));
+            let opt_s = vec::raw::buf_as_slice(ptr, len, str::from_utf16);
+            args.push(opt_s.expect("CommandLineToArgvW returned invalid UTF-16"));
         }
     }
 
diff --git a/src/libstd/str.rs b/src/libstd/str.rs
index 34bcb083134..20321dad600 100644
--- a/src/libstd/str.rs
+++ b/src/libstd/str.rs
@@ -920,11 +920,8 @@ pub fn utf16_items<'a>(v: &'a [u16]) -> UTF16Items<'a> {
     UTF16Items { iter : v.iter() }
 }
 
-/// Decode a UTF-16 encoded vector `v` into a string.
-///
-/// # Failure
-///
-/// Fails on invalid UTF-16 data.
+/// Decode a UTF-16 encoded vector `v` into a string, returning `None`
+/// if `v` contains any invalid data.
 ///
 /// # Example
 ///
@@ -932,17 +929,23 @@ pub fn utf16_items<'a>(v: &'a [u16]) -> UTF16Items<'a> {
 /// use std::str;
 ///
 /// // 𝄞music
-/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075,
-///          0x0073, 0x0069, 0x0063];
-/// assert_eq!(str::from_utf16(v), ~"𝄞music");
+/// let mut v = [0xD834, 0xDD1E, 0x006d, 0x0075,
+///              0x0073, 0x0069, 0x0063];
+/// assert_eq!(str::from_utf16(v), Some(~"𝄞music"));
+///
+/// // 𝄞mu<invalid>ic
+/// v[4] = 0xD800;
+/// assert_eq!(str::from_utf16(v), None);
 /// ```
-pub fn from_utf16(v: &[u16]) -> ~str {
-    utf16_items(v).map(|c| {
-            match c {
-                ScalarValue(c) => c,
-                LoneSurrogate(u) => fail!("from_utf16: found lone surrogate {}", u)
-            }
-        }).collect()
+pub fn from_utf16(v: &[u16]) -> Option<~str> {
+    let mut s = with_capacity(v.len() / 2);
+    for c in utf16_items(v) {
+        match c {
+            ScalarValue(c) => s.push_char(c),
+            LoneSurrogate(_) => return None
+        }
+    }
+    Some(s)
 }
 
 /// Decode a UTF-16 encoded vector `v` into a string, replacing
@@ -3834,15 +3837,30 @@ mod tests {
             assert!(is_utf16(u));
             assert_eq!(s.to_utf16(), u);
 
-            assert_eq!(from_utf16(u), s);
+            assert_eq!(from_utf16(u).unwrap(), s);
             assert_eq!(from_utf16_lossy(u), s);
 
-            assert_eq!(from_utf16(s.to_utf16()), s);
-            assert_eq!(from_utf16(u).to_utf16(), u);
+            assert_eq!(from_utf16(s.to_utf16()).unwrap(), s);
+            assert_eq!(from_utf16(u).unwrap().to_utf16(), u);
         }
     }
 
     #[test]
+    fn test_utf16_invalid() {
+        // completely positive cases tested above.
+        // lead + eof
+        assert_eq!(from_utf16([0xD800]), None);
+        // lead + lead
+        assert_eq!(from_utf16([0xD800, 0xD800]), None);
+
+        // isolated trail
+        assert_eq!(from_utf16([0x0061, 0xDC00]), None);
+
+        // general
+        assert_eq!(from_utf16([0xD800, 0xd801, 0xdc8b, 0xD800]), None);
+    }
+
+    #[test]
     fn test_utf16_lossy() {
         // completely positive cases tested above.
         // lead + eof