From d42cc130f9eaaa4b35944854c3ba34ae98d6361e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 2 Jun 2014 14:51:58 -0700 Subject: [PATCH 01/11] std: Remove the as_utf16_p functions These functions are all much better expressed via RAII using the to_utf16() method on strings. This refactoring also takes this opportunity to properly handle when filenames aren't valid unicode when passed through to the windows I/O layer by properly returning I/O errors. All previous users of the `as_utf16_p` or `as_utf16_mut_p` functions will need to convert their code to using `foo.to_utf16().append_one(0)` to get a null-terminated utf16 string. [breaking-change] --- src/libnative/io/c_win32.rs | 12 ++- src/libnative/io/file_win32.rs | 114 +++++++++++++------------ src/libnative/io/pipe_win32.rs | 132 ++++++++++++++--------------- src/libnative/io/process.rs | 45 +++++----- src/librustdoc/flock.rs | 8 +- src/libstd/os.rs | 46 ++++------ src/libstd/unstable/dynamic_lib.rs | 10 +-- 7 files changed, 178 insertions(+), 189 deletions(-) diff --git a/src/libnative/io/c_win32.rs b/src/libnative/io/c_win32.rs index 93b3ec7ccef..1ec25933eec 100644 --- a/src/libnative/io/c_win32.rs +++ b/src/libnative/io/c_win32.rs @@ -69,7 +69,6 @@ extern "system" { pub mod compat { use std::intrinsics::{atomic_store_relaxed, transmute}; use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; - use std::os::win32::as_utf16_p; extern "system" { fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; @@ -80,12 +79,11 @@ pub mod compat { // This way, calling a function in this compatibility layer (after it's loaded) shouldn't // be any slower than a regular DLL call. unsafe fn store_func(ptr: *mut T, module: &str, symbol: &str, fallback: T) { - as_utf16_p(module, |module| { - symbol.with_c_str(|symbol| { - let handle = GetModuleHandleW(module); - let func: Option = transmute(GetProcAddress(handle, symbol)); - atomic_store_relaxed(ptr, func.unwrap_or(fallback)) - }) + let module = module.to_utf16().append_one(0); + symbol.with_c_str(|symbol| { + let handle = GetModuleHandleW(module.as_ptr()); + let func: Option = transmute(GetProcAddress(handle, symbol)); + atomic_store_relaxed(ptr, func.unwrap_or(fallback)) }) } diff --git a/src/libnative/io/file_win32.rs b/src/libnative/io/file_win32.rs index 2a5b78e5506..0e6c5c744f4 100644 --- a/src/libnative/io/file_win32.rs +++ b/src/libnative/io/file_win32.rs @@ -15,7 +15,7 @@ use libc::{c_int, c_void}; use libc; use std::c_str::CString; use std::mem; -use std::os::win32::{as_utf16_p, fill_utf16_buf_and_decode}; +use std::os::win32::fill_utf16_buf_and_decode; use std::ptr; use std::rt::rtio; use std::rt::rtio::IoResult; @@ -253,6 +253,17 @@ impl Drop for Inner { } } +pub fn to_utf16(s: &CString) -> IoResult> { + match s.as_str() { + Some(s) => Ok(s.to_utf16().append_one(0)), + None => Err(IoError { + code: libc::ERROR_INVALID_NAME as uint, + extra: 0, + detail: Some("valid unicode input required".to_str()), + }) + } +} + pub fn open(path: &CString, fm: rtio::FileMode, fa: rtio::FileAccess) -> IoResult { // Flags passed to open_osfhandle @@ -299,15 +310,16 @@ pub fn open(path: &CString, fm: rtio::FileMode, fa: rtio::FileAccess) // Compat with unix, this allows opening directories (see libuv) dwFlagsAndAttributes |= libc::FILE_FLAG_BACKUP_SEMANTICS; - let handle = as_utf16_p(path.as_str().unwrap(), |buf| unsafe { - libc::CreateFileW(buf, + let path = try!(to_utf16(path)); + let handle = unsafe { + libc::CreateFileW(path.as_ptr(), dwDesiredAccess, dwShareMode, ptr::mut_null(), dwCreationDisposition, dwFlagsAndAttributes, ptr::mut_null()) - }); + }; if handle == libc::INVALID_HANDLE_VALUE as libc::HANDLE { Err(super::last_error()) } else { @@ -324,11 +336,10 @@ pub fn open(path: &CString, fm: rtio::FileMode, fa: rtio::FileAccess) } pub fn mkdir(p: &CString, _mode: uint) -> IoResult<()> { + let p = try!(to_utf16(p)); super::mkerr_winbool(unsafe { // FIXME: turn mode into something useful? #2623 - as_utf16_p(p.as_str().unwrap(), |buf| { - libc::CreateDirectoryW(buf, ptr::mut_null()) - }) + libc::CreateDirectoryW(p.as_ptr(), ptr::mut_null()) }) } @@ -351,9 +362,11 @@ pub fn readdir(p: &CString) -> IoResult> { let star = Path::new(unsafe { CString::new(p.with_ref(|p| p), false) }).join("*"); - as_utf16_p(star.as_str().unwrap(), |path_ptr| unsafe { + let path = try!(to_utf16(&star.to_c_str())); + + unsafe { let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint); - let find_handle = libc::FindFirstFileW(path_ptr, wfd_ptr as libc::HANDLE); + let find_handle = libc::FindFirstFileW(path.as_ptr(), wfd_ptr as libc::HANDLE); if find_handle as libc::c_int != libc::INVALID_HANDLE_VALUE { let mut paths = vec!(); let mut more_files = 1 as libc::c_int; @@ -377,37 +390,35 @@ pub fn readdir(p: &CString) -> IoResult> { } else { Err(super::last_error()) } - }) + } } pub fn unlink(p: &CString) -> IoResult<()> { + let p = try!(to_utf16(p)); super::mkerr_winbool(unsafe { - as_utf16_p(p.as_str().unwrap(), |buf| { - libc::DeleteFileW(buf) - }) + libc::DeleteFileW(p.as_ptr()) }) } pub fn rename(old: &CString, new: &CString) -> IoResult<()> { + let old = try!(to_utf16(old)); + let new = try!(to_utf16(new)); super::mkerr_winbool(unsafe { - as_utf16_p(old.as_str().unwrap(), |old| { - as_utf16_p(new.as_str().unwrap(), |new| { - libc::MoveFileExW(old, new, libc::MOVEFILE_REPLACE_EXISTING) - }) - }) + libc::MoveFileExW(old.as_ptr(), new.as_ptr(), + libc::MOVEFILE_REPLACE_EXISTING) }) } pub fn chmod(p: &CString, mode: uint) -> IoResult<()> { - super::mkerr_libc(as_utf16_p(p.as_str().unwrap(), |p| unsafe { - libc::wchmod(p, mode as libc::c_int) - })) + let p = try!(to_utf16(p)); + super::mkerr_libc(unsafe { + libc::wchmod(p.as_ptr(), mode.bits() as libc::c_int) + }) } pub fn rmdir(p: &CString) -> IoResult<()> { - super::mkerr_libc(as_utf16_p(p.as_str().unwrap(), |p| unsafe { - libc::wrmdir(p) - })) + let p = try!(to_utf16(p)); + super::mkerr_libc(unsafe { libc::wrmdir(p.as_ptr()) }) } pub fn chown(_p: &CString, _uid: int, _gid: int) -> IoResult<()> { @@ -418,16 +429,15 @@ pub fn chown(_p: &CString, _uid: int, _gid: int) -> IoResult<()> { pub fn readlink(p: &CString) -> IoResult { // FIXME: I have a feeling that this reads intermediate symlinks as well. use io::c::compat::kernel32::GetFinalPathNameByHandleW; + let p = try!(to_utf16(p)); let handle = unsafe { - as_utf16_p(p.as_str().unwrap(), |p| { - libc::CreateFileW(p, - libc::GENERIC_READ, - libc::FILE_SHARE_READ, - ptr::mut_null(), - libc::OPEN_EXISTING, - libc::FILE_ATTRIBUTE_NORMAL, - ptr::mut_null()) - }) + libc::CreateFileW(p.as_ptr(), + libc::GENERIC_READ, + libc::FILE_SHARE_READ, + ptr::mut_null(), + libc::OPEN_EXISTING, + libc::FILE_ATTRIBUTE_NORMAL, + ptr::mut_null()) }; if handle as int == libc::INVALID_HANDLE_VALUE as int { return Err(super::last_error()) @@ -453,19 +463,19 @@ pub fn readlink(p: &CString) -> IoResult { pub fn symlink(src: &CString, dst: &CString) -> IoResult<()> { use io::c::compat::kernel32::CreateSymbolicLinkW; - super::mkerr_winbool(as_utf16_p(src.as_str().unwrap(), |src| { - as_utf16_p(dst.as_str().unwrap(), |dst| { - unsafe { CreateSymbolicLinkW(dst, src, 0) } - }) as libc::BOOL - })) + let src = try!(to_utf16(src)); + let dst = try!(to_utf16(dst)); + super::mkerr_winbool(unsafe { + CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), 0) as libc::BOOL + }) } pub fn link(src: &CString, dst: &CString) -> IoResult<()> { - super::mkerr_winbool(as_utf16_p(src.as_str().unwrap(), |src| { - as_utf16_p(dst.as_str().unwrap(), |dst| { - unsafe { libc::CreateHardLinkW(dst, src, ptr::mut_null()) } - }) - })) + let src = try!(to_utf16(src)); + let dst = try!(to_utf16(dst)); + super::mkerr_winbool(unsafe { + libc::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::mut_null()) + }) } fn mkstat(stat: &libc::stat) -> rtio::FileStat { @@ -491,12 +501,11 @@ fn mkstat(stat: &libc::stat) -> rtio::FileStat { pub fn stat(p: &CString) -> IoResult { let mut stat: libc::stat = unsafe { mem::zeroed() }; - as_utf16_p(p.as_str().unwrap(), |up| { - match unsafe { libc::wstat(up, &mut stat) } { - 0 => Ok(mkstat(&stat)), - _ => Err(super::last_error()), - } - }) + let p = try!(to_utf16(p)); + match unsafe { libc::wstat(p.as_ptr(), &mut stat) } { + 0 => Ok(mkstat(&stat)), + _ => Err(super::last_error()), + } } pub fn lstat(_p: &CString) -> IoResult { @@ -509,7 +518,8 @@ pub fn utime(p: &CString, atime: u64, mtime: u64) -> IoResult<()> { actime: (atime / 1000) as libc::time64_t, modtime: (mtime / 1000) as libc::time64_t, }; - super::mkerr_libc(as_utf16_p(p.as_str().unwrap(), |p| unsafe { - libc::wutime(p, &buf) - })) + let p = try!(to_utf16(p)); + super::mkerr_libc(unsafe { + libc::wutime(p.as_ptr(), &buf) + }) } diff --git a/src/libnative/io/pipe_win32.rs b/src/libnative/io/pipe_win32.rs index a5694436b97..45b12aa7007 100644 --- a/src/libnative/io/pipe_win32.rs +++ b/src/libnative/io/pipe_win32.rs @@ -88,7 +88,6 @@ use alloc::arc::Arc; use libc; use std::c_str::CString; use std::mem; -use std::os::win32::as_utf16_p; use std::os; use std::ptr; use std::rt::rtio; @@ -98,6 +97,7 @@ use std::rt::mutex; use super::c; use super::util; +use super::file::to_utf16; struct Event(libc::HANDLE); @@ -261,67 +261,66 @@ impl UnixStream { } pub fn connect(addr: &CString, timeout: Option) -> IoResult { - as_utf16_p(addr.as_str().unwrap(), |p| { - let start = ::io::timer::now(); - loop { - match UnixStream::try_connect(p) { - Some(handle) => { - let inner = Inner::new(handle); - let mut mode = libc::PIPE_TYPE_BYTE | - libc::PIPE_READMODE_BYTE | - libc::PIPE_WAIT; - let ret = unsafe { - libc::SetNamedPipeHandleState(inner.handle, - &mut mode, - ptr::mut_null(), - ptr::mut_null()) - }; - return if ret == 0 { - Err(super::last_error()) - } else { - Ok(UnixStream { - inner: Arc::new(inner), - read: None, - write: None, - read_deadline: 0, - write_deadline: 0, - }) - } + let addr = try!(to_utf16(addr)); + let start = ::io::timer::now(); + loop { + match UnixStream::try_connect(addr.as_ptr()) { + Some(handle) => { + let inner = Inner::new(handle); + let mut mode = libc::PIPE_TYPE_BYTE | + libc::PIPE_READMODE_BYTE | + libc::PIPE_WAIT; + let ret = unsafe { + libc::SetNamedPipeHandleState(inner.handle, + &mut mode, + ptr::mut_null(), + ptr::mut_null()) + }; + return if ret == 0 { + Err(super::last_error()) + } else { + Ok(UnixStream { + inner: Arc::new(inner), + read: None, + write: None, + read_deadline: 0, + write_deadline: 0, + }) + } + } + None => {} + } + + // On windows, if you fail to connect, you may need to call the + // `WaitNamedPipe` function, and this is indicated with an error + // code of ERROR_PIPE_BUSY. + let code = unsafe { libc::GetLastError() }; + if code as int != libc::ERROR_PIPE_BUSY as int { + return Err(super::last_error()) + } + + match timeout { + Some(timeout) => { + let now = ::io::timer::now(); + let timed_out = (now - start) >= timeout || unsafe { + let ms = (timeout - (now - start)) as libc::DWORD; + libc::WaitNamedPipeW(addr.as_ptr(), ms) == 0 + }; + if timed_out { + return Err(util::timeout("connect timed out")) } - None => {} } - // On windows, if you fail to connect, you may need to call the - // `WaitNamedPipe` function, and this is indicated with an error - // code of ERROR_PIPE_BUSY. - let code = unsafe { libc::GetLastError() }; - if code as int != libc::ERROR_PIPE_BUSY as int { - return Err(super::last_error()) - } - - match timeout { - Some(timeout) => { - let now = ::io::timer::now(); - let timed_out = (now - start) >= timeout || unsafe { - let ms = (timeout - (now - start)) as libc::DWORD; - libc::WaitNamedPipeW(p, ms) == 0 - }; - if timed_out { - return Err(util::timeout("connect timed out")) - } - } - - // An example I found on microsoft's website used 20 - // seconds, libuv uses 30 seconds, hence we make the - // obvious choice of waiting for 25 seconds. - None => { - if unsafe { libc::WaitNamedPipeW(p, 25000) } == 0 { - return Err(super::last_error()) - } + // An example I found on microsoft's website used 20 + // seconds, libuv uses 30 seconds, hence we make the + // obvious choice of waiting for 25 seconds. + None => { + if unsafe { libc::WaitNamedPipeW(addr.as_ptr(), 25000) } == 0 { + return Err(super::last_error()) } } } - }) + } } fn handle(&self) -> libc::HANDLE { self.inner.handle } @@ -564,14 +563,13 @@ impl UnixListener { // Although we technically don't need the pipe until much later, we // create the initial handle up front to test the validity of the name // and such. - as_utf16_p(addr.as_str().unwrap(), |p| { - let ret = unsafe { pipe(p, true) }; - if ret == libc::INVALID_HANDLE_VALUE as libc::HANDLE { - Err(super::last_error()) - } else { - Ok(UnixListener { handle: ret, name: addr.clone() }) - } - }) + let addr_v = try!(to_utf16(addr)); + let ret = unsafe { pipe(addr_v.as_ptr(), true) }; + if ret == libc::INVALID_HANDLE_VALUE as libc::HANDLE { + Err(super::last_error()) + } else { + Ok(UnixListener { handle: ret, name: addr.clone() }) + } } pub fn native_listen(self) -> IoResult { @@ -639,6 +637,8 @@ impl UnixAcceptor { // using the original server pipe. let handle = self.listener.handle; + let name = try!(to_utf16(&self.listener.name)); + // Once we've got a "server handle", we need to wait for a client to // connect. The ConnectNamedPipe function will block this thread until // someone on the other end connects. This function can "fail" if a @@ -678,9 +678,7 @@ impl UnixAcceptor { // Now that we've got a connected client to our handle, we need to // create a second server pipe. If this fails, we disconnect the // connected client and return an error (see comments above). - let new_handle = as_utf16_p(self.listener.name.as_str().unwrap(), |p| { - unsafe { pipe(p, false) } - }); + let new_handle = unsafe { pipe(name.as_ptr(), false) }; if new_handle == libc::INVALID_HANDLE_VALUE as libc::HANDLE { let ret = Err(super::last_error()); // If our disconnection fails, then there's not really a whole lot diff --git a/src/libnative/io/process.rs b/src/libnative/io/process.rs index 2c2b7cec1de..97b227ae1d8 100644 --- a/src/libnative/io/process.rs +++ b/src/libnative/io/process.rs @@ -296,16 +296,15 @@ fn spawn_process_os(cfg: ProcessConfig, lpSecurityDescriptor: ptr::mut_null(), bInheritHandle: 1, }; - *slot = os::win32::as_utf16_p("NUL", |filename| { - libc::CreateFileW(filename, - access, - libc::FILE_SHARE_READ | - libc::FILE_SHARE_WRITE, - &mut sa, - libc::OPEN_EXISTING, - 0, - ptr::mut_null()) - }); + let filename = "NUL".to_utf16().append_one(0); + *slot = libc::CreateFileW(filename.as_ptr(), + access, + libc::FILE_SHARE_READ | + libc::FILE_SHARE_WRITE, + &mut sa, + libc::OPEN_EXISTING, + 0, + ptr::mut_null()); if *slot == INVALID_HANDLE_VALUE as libc::HANDLE { return Err(super::last_error()) } @@ -338,18 +337,17 @@ fn spawn_process_os(cfg: ProcessConfig, with_envp(cfg.env, |envp| { with_dirp(cfg.cwd, |dirp| { - os::win32::as_mut_utf16_p(cmd_str.as_slice(), |cmdp| { - let created = CreateProcessW(ptr::null(), - cmdp, - ptr::mut_null(), - ptr::mut_null(), - TRUE, - flags, envp, dirp, - &mut si, &mut pi); - if created == FALSE { - create_err = Some(super::last_error()); - } - }) + let mut cmd_str = cmd_str.to_utf16().append_one(0); + let created = CreateProcessW(ptr::null(), + cmd_str.as_mut_ptr(), + ptr::mut_null(), + ptr::mut_null(), + TRUE, + flags, envp, dirp, + &mut si, &mut pi); + if created == FALSE { + create_err = Some(super::last_error()); + } }) }); @@ -740,7 +738,8 @@ fn with_dirp(d: Option<&CString>, cb: |*u16| -> T) -> T { Some(dir) => { let dir_str = dir.as_str() .expect("expected workingdirectory to be utf-8 encoded"); - os::win32::as_utf16_p(dir_str, cb) + let dir_str = dir_str.to_utf16().append_one(0); + cb(dir_str.as_ptr()) }, None => cb(ptr::null()) } diff --git a/src/librustdoc/flock.rs b/src/librustdoc/flock.rs index fea6748660b..8ad10a686e6 100644 --- a/src/librustdoc/flock.rs +++ b/src/librustdoc/flock.rs @@ -135,7 +135,6 @@ mod imp { mod imp { use libc; use std::mem; - use std::os::win32::as_utf16_p; use std::os; use std::ptr; @@ -162,8 +161,9 @@ mod imp { impl Lock { pub fn new(p: &Path) -> Lock { - let handle = as_utf16_p(p.as_str().unwrap(), |p| unsafe { - libc::CreateFileW(p, + let p_16 = p.as_str().unwrap().to_utf16().append_one(0); + let handle = unsafe { + libc::CreateFileW(p_16.as_ptr(), libc::FILE_GENERIC_READ | libc::FILE_GENERIC_WRITE, libc::FILE_SHARE_READ | @@ -173,7 +173,7 @@ mod imp { libc::CREATE_ALWAYS, libc::FILE_ATTRIBUTE_NORMAL, ptr::mut_null()) - }); + }; if handle as uint == libc::INVALID_HANDLE_VALUE as uint { fail!("create file error: {}", os::last_os_error()); } diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 90df18106f0..fa882e7d016 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -133,7 +133,7 @@ pub mod win32 { use os::TMPBUF_SZ; use slice::{MutableVector, ImmutableVector}; use string::String; - use str::{StrSlice, StrAllocating}; + use str::StrSlice; use str; use vec::Vec; @@ -171,17 +171,6 @@ pub mod win32 { return res; } } - - pub fn as_utf16_p(s: &str, f: |*u16| -> T) -> T { - as_mut_utf16_p(s, |t| { f(t as *u16) }) - } - - pub fn as_mut_utf16_p(s: &str, f: |*mut u16| -> T) -> T { - let mut t = s.to_utf16(); - // Null terminate before passing on. - t.push(0u16); - f(t.as_mut_ptr()) - } } /* @@ -356,11 +345,10 @@ pub fn getenv_as_bytes(n: &str) -> Option> { pub fn getenv(n: &str) -> Option { unsafe { with_env_lock(|| { - use os::win32::{as_utf16_p, fill_utf16_buf_and_decode}; - as_utf16_p(n, |u| { - fill_utf16_buf_and_decode(|buf, sz| { - libc::GetEnvironmentVariableW(u, buf, sz) - }) + use os::win32::{fill_utf16_buf_and_decode}; + let n = n.to_utf16().append_one(0); + fill_utf16_buf_and_decode(|buf, sz| { + libc::GetEnvironmentVariableW(n.as_ptr(), buf, sz) }) }) } @@ -398,14 +386,11 @@ pub fn setenv(n: &str, v: &str) { /// Sets the environment variable `n` to the value `v` for the currently running /// process pub fn setenv(n: &str, v: &str) { + let n = n.to_utf16().append_one(0); + let v = v.to_utf16().append_one(0); unsafe { with_env_lock(|| { - use os::win32::as_utf16_p; - as_utf16_p(n, |nbuf| { - as_utf16_p(v, |vbuf| { - libc::SetEnvironmentVariableW(nbuf, vbuf); - }) - }) + libc::SetEnvironmentVariableW(n.as_ptr(), v.as_ptr()); }) } } @@ -428,12 +413,10 @@ pub fn unsetenv(n: &str) { } #[cfg(windows)] fn _unsetenv(n: &str) { + let n = n.to_utf16().append_one(0); unsafe { with_env_lock(|| { - use os::win32::as_utf16_p; - as_utf16_p(n, |nbuf| { - libc::SetEnvironmentVariableW(nbuf, ptr::null()); - }) + libc::SetEnvironmentVariableW(n.as_ptr(), ptr::null()); }) } } @@ -732,11 +715,12 @@ 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), + None => return false, + }; unsafe { - use os::win32::as_utf16_p; - return as_utf16_p(p.as_str().unwrap(), |buf| { - libc::SetCurrentDirectoryW(buf) != (0 as libc::BOOL) - }); + libc::SetCurrentDirectoryW(p.as_ptr()) != (0 as libc::BOOL) } } diff --git a/src/libstd/unstable/dynamic_lib.rs b/src/libstd/unstable/dynamic_lib.rs index c05cdc85cc5..6980c5cc0c2 100644 --- a/src/libstd/unstable/dynamic_lib.rs +++ b/src/libstd/unstable/dynamic_lib.rs @@ -272,21 +272,21 @@ pub mod dl { #[cfg(target_os = "win32")] pub mod dl { + use c_str::ToCStr; use libc; use os; use ptr; use result::{Ok, Err, Result}; - use string::String; + use str::StrAllocating; use str; - use c_str::ToCStr; + use string::String; pub unsafe fn open_external(filename: T) -> *u8 { // Windows expects Unicode data let filename_cstr = filename.to_c_str(); let filename_str = str::from_utf8(filename_cstr.as_bytes_no_nul()).unwrap(); - os::win32::as_utf16_p(filename_str, |raw_name| { - LoadLibraryW(raw_name as *libc::c_void) as *u8 - }) + let filename_str = filename_str.to_utf16().append_one(0); + LoadLibraryW(filename_str.as_ptr() as *libc::c_void) as *u8 } pub unsafe fn open_internal() -> *u8 { From 1e931918c844e73882bc67ad35ce4314526795d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Thu, 5 Jun 2014 21:07:50 +0200 Subject: [PATCH 02/11] Moved integer trait and functions to submodule --- src/libnum/integer.rs | 411 ++++++++++++++++++++++++++++++++++++++++++ src/libnum/lib.rs | 408 +---------------------------------------- 2 files changed, 418 insertions(+), 401 deletions(-) create mode 100644 src/libnum/integer.rs diff --git a/src/libnum/integer.rs b/src/libnum/integer.rs new file mode 100644 index 00000000000..d958d40d3d1 --- /dev/null +++ b/src/libnum/integer.rs @@ -0,0 +1,411 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Integer trait and functions + +pub trait Integer: Num + PartialOrd + + Div + + Rem { + /// Simultaneous truncated integer division and modulus + #[inline] + fn div_rem(&self, other: &Self) -> (Self, Self) { + (*self / *other, *self % *other) + } + + /// Floored integer division + /// + /// # Examples + /// + /// ~~~ + /// # use num::Integer; + /// assert!(( 8i).div_floor(& 3) == 2); + /// assert!(( 8i).div_floor(&-3) == -3); + /// assert!((-8i).div_floor(& 3) == -3); + /// assert!((-8i).div_floor(&-3) == 2); + /// + /// assert!(( 1i).div_floor(& 2) == 0); + /// assert!(( 1i).div_floor(&-2) == -1); + /// assert!((-1i).div_floor(& 2) == -1); + /// assert!((-1i).div_floor(&-2) == 0); + /// ~~~ + fn div_floor(&self, other: &Self) -> Self; + + /// Floored integer modulo, satisfying: + /// + /// ~~~ + /// # use num::Integer; + /// # let n = 1i; let d = 1i; + /// assert!(n.div_floor(&d) * d + n.mod_floor(&d) == n) + /// ~~~ + /// + /// # Examples + /// + /// ~~~ + /// # use num::Integer; + /// assert!(( 8i).mod_floor(& 3) == 2); + /// assert!(( 8i).mod_floor(&-3) == -1); + /// assert!((-8i).mod_floor(& 3) == 1); + /// assert!((-8i).mod_floor(&-3) == -2); + /// + /// assert!(( 1i).mod_floor(& 2) == 1); + /// assert!(( 1i).mod_floor(&-2) == -1); + /// assert!((-1i).mod_floor(& 2) == 1); + /// assert!((-1i).mod_floor(&-2) == -1); + /// ~~~ + fn mod_floor(&self, other: &Self) -> Self; + + /// Simultaneous floored integer division and modulus + fn div_mod_floor(&self, other: &Self) -> (Self, Self) { + (self.div_floor(other), self.mod_floor(other)) + } + + /// Greatest Common Divisor (GCD) + fn gcd(&self, other: &Self) -> Self; + + /// Lowest Common Multiple (LCM) + fn lcm(&self, other: &Self) -> Self; + + /// Returns `true` if `other` divides evenly into `self` + fn divides(&self, other: &Self) -> bool; + + /// Returns `true` if the number is even + fn is_even(&self) -> bool; + + /// Returns `true` if the number is odd + fn is_odd(&self) -> bool; +} + +/// Simultaneous integer division and modulus +#[inline] pub fn div_rem(x: T, y: T) -> (T, T) { x.div_rem(&y) } +/// Floored integer division +#[inline] pub fn div_floor(x: T, y: T) -> T { x.div_floor(&y) } +/// Floored integer modulus +#[inline] pub fn mod_floor(x: T, y: T) -> T { x.mod_floor(&y) } +/// Simultaneous floored integer division and modulus +#[inline] pub fn div_mod_floor(x: T, y: T) -> (T, T) { x.div_mod_floor(&y) } + +/// Calculates the Greatest Common Divisor (GCD) of the number and `other`. The +/// result is always positive. +#[inline(always)] pub fn gcd(x: T, y: T) -> T { x.gcd(&y) } +/// Calculates the Lowest Common Multiple (LCM) of the number and `other`. +#[inline(always)] pub fn lcm(x: T, y: T) -> T { x.lcm(&y) } + +macro_rules! impl_integer_for_int { + ($T:ty, $test_mod:ident) => ( + impl Integer for $T { + /// Floored integer division + #[inline] + fn div_floor(&self, other: &$T) -> $T { + // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, + // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) + match self.div_rem(other) { + (d, r) if (r > 0 && *other < 0) + || (r < 0 && *other > 0) => d - 1, + (d, _) => d, + } + } + + /// Floored integer modulo + #[inline] + fn mod_floor(&self, other: &$T) -> $T { + // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, + // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) + match *self % *other { + r if (r > 0 && *other < 0) + || (r < 0 && *other > 0) => r + *other, + r => r, + } + } + + /// Calculates `div_floor` and `mod_floor` simultaneously + #[inline] + fn div_mod_floor(&self, other: &$T) -> ($T,$T) { + // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, + // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) + match self.div_rem(other) { + (d, r) if (r > 0 && *other < 0) + || (r < 0 && *other > 0) => (d - 1, r + *other), + (d, r) => (d, r), + } + } + + /// Calculates the Greatest Common Divisor (GCD) of the number and + /// `other`. The result is always positive. + #[inline] + fn gcd(&self, other: &$T) -> $T { + // Use Euclid's algorithm + let mut m = *self; + let mut n = *other; + while m != 0 { + let temp = m; + m = n % temp; + n = temp; + } + n.abs() + } + + /// Calculates the Lowest Common Multiple (LCM) of the number and + /// `other`. + #[inline] + fn lcm(&self, other: &$T) -> $T { + // should not have to recalculate abs + ((*self * *other) / self.gcd(other)).abs() + } + + /// Returns `true` if the number can be divided by `other` without + /// leaving a remainder + #[inline] + fn divides(&self, other: &$T) -> bool { *self % *other == 0 } + + /// Returns `true` if the number is divisible by `2` + #[inline] + fn is_even(&self) -> bool { self & 1 == 0 } + + /// Returns `true` if the number is not divisible by `2` + #[inline] + fn is_odd(&self) -> bool { !self.is_even() } + } + + #[cfg(test)] + mod $test_mod { + use Integer; + + /// Checks that the division rule holds for: + /// + /// - `n`: numerator (dividend) + /// - `d`: denominator (divisor) + /// - `qr`: quotient and remainder + #[cfg(test)] + fn test_division_rule((n,d): ($T,$T), (q,r): ($T,$T)) { + assert_eq!(d * q + r, n); + } + + #[test] + fn test_div_rem() { + fn test_nd_dr(nd: ($T,$T), qr: ($T,$T)) { + let (n,d) = nd; + let separate_div_rem = (n / d, n % d); + let combined_div_rem = n.div_rem(&d); + + assert_eq!(separate_div_rem, qr); + assert_eq!(combined_div_rem, qr); + + test_division_rule(nd, separate_div_rem); + test_division_rule(nd, combined_div_rem); + } + + test_nd_dr(( 8, 3), ( 2, 2)); + test_nd_dr(( 8, -3), (-2, 2)); + test_nd_dr((-8, 3), (-2, -2)); + test_nd_dr((-8, -3), ( 2, -2)); + + test_nd_dr(( 1, 2), ( 0, 1)); + test_nd_dr(( 1, -2), ( 0, 1)); + test_nd_dr((-1, 2), ( 0, -1)); + test_nd_dr((-1, -2), ( 0, -1)); + } + + #[test] + fn test_div_mod_floor() { + fn test_nd_dm(nd: ($T,$T), dm: ($T,$T)) { + let (n,d) = nd; + let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d)); + let combined_div_mod_floor = n.div_mod_floor(&d); + + assert_eq!(separate_div_mod_floor, dm); + assert_eq!(combined_div_mod_floor, dm); + + test_division_rule(nd, separate_div_mod_floor); + test_division_rule(nd, combined_div_mod_floor); + } + + test_nd_dm(( 8, 3), ( 2, 2)); + test_nd_dm(( 8, -3), (-3, -1)); + test_nd_dm((-8, 3), (-3, 1)); + test_nd_dm((-8, -3), ( 2, -2)); + + test_nd_dm(( 1, 2), ( 0, 1)); + test_nd_dm(( 1, -2), (-1, -1)); + test_nd_dm((-1, 2), (-1, 1)); + test_nd_dm((-1, -2), ( 0, -1)); + } + + #[test] + fn test_gcd() { + assert_eq!((10 as $T).gcd(&2), 2 as $T); + assert_eq!((10 as $T).gcd(&3), 1 as $T); + assert_eq!((0 as $T).gcd(&3), 3 as $T); + assert_eq!((3 as $T).gcd(&3), 3 as $T); + assert_eq!((56 as $T).gcd(&42), 14 as $T); + assert_eq!((3 as $T).gcd(&-3), 3 as $T); + assert_eq!((-6 as $T).gcd(&3), 3 as $T); + assert_eq!((-4 as $T).gcd(&-2), 2 as $T); + } + + #[test] + fn test_lcm() { + assert_eq!((1 as $T).lcm(&0), 0 as $T); + assert_eq!((0 as $T).lcm(&1), 0 as $T); + assert_eq!((1 as $T).lcm(&1), 1 as $T); + assert_eq!((-1 as $T).lcm(&1), 1 as $T); + assert_eq!((1 as $T).lcm(&-1), 1 as $T); + assert_eq!((-1 as $T).lcm(&-1), 1 as $T); + assert_eq!((8 as $T).lcm(&9), 72 as $T); + assert_eq!((11 as $T).lcm(&5), 55 as $T); + } + + #[test] + fn test_even() { + assert_eq!((-4 as $T).is_even(), true); + assert_eq!((-3 as $T).is_even(), false); + assert_eq!((-2 as $T).is_even(), true); + assert_eq!((-1 as $T).is_even(), false); + assert_eq!((0 as $T).is_even(), true); + assert_eq!((1 as $T).is_even(), false); + assert_eq!((2 as $T).is_even(), true); + assert_eq!((3 as $T).is_even(), false); + assert_eq!((4 as $T).is_even(), true); + } + + #[test] + fn test_odd() { + assert_eq!((-4 as $T).is_odd(), false); + assert_eq!((-3 as $T).is_odd(), true); + assert_eq!((-2 as $T).is_odd(), false); + assert_eq!((-1 as $T).is_odd(), true); + assert_eq!((0 as $T).is_odd(), false); + assert_eq!((1 as $T).is_odd(), true); + assert_eq!((2 as $T).is_odd(), false); + assert_eq!((3 as $T).is_odd(), true); + assert_eq!((4 as $T).is_odd(), false); + } + } + ) +} + +impl_integer_for_int!(i8, test_integer_i8) +impl_integer_for_int!(i16, test_integer_i16) +impl_integer_for_int!(i32, test_integer_i32) +impl_integer_for_int!(i64, test_integer_i64) +impl_integer_for_int!(int, test_integer_int) + +macro_rules! impl_integer_for_uint { + ($T:ty, $test_mod:ident) => ( + impl Integer for $T { + /// Unsigned integer division. Returns the same result as `div` (`/`). + #[inline] + fn div_floor(&self, other: &$T) -> $T { *self / *other } + + /// Unsigned integer modulo operation. Returns the same result as `rem` (`%`). + #[inline] + fn mod_floor(&self, other: &$T) -> $T { *self % *other } + + /// Calculates the Greatest Common Divisor (GCD) of the number and `other` + #[inline] + fn gcd(&self, other: &$T) -> $T { + // Use Euclid's algorithm + let mut m = *self; + let mut n = *other; + while m != 0 { + let temp = m; + m = n % temp; + n = temp; + } + n + } + + /// Calculates the Lowest Common Multiple (LCM) of the number and `other` + #[inline] + fn lcm(&self, other: &$T) -> $T { + (*self * *other) / self.gcd(other) + } + + /// Returns `true` if the number can be divided by `other` without leaving a remainder + #[inline] + fn divides(&self, other: &$T) -> bool { *self % *other == 0 } + + /// Returns `true` if the number is divisible by `2` + #[inline] + fn is_even(&self) -> bool { self & 1 == 0 } + + /// Returns `true` if the number is not divisible by `2` + #[inline] + fn is_odd(&self) -> bool { !self.is_even() } + } + + #[cfg(test)] + mod $test_mod { + use Integer; + + #[test] + fn test_div_mod_floor() { + assert_eq!((10 as $T).div_floor(&(3 as $T)), 3 as $T); + assert_eq!((10 as $T).mod_floor(&(3 as $T)), 1 as $T); + assert_eq!((10 as $T).div_mod_floor(&(3 as $T)), (3 as $T, 1 as $T)); + assert_eq!((5 as $T).div_floor(&(5 as $T)), 1 as $T); + assert_eq!((5 as $T).mod_floor(&(5 as $T)), 0 as $T); + assert_eq!((5 as $T).div_mod_floor(&(5 as $T)), (1 as $T, 0 as $T)); + assert_eq!((3 as $T).div_floor(&(7 as $T)), 0 as $T); + assert_eq!((3 as $T).mod_floor(&(7 as $T)), 3 as $T); + assert_eq!((3 as $T).div_mod_floor(&(7 as $T)), (0 as $T, 3 as $T)); + } + + #[test] + fn test_gcd() { + assert_eq!((10 as $T).gcd(&2), 2 as $T); + assert_eq!((10 as $T).gcd(&3), 1 as $T); + assert_eq!((0 as $T).gcd(&3), 3 as $T); + assert_eq!((3 as $T).gcd(&3), 3 as $T); + assert_eq!((56 as $T).gcd(&42), 14 as $T); + } + + #[test] + fn test_lcm() { + assert_eq!((1 as $T).lcm(&0), 0 as $T); + assert_eq!((0 as $T).lcm(&1), 0 as $T); + assert_eq!((1 as $T).lcm(&1), 1 as $T); + assert_eq!((8 as $T).lcm(&9), 72 as $T); + assert_eq!((11 as $T).lcm(&5), 55 as $T); + assert_eq!((99 as $T).lcm(&17), 1683 as $T); + } + + #[test] + fn test_divides() { + assert!((6 as $T).divides(&(6 as $T))); + assert!((6 as $T).divides(&(3 as $T))); + assert!((6 as $T).divides(&(1 as $T))); + } + + #[test] + fn test_even() { + assert_eq!((0 as $T).is_even(), true); + assert_eq!((1 as $T).is_even(), false); + assert_eq!((2 as $T).is_even(), true); + assert_eq!((3 as $T).is_even(), false); + assert_eq!((4 as $T).is_even(), true); + } + + #[test] + fn test_odd() { + assert_eq!((0 as $T).is_odd(), false); + assert_eq!((1 as $T).is_odd(), true); + assert_eq!((2 as $T).is_odd(), false); + assert_eq!((3 as $T).is_odd(), true); + assert_eq!((4 as $T).is_odd(), false); + } + } + ) +} + +impl_integer_for_uint!(u8, test_integer_u8) +impl_integer_for_uint!(u16, test_integer_u16) +impl_integer_for_uint!(u32, test_integer_u32) +impl_integer_for_uint!(u64, test_integer_u64) +impl_integer_for_uint!(uint, test_integer_uint) diff --git a/src/libnum/lib.rs b/src/libnum/lib.rs index fae21e80f30..709882c87ce 100644 --- a/src/libnum/lib.rs +++ b/src/libnum/lib.rs @@ -57,406 +57,12 @@ extern crate rand; +pub use bigint::{BigInt, BigUint}; +pub use rational::{Rational, BigRational}; +pub use complex::Complex; +pub use integer::Integer; + pub mod bigint; -pub mod rational; pub mod complex; - -pub trait Integer: Num + PartialOrd - + Div - + Rem { - /// Simultaneous truncated integer division and modulus - #[inline] - fn div_rem(&self, other: &Self) -> (Self, Self) { - (*self / *other, *self % *other) - } - - /// Floored integer division - /// - /// # Examples - /// - /// ~~~ - /// # use num::Integer; - /// assert!(( 8i).div_floor(& 3) == 2); - /// assert!(( 8i).div_floor(&-3) == -3); - /// assert!((-8i).div_floor(& 3) == -3); - /// assert!((-8i).div_floor(&-3) == 2); - /// - /// assert!(( 1i).div_floor(& 2) == 0); - /// assert!(( 1i).div_floor(&-2) == -1); - /// assert!((-1i).div_floor(& 2) == -1); - /// assert!((-1i).div_floor(&-2) == 0); - /// ~~~ - fn div_floor(&self, other: &Self) -> Self; - - /// Floored integer modulo, satisfying: - /// - /// ~~~ - /// # use num::Integer; - /// # let n = 1i; let d = 1i; - /// assert!(n.div_floor(&d) * d + n.mod_floor(&d) == n) - /// ~~~ - /// - /// # Examples - /// - /// ~~~ - /// # use num::Integer; - /// assert!(( 8i).mod_floor(& 3) == 2); - /// assert!(( 8i).mod_floor(&-3) == -1); - /// assert!((-8i).mod_floor(& 3) == 1); - /// assert!((-8i).mod_floor(&-3) == -2); - /// - /// assert!(( 1i).mod_floor(& 2) == 1); - /// assert!(( 1i).mod_floor(&-2) == -1); - /// assert!((-1i).mod_floor(& 2) == 1); - /// assert!((-1i).mod_floor(&-2) == -1); - /// ~~~ - fn mod_floor(&self, other: &Self) -> Self; - - /// Simultaneous floored integer division and modulus - fn div_mod_floor(&self, other: &Self) -> (Self, Self) { - (self.div_floor(other), self.mod_floor(other)) - } - - /// Greatest Common Divisor (GCD) - fn gcd(&self, other: &Self) -> Self; - - /// Lowest Common Multiple (LCM) - fn lcm(&self, other: &Self) -> Self; - - /// Returns `true` if `other` divides evenly into `self` - fn divides(&self, other: &Self) -> bool; - - /// Returns `true` if the number is even - fn is_even(&self) -> bool; - - /// Returns `true` if the number is odd - fn is_odd(&self) -> bool; -} - -/// Simultaneous integer division and modulus -#[inline] pub fn div_rem(x: T, y: T) -> (T, T) { x.div_rem(&y) } -/// Floored integer division -#[inline] pub fn div_floor(x: T, y: T) -> T { x.div_floor(&y) } -/// Floored integer modulus -#[inline] pub fn mod_floor(x: T, y: T) -> T { x.mod_floor(&y) } -/// Simultaneous floored integer division and modulus -#[inline] pub fn div_mod_floor(x: T, y: T) -> (T, T) { x.div_mod_floor(&y) } - -/// Calculates the Greatest Common Divisor (GCD) of the number and `other`. The -/// result is always positive. -#[inline(always)] pub fn gcd(x: T, y: T) -> T { x.gcd(&y) } -/// Calculates the Lowest Common Multiple (LCM) of the number and `other`. -#[inline(always)] pub fn lcm(x: T, y: T) -> T { x.lcm(&y) } - -macro_rules! impl_integer_for_int { - ($T:ty, $test_mod:ident) => ( - impl Integer for $T { - /// Floored integer division - #[inline] - fn div_floor(&self, other: &$T) -> $T { - // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, - // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match self.div_rem(other) { - (d, r) if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => d - 1, - (d, _) => d, - } - } - - /// Floored integer modulo - #[inline] - fn mod_floor(&self, other: &$T) -> $T { - // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, - // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match *self % *other { - r if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => r + *other, - r => r, - } - } - - /// Calculates `div_floor` and `mod_floor` simultaneously - #[inline] - fn div_mod_floor(&self, other: &$T) -> ($T,$T) { - // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, - // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match self.div_rem(other) { - (d, r) if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => (d - 1, r + *other), - (d, r) => (d, r), - } - } - - /// Calculates the Greatest Common Divisor (GCD) of the number and - /// `other`. The result is always positive. - #[inline] - fn gcd(&self, other: &$T) -> $T { - // Use Euclid's algorithm - let mut m = *self; - let mut n = *other; - while m != 0 { - let temp = m; - m = n % temp; - n = temp; - } - n.abs() - } - - /// Calculates the Lowest Common Multiple (LCM) of the number and - /// `other`. - #[inline] - fn lcm(&self, other: &$T) -> $T { - // should not have to recalculate abs - ((*self * *other) / self.gcd(other)).abs() - } - - /// Returns `true` if the number can be divided by `other` without - /// leaving a remainder - #[inline] - fn divides(&self, other: &$T) -> bool { *self % *other == 0 } - - /// Returns `true` if the number is divisible by `2` - #[inline] - fn is_even(&self) -> bool { self & 1 == 0 } - - /// Returns `true` if the number is not divisible by `2` - #[inline] - fn is_odd(&self) -> bool { !self.is_even() } - } - - #[cfg(test)] - mod $test_mod { - use Integer; - - /// Checks that the division rule holds for: - /// - /// - `n`: numerator (dividend) - /// - `d`: denominator (divisor) - /// - `qr`: quotient and remainder - #[cfg(test)] - fn test_division_rule((n,d): ($T,$T), (q,r): ($T,$T)) { - assert_eq!(d * q + r, n); - } - - #[test] - fn test_div_rem() { - fn test_nd_dr(nd: ($T,$T), qr: ($T,$T)) { - let (n,d) = nd; - let separate_div_rem = (n / d, n % d); - let combined_div_rem = n.div_rem(&d); - - assert_eq!(separate_div_rem, qr); - assert_eq!(combined_div_rem, qr); - - test_division_rule(nd, separate_div_rem); - test_division_rule(nd, combined_div_rem); - } - - test_nd_dr(( 8, 3), ( 2, 2)); - test_nd_dr(( 8, -3), (-2, 2)); - test_nd_dr((-8, 3), (-2, -2)); - test_nd_dr((-8, -3), ( 2, -2)); - - test_nd_dr(( 1, 2), ( 0, 1)); - test_nd_dr(( 1, -2), ( 0, 1)); - test_nd_dr((-1, 2), ( 0, -1)); - test_nd_dr((-1, -2), ( 0, -1)); - } - - #[test] - fn test_div_mod_floor() { - fn test_nd_dm(nd: ($T,$T), dm: ($T,$T)) { - let (n,d) = nd; - let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d)); - let combined_div_mod_floor = n.div_mod_floor(&d); - - assert_eq!(separate_div_mod_floor, dm); - assert_eq!(combined_div_mod_floor, dm); - - test_division_rule(nd, separate_div_mod_floor); - test_division_rule(nd, combined_div_mod_floor); - } - - test_nd_dm(( 8, 3), ( 2, 2)); - test_nd_dm(( 8, -3), (-3, -1)); - test_nd_dm((-8, 3), (-3, 1)); - test_nd_dm((-8, -3), ( 2, -2)); - - test_nd_dm(( 1, 2), ( 0, 1)); - test_nd_dm(( 1, -2), (-1, -1)); - test_nd_dm((-1, 2), (-1, 1)); - test_nd_dm((-1, -2), ( 0, -1)); - } - - #[test] - fn test_gcd() { - assert_eq!((10 as $T).gcd(&2), 2 as $T); - assert_eq!((10 as $T).gcd(&3), 1 as $T); - assert_eq!((0 as $T).gcd(&3), 3 as $T); - assert_eq!((3 as $T).gcd(&3), 3 as $T); - assert_eq!((56 as $T).gcd(&42), 14 as $T); - assert_eq!((3 as $T).gcd(&-3), 3 as $T); - assert_eq!((-6 as $T).gcd(&3), 3 as $T); - assert_eq!((-4 as $T).gcd(&-2), 2 as $T); - } - - #[test] - fn test_lcm() { - assert_eq!((1 as $T).lcm(&0), 0 as $T); - assert_eq!((0 as $T).lcm(&1), 0 as $T); - assert_eq!((1 as $T).lcm(&1), 1 as $T); - assert_eq!((-1 as $T).lcm(&1), 1 as $T); - assert_eq!((1 as $T).lcm(&-1), 1 as $T); - assert_eq!((-1 as $T).lcm(&-1), 1 as $T); - assert_eq!((8 as $T).lcm(&9), 72 as $T); - assert_eq!((11 as $T).lcm(&5), 55 as $T); - } - - #[test] - fn test_even() { - assert_eq!((-4 as $T).is_even(), true); - assert_eq!((-3 as $T).is_even(), false); - assert_eq!((-2 as $T).is_even(), true); - assert_eq!((-1 as $T).is_even(), false); - assert_eq!((0 as $T).is_even(), true); - assert_eq!((1 as $T).is_even(), false); - assert_eq!((2 as $T).is_even(), true); - assert_eq!((3 as $T).is_even(), false); - assert_eq!((4 as $T).is_even(), true); - } - - #[test] - fn test_odd() { - assert_eq!((-4 as $T).is_odd(), false); - assert_eq!((-3 as $T).is_odd(), true); - assert_eq!((-2 as $T).is_odd(), false); - assert_eq!((-1 as $T).is_odd(), true); - assert_eq!((0 as $T).is_odd(), false); - assert_eq!((1 as $T).is_odd(), true); - assert_eq!((2 as $T).is_odd(), false); - assert_eq!((3 as $T).is_odd(), true); - assert_eq!((4 as $T).is_odd(), false); - } - } - ) -} - -impl_integer_for_int!(i8, test_integer_i8) -impl_integer_for_int!(i16, test_integer_i16) -impl_integer_for_int!(i32, test_integer_i32) -impl_integer_for_int!(i64, test_integer_i64) -impl_integer_for_int!(int, test_integer_int) - -macro_rules! impl_integer_for_uint { - ($T:ty, $test_mod:ident) => ( - impl Integer for $T { - /// Unsigned integer division. Returns the same result as `div` (`/`). - #[inline] - fn div_floor(&self, other: &$T) -> $T { *self / *other } - - /// Unsigned integer modulo operation. Returns the same result as `rem` (`%`). - #[inline] - fn mod_floor(&self, other: &$T) -> $T { *self % *other } - - /// Calculates the Greatest Common Divisor (GCD) of the number and `other` - #[inline] - fn gcd(&self, other: &$T) -> $T { - // Use Euclid's algorithm - let mut m = *self; - let mut n = *other; - while m != 0 { - let temp = m; - m = n % temp; - n = temp; - } - n - } - - /// Calculates the Lowest Common Multiple (LCM) of the number and `other` - #[inline] - fn lcm(&self, other: &$T) -> $T { - (*self * *other) / self.gcd(other) - } - - /// Returns `true` if the number can be divided by `other` without leaving a remainder - #[inline] - fn divides(&self, other: &$T) -> bool { *self % *other == 0 } - - /// Returns `true` if the number is divisible by `2` - #[inline] - fn is_even(&self) -> bool { self & 1 == 0 } - - /// Returns `true` if the number is not divisible by `2` - #[inline] - fn is_odd(&self) -> bool { !self.is_even() } - } - - #[cfg(test)] - mod $test_mod { - use Integer; - - #[test] - fn test_div_mod_floor() { - assert_eq!((10 as $T).div_floor(&(3 as $T)), 3 as $T); - assert_eq!((10 as $T).mod_floor(&(3 as $T)), 1 as $T); - assert_eq!((10 as $T).div_mod_floor(&(3 as $T)), (3 as $T, 1 as $T)); - assert_eq!((5 as $T).div_floor(&(5 as $T)), 1 as $T); - assert_eq!((5 as $T).mod_floor(&(5 as $T)), 0 as $T); - assert_eq!((5 as $T).div_mod_floor(&(5 as $T)), (1 as $T, 0 as $T)); - assert_eq!((3 as $T).div_floor(&(7 as $T)), 0 as $T); - assert_eq!((3 as $T).mod_floor(&(7 as $T)), 3 as $T); - assert_eq!((3 as $T).div_mod_floor(&(7 as $T)), (0 as $T, 3 as $T)); - } - - #[test] - fn test_gcd() { - assert_eq!((10 as $T).gcd(&2), 2 as $T); - assert_eq!((10 as $T).gcd(&3), 1 as $T); - assert_eq!((0 as $T).gcd(&3), 3 as $T); - assert_eq!((3 as $T).gcd(&3), 3 as $T); - assert_eq!((56 as $T).gcd(&42), 14 as $T); - } - - #[test] - fn test_lcm() { - assert_eq!((1 as $T).lcm(&0), 0 as $T); - assert_eq!((0 as $T).lcm(&1), 0 as $T); - assert_eq!((1 as $T).lcm(&1), 1 as $T); - assert_eq!((8 as $T).lcm(&9), 72 as $T); - assert_eq!((11 as $T).lcm(&5), 55 as $T); - assert_eq!((99 as $T).lcm(&17), 1683 as $T); - } - - #[test] - fn test_divides() { - assert!((6 as $T).divides(&(6 as $T))); - assert!((6 as $T).divides(&(3 as $T))); - assert!((6 as $T).divides(&(1 as $T))); - } - - #[test] - fn test_even() { - assert_eq!((0 as $T).is_even(), true); - assert_eq!((1 as $T).is_even(), false); - assert_eq!((2 as $T).is_even(), true); - assert_eq!((3 as $T).is_even(), false); - assert_eq!((4 as $T).is_even(), true); - } - - #[test] - fn test_odd() { - assert_eq!((0 as $T).is_odd(), false); - assert_eq!((1 as $T).is_odd(), true); - assert_eq!((2 as $T).is_odd(), false); - assert_eq!((3 as $T).is_odd(), true); - assert_eq!((4 as $T).is_odd(), false); - } - } - ) -} - -impl_integer_for_uint!(u8, test_integer_u8) -impl_integer_for_uint!(u16, test_integer_u16) -impl_integer_for_uint!(u32, test_integer_u32) -impl_integer_for_uint!(u64, test_integer_u64) -impl_integer_for_uint!(uint, test_integer_uint) +pub mod integer; +pub mod rational; From 9faf5a3483c4fc9a0d290c9dc6af006c6b76255c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Fri, 6 Jun 2014 10:56:03 +0200 Subject: [PATCH 03/11] Cleanup bigint --- src/libnum/bigint.rs | 63 +++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/src/libnum/bigint.rs b/src/libnum/bigint.rs index 67501c9795d..0933301970d 100644 --- a/src/libnum/bigint.rs +++ b/src/libnum/bigint.rs @@ -17,18 +17,16 @@ A `BigInt` is a combination of `BigUint` and `Sign`. */ use Integer; +use rand::Rng; -use std::cmp; +use std::{cmp, fmt}; use std::default::Default; -use std::fmt; use std::from_str::FromStr; use std::num::CheckedDiv; use std::num::{Bitwise, ToPrimitive, FromPrimitive}; use std::num::{Zero, One, ToStrRadix, FromStrRadix}; -use rand::Rng; use std::string::String; -use std::uint; -use std::{i64, u64}; +use std::{uint, i64, u64}; /** A `BigDigit` is a `BigUint`'s composing element. @@ -94,7 +92,7 @@ impl Eq for BigUint {} impl PartialOrd for BigUint { #[inline] fn lt(&self, other: &BigUint) -> bool { - match self.cmp(other) { Less => true, _ => false} + self.cmp(other) == Less } } @@ -115,7 +113,7 @@ impl Ord for BigUint { impl Default for BigUint { #[inline] - fn default() -> BigUint { BigUint::new(Vec::new()) } + fn default() -> BigUint { Zero::zero() } } impl fmt::Show for BigUint { @@ -605,7 +603,7 @@ impl_to_biguint!(u64, FromPrimitive::from_u64) impl ToStrRadix for BigUint { fn to_str_radix(&self, radix: uint) -> String { - assert!(1 < radix && radix <= 16); + assert!(1 < radix && radix <= 16, "The radix must be within (1, 16]"); let (base, max_len) = get_radix_base(radix); if base == BigDigit::base { return fill_concat(self.data.as_slice(), radix, max_len) @@ -645,8 +643,7 @@ impl ToStrRadix for BigUint { impl FromStrRadix for BigUint { /// Creates and initializes a `BigUint`. #[inline] - fn from_str_radix(s: &str, radix: uint) - -> Option { + fn from_str_radix(s: &str, radix: uint) -> Option { BigUint::parse_bytes(s.as_bytes(), radix) } } @@ -656,14 +653,11 @@ impl BigUint { /// /// The digits are be in base 2^32. #[inline] - pub fn new(v: Vec) -> BigUint { + pub fn new(mut digits: Vec) -> BigUint { // omit trailing zeros - let new_len = v.iter().rposition(|n| *n != 0).map_or(0, |p| p + 1); - - if new_len == v.len() { return BigUint { data: v }; } - let mut v = v; - v.truncate(new_len); - return BigUint { data: v }; + let new_len = digits.iter().rposition(|n| *n != 0).map_or(0, |p| p + 1); + digits.truncate(new_len); + BigUint { data: digits } } /// Creates and initializes a `BigUint`. @@ -671,7 +665,7 @@ impl BigUint { /// The digits are be in base 2^32. #[inline] pub fn from_slice(slice: &[BigDigit]) -> BigUint { - return BigUint::new(Vec::from_slice(slice)); + BigUint::new(Vec::from_slice(slice)) } /// Creates and initializes a `BigUint`. @@ -768,7 +762,6 @@ impl BigUint { // `DoubleBigDigit` size dependent #[inline] fn get_radix_base(radix: uint) -> (DoubleBigDigit, uint) { - assert!(1 < radix && radix <= 16); match radix { 2 => (4294967296, 32), 3 => (3486784401, 20), @@ -785,7 +778,7 @@ fn get_radix_base(radix: uint) -> (DoubleBigDigit, uint) { 14 => (1475789056, 8), 15 => (2562890625, 8), 16 => (4294967296, 8), - _ => fail!() + _ => fail!("The radix must be within (1, 16]") } } @@ -815,7 +808,7 @@ pub struct BigInt { impl PartialEq for BigInt { #[inline] fn eq(&self, other: &BigInt) -> bool { - match self.cmp(other) { Equal => true, _ => false } + self.cmp(other) == Equal } } @@ -824,7 +817,7 @@ impl Eq for BigInt {} impl PartialOrd for BigInt { #[inline] fn lt(&self, other: &BigInt) -> bool { - match self.cmp(other) { Less => true, _ => false} + self.cmp(other) == Less } } @@ -844,7 +837,7 @@ impl Ord for BigInt { impl Default for BigInt { #[inline] - fn default() -> BigInt { BigInt::new(Zero, Vec::new()) } + fn default() -> BigInt { Zero::zero() } } impl fmt::Show for BigInt { @@ -929,8 +922,7 @@ impl Add for BigInt { match (self.sign, other.sign) { (Zero, _) => other.clone(), (_, Zero) => self.clone(), - (Plus, Plus) => BigInt::from_biguint(Plus, - self.data + other.data), + (Plus, Plus) => BigInt::from_biguint(Plus, self.data + other.data), (Plus, Minus) => self - (-*other), (Minus, Plus) => other - (-*self), (Minus, Minus) => -((-self) + (-*other)) @@ -975,7 +967,7 @@ impl Div for BigInt { #[inline] fn div(&self, other: &BigInt) -> BigInt { let (q, _) = self.div_rem(other); - return q; + q } } @@ -983,7 +975,7 @@ impl Rem for BigInt { #[inline] fn rem(&self, other: &BigInt) -> BigInt { let (_, r) = self.div_rem(other); - return r; + r } } @@ -1045,13 +1037,13 @@ impl Integer for BigInt { #[inline] fn div_floor(&self, other: &BigInt) -> BigInt { let (d, _) = self.div_mod_floor(other); - return d; + d } #[inline] fn mod_floor(&self, other: &BigInt) -> BigInt { let (_, m) = self.div_mod_floor(other); - return m; + m } fn div_mod_floor(&self, other: &BigInt) -> (BigInt, BigInt) { @@ -1265,7 +1257,7 @@ impl RandBigInt for R { let final_digit: BigDigit = self.gen(); data.push(final_digit >> (BigDigit::bits - rem)); } - return BigUint::new(data); + BigUint::new(data) } fn gen_bigint(&mut self, bit_size: uint) -> BigInt { @@ -1287,7 +1279,7 @@ impl RandBigInt for R { } else { Minus }; - return BigInt::from_biguint(sign, biguint); + BigInt::from_biguint(sign, biguint) } fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint { @@ -1322,8 +1314,8 @@ impl BigInt { /// /// The digits are be in base 2^32. #[inline] - pub fn new(sign: Sign, v: Vec) -> BigInt { - BigInt::from_biguint(sign, BigUint::new(v)) + pub fn new(sign: Sign, digits: Vec) -> BigInt { + BigInt::from_biguint(sign, BigUint::new(digits)) } /// Creates and initializes a `BigInt`. @@ -1334,7 +1326,7 @@ impl BigInt { if sign == Zero || data.is_zero() { return BigInt { sign: Zero, data: Zero::zero() }; } - return BigInt { sign: sign, data: data }; + BigInt { sign: sign, data: data } } /// Creates and initializes a `BigInt`. @@ -1344,8 +1336,7 @@ impl BigInt { } /// Creates and initializes a `BigInt`. - pub fn parse_bytes(buf: &[u8], radix: uint) - -> Option { + pub fn parse_bytes(buf: &[u8], radix: uint) -> Option { if buf.is_empty() { return None; } let mut sign = Plus; let mut start = 0; From 5eb4d19dc35dc59aaeaf3d53759c9b0341148ef8 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 8 Jun 2014 17:10:27 -0700 Subject: [PATCH 04/11] Add a --color flag to test binaries It uses the same behavior as rustc's. --- src/compiletest/compiletest.rs | 1 + src/libtest/lib.rs | 35 ++++++++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index de0ca4971f5..977b7dc32c5 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -292,6 +292,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts { save_metrics: config.save_metrics.clone(), test_shard: config.test_shard.clone(), nocapture: false, + color: test::AutoColor, } } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 9e562a08ff9..7d94e46a88a 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -271,6 +271,12 @@ pub fn test_main_static_x(args: &[~str], tests: &[TestDescAndFn]) { tests) } +pub enum ColorConfig { + AutoColor, + AlwaysColor, + NeverColor, +} + pub struct TestOpts { pub filter: Option, pub run_ignored: bool, @@ -282,6 +288,7 @@ pub struct TestOpts { pub test_shard: Option<(uint,uint)>, pub logfile: Option, pub nocapture: bool, + pub color: ColorConfig, } impl TestOpts { @@ -298,6 +305,7 @@ impl TestOpts { test_shard: None, logfile: None, nocapture: false, + color: AutoColor, } } } @@ -324,7 +332,11 @@ fn optgroups() -> Vec { getopts::optopt("", "test-shard", "run shard A, of B shards, worth of the testsuite", "A.B"), getopts::optflag("", "nocapture", "don't capture stdout/stderr of each \ - task, allow printing directly")) + task, allow printing directly"), + getopts::optopt("", "color", "Configure coloring of output: + auto = colorize if stdout is a tty and tests are run on serially (default); + always = always colorize output; + never = never colorize output;", "auto|always|never")) } fn usage(binary: &str) { @@ -406,6 +418,16 @@ pub fn parse_opts(args: &[String]) -> Option { nocapture = os::getenv("RUST_TEST_NOCAPTURE").is_some(); } + let color = match matches.opt_str("color").as_ref().map(|s| s.as_slice()) { + Some("auto") | None => AutoColor, + Some("always") => AlwaysColor, + Some("never") => NeverColor, + + Some(v) => return Some(Err(format!("argument for --color must be \ + auto, always, or never (was {})", + v))), + }; + let test_opts = TestOpts { filter: filter, run_ignored: run_ignored, @@ -417,6 +439,7 @@ pub fn parse_opts(args: &[String]) -> Option { test_shard: test_shard, logfile: logfile, nocapture: nocapture, + color: color, }; Some(Ok(test_opts)) @@ -492,7 +515,7 @@ impl ConsoleTestState { Ok(ConsoleTestState { out: out, log_out: log_out, - use_color: use_color(), + use_color: use_color(opts), total: 0u, passed: 0u, failed: 0u, @@ -867,8 +890,12 @@ fn should_sort_failures_before_printing_them() { assert!(apos < bpos); } -fn use_color() -> bool { - get_concurrency() == 1 && io::stdout().get_ref().isatty() +fn use_color(opts: &TestOpts) -> bool { + match opts.color { + AutoColor => get_concurrency() == 1 && io::stdout().get_ref().isatty(), + AlwaysColor => true, + NeverColor => false, + } } #[deriving(Clone)] From 1635ef2a1958749e7b0cf4e812e1a87cd919027f Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 8 Jun 2014 20:12:10 -0700 Subject: [PATCH 05/11] std: Move dynamic_lib from std::unstable to std This leaves a deprecated reexport in place temporarily. Closes #1457. --- src/compiletest/procsrv.rs | 2 +- src/librustc/metadata/filesearch.rs | 2 +- src/librustc/plugin/load.rs | 2 +- src/librustdoc/plugins.rs | 2 +- src/librustdoc/test.rs | 2 +- src/libstd/{unstable => }/dynamic_lib.rs | 3 +++ src/libstd/lib.rs | 13 +++++++++---- src/libstd/rt/backtrace.rs | 2 +- src/libstd/unstable/mod.rs | 13 ------------- src/test/auxiliary/linkage-visibility.rs | 2 +- src/test/run-make/extern-fn-reachable/main.rs | 2 +- src/test/run-pass/linkage-visibility.rs | 2 +- 12 files changed, 21 insertions(+), 26 deletions(-) rename src/libstd/{unstable => }/dynamic_lib.rs (99%) delete mode 100644 src/libstd/unstable/mod.rs diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index a48a9f1be75..8fa34dd6d27 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -11,7 +11,7 @@ use std::os; use std::str; use std::io::process::{ProcessExit, Command, Process, ProcessOutput}; -use std::unstable::dynamic_lib::DynamicLibrary; +use std::dynamic_lib::DynamicLibrary; fn target_env(lib_path: &str, prog: &str) -> Vec<(String, String)> { let prog = if cfg!(windows) {prog.slice_to(prog.len() - 4)} else {prog}; diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 9033b83d474..ec46e7f8592 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -13,7 +13,7 @@ use std::cell::RefCell; use std::os; use std::io::fs; -use std::unstable::dynamic_lib::DynamicLibrary; +use std::dynamic_lib::DynamicLibrary; use std::collections::HashSet; use myfs = util::fs; diff --git a/src/librustc/plugin/load.rs b/src/librustc/plugin/load.rs index ba50a15a82b..97ffcf279ae 100644 --- a/src/librustc/plugin/load.rs +++ b/src/librustc/plugin/load.rs @@ -16,7 +16,7 @@ use plugin::registry::Registry; use std::mem; use std::os; -use std::unstable::dynamic_lib::DynamicLibrary; +use std::dynamic_lib::DynamicLibrary; use syntax::ast; use syntax::attr; use syntax::visit; diff --git a/src/librustdoc/plugins.rs b/src/librustdoc/plugins.rs index 7a796e97f41..fee1d63a274 100644 --- a/src/librustdoc/plugins.rs +++ b/src/librustdoc/plugins.rs @@ -10,7 +10,7 @@ use clean; -use dl = std::unstable::dynamic_lib; +use dl = std::dynamic_lib; use serialize::json; use std::string::String; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 34363058297..0d777641274 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -15,7 +15,7 @@ use std::io::{Command, TempDir}; use std::os; use std::str; use std::string::String; -use std::unstable::dynamic_lib::DynamicLibrary; +use std::dynamic_lib::DynamicLibrary; use std::collections::{HashSet, HashMap}; use testing; diff --git a/src/libstd/unstable/dynamic_lib.rs b/src/libstd/dynamic_lib.rs similarity index 99% rename from src/libstd/unstable/dynamic_lib.rs rename to src/libstd/dynamic_lib.rs index 6980c5cc0c2..fa6efc8a4b1 100644 --- a/src/libstd/unstable/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -16,6 +16,9 @@ A simple wrapper over the platform's dynamic library facilities */ +#![experimental] +#![allow(missing_doc)] + use clone::Clone; use c_str::ToCStr; use iter::Iterator; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 85813c02d55..e147997334c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -241,15 +241,12 @@ pub mod sync; /* Runtime and platform support */ pub mod c_vec; +pub mod dynamic_lib; pub mod os; pub mod io; pub mod path; pub mod fmt; -// Private APIs -#[unstable] -pub mod unstable; - // FIXME #7809: This shouldn't be pub, and it should be reexported under 'unstable' // but name resolution doesn't work without it being pub. #[unstable] @@ -279,3 +276,11 @@ mod std { // The test runner requires std::slice::Vector, so re-export std::slice just for it. #[cfg(test)] pub use slice; } + +#[deprecated] +#[allow(missing_doc)] +#[doc(hiden)] +pub mod unstable { + #[deprecated = "use std::dynamic_lib"] + pub use dynamic_lib; +} diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index 83fc95267af..423f372f018 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -614,7 +614,7 @@ mod imp { use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; use slice::ImmutableVector; use str::StrSlice; - use unstable::dynamic_lib::DynamicLibrary; + use dynamic_lib::DynamicLibrary; #[allow(non_snake_case_functions)] extern "system" { diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs deleted file mode 100644 index 985ef2e142c..00000000000 --- a/src/libstd/unstable/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![doc(hidden)] - -pub mod dynamic_lib; diff --git a/src/test/auxiliary/linkage-visibility.rs b/src/test/auxiliary/linkage-visibility.rs index 4ae0b6f14f5..0b4bea49fa2 100644 --- a/src/test/auxiliary/linkage-visibility.rs +++ b/src/test/auxiliary/linkage-visibility.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::unstable::dynamic_lib::DynamicLibrary; +use std::dynamic_lib::DynamicLibrary; #[no_mangle] pub fn foo() { bar(); } diff --git a/src/test/run-make/extern-fn-reachable/main.rs b/src/test/run-make/extern-fn-reachable/main.rs index e05d43145d7..0f759efb025 100644 --- a/src/test/run-make/extern-fn-reachable/main.rs +++ b/src/test/run-make/extern-fn-reachable/main.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::unstable::dynamic_lib::DynamicLibrary; +use std::dynamic_lib::DynamicLibrary; use std::os; pub fn main() { diff --git a/src/test/run-pass/linkage-visibility.rs b/src/test/run-pass/linkage-visibility.rs index e263767990a..58f66314e44 100644 --- a/src/test/run-pass/linkage-visibility.rs +++ b/src/test/run-pass/linkage-visibility.rs @@ -10,7 +10,7 @@ // aux-build:linkage-visibility.rs // ignore-android: FIXME(#10379) -// ignore-win32: std::unstable::dynamic_lib does not work on win32 well +// ignore-win32: std::dynamic_lib does not work on win32 well extern crate foo = "linkage-visibility"; From 810ddfd611f5a56980df0c05e10e751203710d81 Mon Sep 17 00:00:00 2001 From: Piotr Jawniak Date: Mon, 9 Jun 2014 07:44:49 +0200 Subject: [PATCH 06/11] Add test for issue #13446 Closes #13446 --- src/test/compile-fail/issue-13446.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/compile-fail/issue-13446.rs diff --git a/src/test/compile-fail/issue-13446.rs b/src/test/compile-fail/issue-13446.rs new file mode 100644 index 00000000000..0bb6ded0012 --- /dev/null +++ b/src/test/compile-fail/issue-13446.rs @@ -0,0 +1,17 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// Used to cause ICE + +static VEC: [u32, ..256] = vec!(); //~ ERROR mismatched types + +fn main() {} + From d6a39419dbcb2e31ce0711440eab3e8155e69286 Mon Sep 17 00:00:00 2001 From: Tom Jakubowski Date: Mon, 9 Jun 2014 00:30:04 -0700 Subject: [PATCH 07/11] collections: Add missing Default impls Add Default impls for TreeMap, TreeSet, SmallIntMap, BitvSet, DList, PriorityQueue, RingBuf, TrieMap, and TrieSet. --- src/libcollections/bitv.rs | 6 ++++++ src/libcollections/dlist.rs | 6 ++++++ src/libcollections/priority_queue.rs | 6 ++++++ src/libcollections/ringbuf.rs | 6 ++++++ src/libcollections/smallintmap.rs | 6 ++++++ src/libcollections/treemap.rs | 11 +++++++++++ src/libcollections/trie.rs | 11 +++++++++++ 7 files changed, 52 insertions(+) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index 42c81779770..e100baa1e3a 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -13,6 +13,7 @@ use core::prelude::*; use core::cmp; +use core::default::Default; use core::fmt; use core::iter::{Enumerate, Repeat, Map, Zip}; use core::ops; @@ -698,6 +699,11 @@ pub struct BitvSet { bitv: BigBitv } +impl Default for BitvSet { + #[inline] + fn default() -> BitvSet { BitvSet::new() } +} + impl BitvSet { /// Creates a new bit vector set with initially no contents pub fn new() -> BitvSet { diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index 5a231245691..ac8c5c5557e 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -24,6 +24,7 @@ use core::prelude::*; use alloc::owned::Box; +use core::default::Default; use core::fmt; use core::iter; use core::mem; @@ -262,6 +263,11 @@ impl Deque for DList { } } +impl Default for DList { + #[inline] + fn default() -> DList { DList::new() } +} + impl DList { /// Create an empty DList #[inline] diff --git a/src/libcollections/priority_queue.rs b/src/libcollections/priority_queue.rs index ea3e7d17471..f25864933f2 100644 --- a/src/libcollections/priority_queue.rs +++ b/src/libcollections/priority_queue.rs @@ -14,6 +14,7 @@ use core::prelude::*; +use core::default::Default; use core::mem::{zeroed, replace, swap}; use core::ptr; @@ -37,6 +38,11 @@ impl Mutable for PriorityQueue { fn clear(&mut self) { self.data.truncate(0) } } +impl Default for PriorityQueue { + #[inline] + fn default() -> PriorityQueue { PriorityQueue::new() } +} + impl PriorityQueue { /// An iterator visiting all values in underlying vector, in /// arbitrary order. diff --git a/src/libcollections/ringbuf.rs b/src/libcollections/ringbuf.rs index addf73d67a8..ae1925126ca 100644 --- a/src/libcollections/ringbuf.rs +++ b/src/libcollections/ringbuf.rs @@ -16,6 +16,7 @@ use core::prelude::*; use core::cmp; +use core::default::Default; use core::fmt; use core::iter::RandomAccessIterator; @@ -112,6 +113,11 @@ impl Deque for RingBuf { } } +impl Default for RingBuf { + #[inline] + fn default() -> RingBuf { RingBuf::new() } +} + impl RingBuf { /// Create an empty RingBuf pub fn new() -> RingBuf { diff --git a/src/libcollections/smallintmap.rs b/src/libcollections/smallintmap.rs index cc901864ab5..6b4982de082 100644 --- a/src/libcollections/smallintmap.rs +++ b/src/libcollections/smallintmap.rs @@ -17,6 +17,7 @@ use core::prelude::*; +use core::default::Default; use core::fmt; use core::iter::{Enumerate, FilterMap}; use core::mem::replace; @@ -114,6 +115,11 @@ impl MutableMap for SmallIntMap { } } +impl Default for SmallIntMap { + #[inline] + fn default() -> SmallIntMap { SmallIntMap::new() } +} + impl SmallIntMap { /// Create an empty SmallIntMap pub fn new() -> SmallIntMap { SmallIntMap{v: vec!()} } diff --git a/src/libcollections/treemap.rs b/src/libcollections/treemap.rs index 489fe60cebf..1f4ee52008c 100644 --- a/src/libcollections/treemap.rs +++ b/src/libcollections/treemap.rs @@ -15,6 +15,7 @@ use core::prelude::*; use alloc::owned::Box; +use core::default::Default; use core::fmt; use core::fmt::Show; use core::iter::Peekable; @@ -135,6 +136,11 @@ impl MutableMap for TreeMap { } } +impl Default for TreeMap { + #[inline] + fn default() -> TreeMap { TreeMap::new() } +} + impl TreeMap { /// Create an empty TreeMap pub fn new() -> TreeMap { TreeMap{root: None, length: 0} } @@ -633,6 +639,11 @@ impl MutableSet for TreeSet { fn remove(&mut self, value: &T) -> bool { self.map.remove(value) } } +impl Default for TreeSet { + #[inline] + fn default() -> TreeSet { TreeSet::new() } +} + impl TreeSet { /// Create an empty TreeSet #[inline] diff --git a/src/libcollections/trie.rs b/src/libcollections/trie.rs index 6e99d6054a5..3f4fdd66b80 100644 --- a/src/libcollections/trie.rs +++ b/src/libcollections/trie.rs @@ -13,6 +13,7 @@ use core::prelude::*; use alloc::owned::Box; +use core::default::Default; use core::mem::zeroed; use core::mem; use core::uint; @@ -105,6 +106,11 @@ impl MutableMap for TrieMap { } } +impl Default for TrieMap { + #[inline] + fn default() -> TrieMap { TrieMap::new() } +} + impl TrieMap { /// Create an empty TrieMap #[inline] @@ -332,6 +338,11 @@ impl MutableSet for TrieSet { } } +impl Default for TrieSet { + #[inline] + fn default() -> TrieSet { TrieSet::new() } +} + impl TrieSet { /// Create an empty TrieSet #[inline] From 05810604c8f1ecebe35a8676df7371487ec80513 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Tue, 10 Jun 2014 00:31:31 +1000 Subject: [PATCH 08/11] native: add more info to the native unimplemented error. This refers to green, which (AFAICT) has everything implemented. In particular, this will help guide people to get working signal handling via libgreen. --- src/libnative/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index 3b0dbe2d0dc..4c5929ef223 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -77,7 +77,7 @@ fn unimpl() -> IoError { IoError { code: ERROR as uint, extra: 0, - detail: None, + detail: Some("not yet supported by the `native` runtime, maybe try `green`.".to_string()), } } From 14668f2791c4893b84ae4111c52dee07c79faac7 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Tue, 10 Jun 2014 00:33:04 +1000 Subject: [PATCH 09/11] std: adjust the TCP io doc example to work reliably. Fixes #11576 by making the code never run (and hence never pass when the test was marked `should_fail`). --- src/libstd/io/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 6f3eec01e8e..a1e0fa88978 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -81,13 +81,18 @@ Some examples of obvious things you might want to do * Make a simple TCP client connection and request - ```rust,should_fail + ```rust # #![allow(unused_must_use)] use std::io::net::tcp::TcpStream; + # // connection doesn't fail if a server is running on 8080 + # // locally, we still want to be type checking this code, so lets + # // just stop it running (#11576) + # if false { let mut socket = TcpStream::connect("127.0.0.1", 8080).unwrap(); socket.write(bytes!("GET / HTTP/1.0\n\n")); let response = socket.read_to_end(); + # } ``` * Make a simple TCP server From 24cbe384236b28512f0b8bc22343fbe4c4481c62 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 9 Jun 2014 12:56:37 -0700 Subject: [PATCH 10/11] rustdoc: Correctly classify enums/typedefs Both of these items are surfaced as a DefTy, so some extra logic was needed in the decoder module to figure out whether one is actually an enum or whether it's a typedef. Closes #14757 --- src/librustc/metadata/csearch.rs | 5 +++++ src/librustc/metadata/decoder.rs | 8 ++++++++ src/librustdoc/clean/inline.rs | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index c7ad74dce57..0a88abd67d9 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -321,3 +321,8 @@ pub fn get_reachable_extern_fns(cstore: &cstore::CStore, cnum: ast::CrateNum) let cdata = cstore.get_crate_data(cnum); decoder::get_reachable_extern_fns(&*cdata) } + +pub fn is_typedef(cstore: &cstore::CStore, did: ast::DefId) -> bool { + let cdata = cstore.get_crate_data(did.krate); + decoder::is_typedef(&*cdata, did.node) +} diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 8a2c3c08d41..56d6766e1b7 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -1339,3 +1339,11 @@ pub fn get_reachable_extern_fns(cdata: Cmd) -> Vec { }); return ret; } + +pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool { + let item_doc = lookup_item(id, cdata.data()); + match item_family(item_doc) { + Type => true, + _ => false, + } +} diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 2a4774ffd84..d243c61ddaf 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -203,7 +203,7 @@ fn build_struct(tcx: &ty::ctxt, did: ast::DefId) -> clean::Struct { fn build_type(tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEnum { let t = ty::lookup_item_type(tcx, did); match ty::get(t.ty).sty { - ty::ty_enum(edid, _) => { + ty::ty_enum(edid, _) if !csearch::is_typedef(&tcx.sess.cstore, did) => { return clean::EnumItem(clean::Enum { generics: t.generics.clean(), variants_stripped: false, From 5ede96c2fd62a63e75cb5faf073933d914f3eeaf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 9 Jun 2014 19:55:28 -0700 Subject: [PATCH 11/11] Test fixes from rollup --- src/libnative/io/file_win32.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libnative/io/file_win32.rs b/src/libnative/io/file_win32.rs index 0e6c5c744f4..5ace8e347c6 100644 --- a/src/libnative/io/file_win32.rs +++ b/src/libnative/io/file_win32.rs @@ -18,7 +18,7 @@ use std::mem; use std::os::win32::fill_utf16_buf_and_decode; use std::ptr; use std::rt::rtio; -use std::rt::rtio::IoResult; +use std::rt::rtio::{IoResult, IoError}; use std::str; use std::vec; @@ -412,7 +412,7 @@ pub fn rename(old: &CString, new: &CString) -> IoResult<()> { pub fn chmod(p: &CString, mode: uint) -> IoResult<()> { let p = try!(to_utf16(p)); super::mkerr_libc(unsafe { - libc::wchmod(p.as_ptr(), mode.bits() as libc::c_int) + libc::wchmod(p.as_ptr(), mode as libc::c_int) }) }