]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #14613 : schmee/rust/utf16-iterator, r=huonw
authorbors <bors@rust-lang.org>
Mon, 30 Jun 2014 19:26:35 +0000 (19:26 +0000)
committerbors <bors@rust-lang.org>
Mon, 30 Jun 2014 19:26:35 +0000 (19:26 +0000)
Closes #14358.

~~The tests are not yet moved to `utf16_iter`, so this probably won't compile. I'm submitting this PR anyway so it can be reviewed and since it was mentioned in #14611.~~ EDIT: Tests now use `utf16_iter`.

This deprecates `.to_utf16`. `x.to_utf16()` should be replaced by either `x.utf16_iter().collect::<Vec<u16>>()` (the type annotation may be optional), or just `x.utf16_iter()` directly, if it can be used in an iterator context.

[breaking-change]

cc @huonw

1  2 
src/libcollections/str.rs
src/libcore/str.rs
src/libnative/io/process.rs
src/libstd/os.rs

index b5424d1683fca566bba7a5296876c36c10113cea,e07281523f4b63fb5b24ac5a9e50c2d798643c6c..10309adef20d9faafa8c8de2d610b66e30eeef9e
@@@ -572,8 -572,8 +572,8 @@@ impl<'a> Eq for MaybeOwned<'a> {
  
  impl<'a> PartialOrd for MaybeOwned<'a> {
      #[inline]
 -    fn lt(&self, other: &MaybeOwned) -> bool {
 -        self.as_slice().lt(&other.as_slice())
 +    fn partial_cmp(&self, other: &MaybeOwned) -> Option<Ordering> {
 +        Some(self.cmp(other))
      }
  }
  
@@@ -803,15 -803,9 +803,9 @@@ pub trait StrAllocating: Str 
      }
  
      /// Converts to a vector of `u16` encoded as UTF-16.
+     #[deprecated = "use `utf16_units` instead"]
      fn to_utf16(&self) -> Vec<u16> {
-         let me = self.as_slice();
-         let mut u = Vec::new();
-         for ch in me.chars() {
-             let mut buf = [0u16, ..2];
-             let n = ch.encode_utf16(buf /* as mut slice! */);
-             u.push_all(buf.slice_to(n));
-         }
-         u
+         self.as_slice().utf16_units().collect::<Vec<u16>>()
      }
  
      /// Given a string, make a new string with repeated copies of it.
@@@ -1103,7 -1097,7 +1097,7 @@@ mod tests 
          assert_eq!("bc", unsafe {raw::slice_bytes("abc", 1, 3)});
          assert_eq!("", unsafe {raw::slice_bytes("abc", 1, 1)});
          fn a_million_letter_a() -> String {
 -            let mut i = 0;
 +            let mut i = 0u;
              let mut rs = String::new();
              while i < 100000 {
                  rs.push_str("aaaaaaaaaa");
              rs
          }
          fn half_a_million_letter_a() -> String {
 -            let mut i = 0;
 +            let mut i = 0u;
              let mut rs = String::new();
              while i < 100000 {
                  rs.push_str("aaaaa");
          assert_eq!("华", data.slice(30, 33));
  
          fn a_million_letter_x() -> String {
 -            let mut i = 0;
 +            let mut i = 0u;
              let mut rs = String::new();
              while i < 100000 {
                  rs.push_str("华华华华华华华华华华");
              rs
          }
          fn half_a_million_letter_x() -> String {
 -            let mut i = 0;
 +            let mut i = 0u;
              let mut rs = String::new();
              while i < 100000 {
                  rs.push_str("华华华华华");
  
          for p in pairs.iter() {
              let (s, u) = (*p).clone();
+             let s_as_utf16 = s.as_slice().utf16_units().collect::<Vec<u16>>();
+             let u_as_string = from_utf16(u.as_slice()).unwrap();
              assert!(is_utf16(u.as_slice()));
-             assert_eq!(s.to_utf16(), u);
+             assert_eq!(s_as_utf16, u);
  
-             assert_eq!(from_utf16(u.as_slice()).unwrap(), s);
+             assert_eq!(u_as_string, s);
              assert_eq!(from_utf16_lossy(u.as_slice()), s);
  
-             assert_eq!(from_utf16(s.to_utf16().as_slice()).unwrap(), s);
-             assert_eq!(from_utf16(u.as_slice()).unwrap().to_utf16(), u);
+             assert_eq!(from_utf16(s_as_utf16.as_slice()).unwrap(), s);
+             assert_eq!(u_as_string.as_slice().utf16_units().collect::<Vec<u16>>(), u);
          }
      }
  
diff --combined src/libcore/str.rs
index de23e04393be1bb99e22a3c66d2a0c79d94160e4,e7174944a2143383e4a39e52e88226f055d623ff..b336c57efa07228ad8d6d54518b3e6af46904079
@@@ -16,6 -16,7 +16,7 @@@
  
  use mem;
  use char;
+ use char::Char;
  use clone::Clone;
  use cmp;
  use cmp::{PartialEq, Eq};
@@@ -24,7 -25,7 +25,7 @@@ use default::Default
  use iter::{Filter, Map, Iterator};
  use iter::{DoubleEndedIterator, ExactSize};
  use iter::range;
- use num::Saturating;
+ use num::{CheckedMul, Saturating};
  use option::{None, Option, Some};
  use raw::Repr;
  use slice::ImmutableVector;
@@@ -557,6 -558,41 +558,41 @@@ impl<'a> Iterator<&'a str> for StrSplit
      }
  }
  
+ /// External iterator for a string's UTF16 codeunits.
+ /// Use with the `std::iter` module.
+ #[deriving(Clone)]
+ pub struct Utf16CodeUnits<'a> {
+     chars: Chars<'a>,
+     extra: u16
+ }
+ impl<'a> Iterator<u16> for Utf16CodeUnits<'a> {
+     #[inline]
+     fn next(&mut self) -> Option<u16> {
+         if self.extra != 0 {
+             let tmp = self.extra;
+             self.extra = 0;
+             return Some(tmp);
+         }
+         let mut buf = [0u16, ..2];
+         self.chars.next().map(|ch| {
+             let n = ch.encode_utf16(buf /* as mut slice! */);
+             if n == 2 { self.extra = buf[1]; }
+             buf[0]
+         })
+     }
+     #[inline]
+     fn size_hint(&self) -> (uint, Option<uint>) {
+         let (low, high) = self.chars.size_hint();
+         // every char gets either one u16 or two u16,
+         // so this iterator is between 1 or 2 times as
+         // long as the underlying iterator.
+         (low, high.and_then(|n| n.checked_mul(&2)))
+     }
+ }
  /*
  Section: Comparing strings
  */
@@@ -579,12 -615,20 +615,12 @@@ fn eq_slice_(a: &str, b: &str) -> bool 
  /// Bytewise slice equality
  /// NOTE: This function is (ab)used in rustc::middle::trans::_match
  /// to compare &[u8] byte slices that are not necessarily valid UTF-8.
 -#[cfg(not(test))]
  #[lang="str_eq"]
  #[inline]
  pub fn eq_slice(a: &str, b: &str) -> bool {
      eq_slice_(a, b)
  }
  
 -/// Bytewise slice equality
 -#[cfg(test)]
 -#[inline]
 -pub fn eq_slice(a: &str, b: &str) -> bool {
 -    eq_slice_(a, b)
 -}
 -
  /*
  Section: Misc
  */
@@@ -926,12 -970,13 +962,12 @@@ pub mod raw 
  Section: Trait implementations
  */
  
 -#[cfg(not(test))]
  #[allow(missing_doc)]
  pub mod traits {
      use cmp::{Ord, Ordering, Less, Equal, Greater, PartialEq, PartialOrd, Equiv, Eq};
      use collections::Collection;
      use iter::Iterator;
 -    use option::{Some, None};
 +    use option::{Option, Some, None};
      use str::{Str, StrSlice, eq_slice};
  
      impl<'a> Ord for &'a str {
  
      impl<'a> PartialOrd for &'a str {
          #[inline]
 -        fn lt(&self, other: & &'a str) -> bool { self.cmp(other) == Less }
 +        fn partial_cmp(&self, other: &&'a str) -> Option<Ordering> {
 +            Some(self.cmp(other))
 +        }
      }
  
      impl<'a, S: Str> Equiv<S> for &'a str {
      }
  }
  
 -#[cfg(test)]
 -pub mod traits {}
 -
  /// Any string that can be represented as a slice
  pub trait Str {
      /// Work with `self` as a slice.
@@@ -1609,6 -1655,9 +1645,9 @@@ pub trait StrSlice<'a> 
      /// and that it is not reallocated (e.g. by pushing to the
      /// string).
      fn as_ptr(&self) -> *const u8;
+     /// Return an iterator of `u16` over the string encoded as UTF-16.
+     fn utf16_units(&self) -> Utf16CodeUnits<'a>;
  }
  
  impl<'a> StrSlice<'a> for &'a str {
      fn as_ptr(&self) -> *const u8 {
          self.repr().data
      }
+     #[inline]
+     fn utf16_units(&self) -> Utf16CodeUnits<'a> {
+         Utf16CodeUnits{ chars: self.chars(), extra: 0}
+     }
  }
  
  impl<'a> Default for &'a str {
index b1c0d9a15069385582c6afdc2543330f8bf62a78,3d248e159a2ea80e732753a94e9364a7d55bc59b..6fab73115cf9a5e2dcd1ddf7847f2796b4f44e4d
@@@ -294,6 -294,8 +294,8 @@@ fn spawn_process_os(cfg: ProcessConfig
      use libc::funcs::extra::msvcrt::get_osfhandle;
  
      use std::mem;
+     use std::iter::Iterator;
+     use std::str::StrSlice;
  
      if cfg.gid.is_some() || cfg.uid.is_some() {
          return Err(IoError {
                          lpSecurityDescriptor: ptr::mut_null(),
                          bInheritHandle: 1,
                      };
-                     let filename = "NUL".to_utf16().append_one(0);
+                     let filename: Vec<u16> = "NUL".utf16_units().collect();
+                     let filename = filename.append_one(0);
                      *slot = libc::CreateFileW(filename.as_ptr(),
                                                access,
                                                libc::FILE_SHARE_READ |
  
          with_envp(cfg.env, |envp| {
              with_dirp(cfg.cwd, |dirp| {
-                 let mut cmd_str = cmd_str.to_utf16().append_one(0);
+                 let mut cmd_str: Vec<u16> = cmd_str.as_slice().utf16_units().collect();
+                 cmd_str = cmd_str.append_one(0);
                  let created = CreateProcessW(ptr::null(),
                                               cmd_str.as_mut_ptr(),
                                               ptr::mut_null(),
@@@ -770,7 -774,7 +774,7 @@@ fn with_envp<T>(env: Option<&[(CString
                  let kv = format!("{}={}",
                                   pair.ref0().as_str().unwrap(),
                                   pair.ref1().as_str().unwrap());
-                 blk.push_all(kv.to_utf16().as_slice());
+                 blk.extend(kv.as_slice().utf16_units());
                  blk.push(0);
              }
  
@@@ -788,7 -792,9 +792,9 @@@ fn with_dirp<T>(d: Option<&CString>, cb
        Some(dir) => {
            let dir_str = dir.as_str()
                             .expect("expected workingdirectory to be utf-8 encoded");
-           let dir_str = dir_str.to_utf16().append_one(0);
+           let dir_str: Vec<u16> = dir_str.utf16_units().collect();
+           let dir_str = dir_str.append_one(0);
            cb(dir_str.as_ptr())
        },
        None => cb(ptr::null())
@@@ -1136,7 -1142,7 +1142,7 @@@ fn waitpid(pid: pid_t, deadline: u64) -
      // which will wake up the other end at some point, so we just allow this
      // signal to be coalesced with the pending signals on the pipe.
      extern fn sigchld_handler(_signum: libc::c_int) {
 -        let msg = 1;
 +        let msg = 1i;
          match unsafe {
              libc::write(WRITE_FD, &msg as *const _ as *const libc::c_void, 1)
          } {
diff --combined src/libstd/os.rs
index e0ed8cf667b38e185089866259d642fffe08f3ed,be3b6be57b3849ef3c7da1c442d764b99ba75a54..5201a81179144e2f7658f6c3d688ff101399c754
@@@ -365,7 -365,8 +365,8 @@@ pub fn getenv(n: &str) -> Option<String
      unsafe {
          with_env_lock(|| {
              use os::win32::{fill_utf16_buf_and_decode};
-             let n = n.to_utf16().append_one(0);
+             let n: Vec<u16> = n.utf16_units().collect();
+             let n = n.append_one(0);
              fill_utf16_buf_and_decode(|buf, sz| {
                  libc::GetEnvironmentVariableW(n.as_ptr(), buf, sz)
              })
@@@ -411,8 -412,10 +412,10 @@@ pub fn setenv(n: &str, v: &str) 
  
      #[cfg(windows)]
      fn _setenv(n: &str, v: &str) {
-         let n = n.to_utf16().append_one(0);
-         let v = v.to_utf16().append_one(0);
+         let n: Vec<u16> = n.utf16_units().collect();
+         let n = n.append_one(0);
+         let v: Vec<u16> = v.utf16_units().collect();
+         let v = v.append_one(0);
          unsafe {
              with_env_lock(|| {
                  libc::SetEnvironmentVariableW(n.as_ptr(), v.as_ptr());
@@@ -437,7 -440,8 +440,8 @@@ pub fn unsetenv(n: &str) 
  
      #[cfg(windows)]
      fn _unsetenv(n: &str) {
-         let n = n.to_utf16().append_one(0);
+         let n: Vec<u16> = n.utf16_units().collect();
+         let n = n.append_one(0);
          unsafe {
              with_env_lock(|| {
                  libc::SetEnvironmentVariableW(n.as_ptr(), ptr::null());
@@@ -804,7 -808,7 +808,7 @@@ pub fn change_dir(p: &Path) -> bool 
      #[cfg(windows)]
      fn chdir(p: &Path) -> bool {
          let p = match p.as_str() {
-             Some(s) => s.to_utf16().append_one(0),
+             Some(s) => s.utf16_units().collect::<Vec<u16>>().append_one(0),
              None => return false,
          };
          unsafe {
@@@ -1816,7 -1820,7 +1820,7 @@@ mod tests 
      #[ignore]
      fn test_getenv_big() {
          let mut s = "".to_string();
 -        let mut i = 0;
 +        let mut i = 0i;
          while i < 100 {
              s.push_str("aaaaaaaaaa");
              i += 1;