diff options
Diffstat (limited to 'src/libcore')
72 files changed, 2928 insertions, 790 deletions
diff --git a/src/libcore/bool.rs b/src/libcore/bool.rs index 6c60cec2595..1b4b81dca26 100644 --- a/src/libcore/bool.rs +++ b/src/libcore/bool.rs @@ -108,8 +108,6 @@ mod tests { #[test] fn test_bool_from_str() { - use from_str::FromStr; - do all_values |v| { assert!(Some(v) == FromStr::from_str(to_str(v))) } diff --git a/src/libcore/cast.rs b/src/libcore/cast.rs index 6fb737d3770..96e1c3bd124 100644 --- a/src/libcore/cast.rs +++ b/src/libcore/cast.rs @@ -19,35 +19,11 @@ pub mod rusti { pub extern "rust-intrinsic" { fn forget<T>(+x: T); - #[cfg(stage0)] - fn reinterpret_cast<T, U>(&&e: T) -> U; - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn transmute<T,U>(e: T) -> U; } } /// Casts the value at `src` to U. The two types must have the same length. -#[inline(always)] -#[cfg(stage0)] -pub unsafe fn reinterpret_cast<T, U>(src: &T) -> U { - rusti::reinterpret_cast(*src) -} - -/// Unsafely copies and casts the value at `src` to U, even if the value is -/// noncopyable. The two types must have the same length. -#[inline(always)] -#[cfg(stage0)] -pub unsafe fn transmute_copy<T, U>(src: &T) -> U { - rusti::reinterpret_cast(*src) -} - -#[inline(always)] -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub unsafe fn transmute_copy<T, U>(src: &T) -> U { let mut dest: U = unstable::intrinsics::init(); { @@ -88,17 +64,6 @@ pub unsafe fn bump_box_refcount<T>(t: @T) { forget(t); } * assert!(transmute("L") == ~[76u8, 0u8]); */ #[inline(always)] -#[cfg(stage0)] -pub unsafe fn transmute<L, G>(thing: L) -> G { - let newthing: G = reinterpret_cast(&thing); - forget(thing); - newthing -} - -#[inline(always)] -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub unsafe fn transmute<L, G>(thing: L) -> G { rusti::transmute(thing) } @@ -159,15 +124,6 @@ mod tests { use cast::{bump_box_refcount, transmute}; #[test] - #[cfg(stage0)] - fn test_reinterpret_cast() { - assert!(1u == unsafe { ::cast::reinterpret_cast(&1) }); - } - - #[test] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn test_transmute_copy() { assert!(1u == unsafe { ::cast::transmute_copy(&1) }); } diff --git a/src/libcore/char.rs b/src/libcore/char.rs index ef2bd91e973..7868b463807 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -10,6 +10,7 @@ //! Utilities for manipulating the char type +#[cfg(notest)] use cmp::Ord; use option::{None, Option, Some}; use str; diff --git a/src/libcore/cleanup.rs b/src/libcore/cleanup.rs index 3f7366c6c45..435b1cb7f34 100644 --- a/src/libcore/cleanup.rs +++ b/src/libcore/cleanup.rs @@ -258,4 +258,3 @@ pub mod rustrt { pub unsafe fn rust_get_task() -> *c_void; } } - diff --git a/src/libcore/condition.rs b/src/libcore/condition.rs index dc6c80228dd..1240fe03dd5 100644 --- a/src/libcore/condition.rs +++ b/src/libcore/condition.rs @@ -192,4 +192,27 @@ mod test { assert!(trapped); } + + // Issue #6009 + mod m { + condition! { + sadness: int -> int; + } + + mod n { + use super::sadness; + + #[test] + fn test_conditions_are_public() { + let mut trapped = false; + do sadness::cond.trap(|_| { + trapped = true; + 0 + }).in { + sadness::cond.raise(0); + } + assert!(trapped); + } + } + } } diff --git a/src/libcore/core.rc b/src/libcore/core.rc index f6e4056f3d0..9672bf887ca 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -63,7 +63,6 @@ they contained the following prologue: #[warn(vecs_implicitly_copyable)]; #[deny(non_camel_case_types)]; #[allow(deprecated_mutable_fields)]; -#[allow(deprecated_drop)]; // Make core testable by not duplicating lang items. See #2912 #[cfg(test)] extern mod realcore(name = "core", vers = "0.7-pre"); @@ -75,7 +74,7 @@ they contained the following prologue: pub use kinds::{Const, Copy, Owned, Durable}; pub use ops::{Drop}; -pub use ops::{Add, Sub, Mul, Quot, Rem, Neg, Not}; +pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Shl, Shr, Index}; @@ -109,6 +108,7 @@ pub use num::{Bitwise, BitCount, Bounded}; pub use num::{Primitive, Int, Float}; pub use ptr::Ptr; +pub use from_str::FromStr; pub use to_str::ToStr; pub use clone::Clone; @@ -122,6 +122,9 @@ pub mod linkhack { } } +// Internal macros +mod macros; + /* The Prelude. */ pub mod prelude; @@ -261,12 +264,3 @@ mod core { pub use sys; pub use pipes; } - - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/either.rs b/src/libcore/either.rs index 92f850cddd6..33b7e81ee85 100644 --- a/src/libcore/either.rs +++ b/src/libcore/either.rs @@ -263,13 +263,3 @@ fn test_partition_empty() { assert_eq!(vec::len(lefts), 0u); assert_eq!(vec::len(rights), 0u); } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index 8ed54741f12..9b01c1dad06 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -678,7 +678,7 @@ pub impl <T:Hash + Eq> HashSet<T> { } } -#[test] +#[cfg(test)] mod test_map { use container::{Container, Map, Set}; use option::{None, Some}; @@ -854,7 +854,7 @@ mod test_map { } } -#[test] +#[cfg(test)] mod test_set { use super::*; use container::{Container, Map, Set}; diff --git a/src/libcore/io.rs b/src/libcore/io.rs index 217ea1a9982..460fd60d4c5 100644 --- a/src/libcore/io.rs +++ b/src/libcore/io.rs @@ -1954,13 +1954,3 @@ mod tests { } } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 7476531ef94..8fc2db6d6f1 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -41,6 +41,9 @@ much easier to implement. */ +use cmp::Ord; +use option::{Option, Some, None}; + pub trait Times { fn times(&self, it: &fn() -> bool); } @@ -104,6 +107,78 @@ pub fn all<T>(predicate: &fn(T) -> bool, iter: &fn(f: &fn(T) -> bool)) -> bool { true } +/** + * Return the first element where `predicate` returns `true`. Return `None` if no element is found. + * + * # Example: + * + * ~~~~ + * let xs = ~[1u, 2, 3, 4, 5, 6]; + * assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.each(f)).unwrap(), 4); + * ~~~~ + */ +#[inline(always)] +pub fn find<T>(predicate: &fn(&T) -> bool, iter: &fn(f: &fn(T) -> bool)) -> Option<T> { + for iter |x| { + if predicate(&x) { + return Some(x); + } + } + None +} + +/** + * Return the largest item yielded by an iterator. Return `None` if the iterator is empty. + * + * # Example: + * + * ~~~~ + * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; + * assert_eq!(max(|f| xs.each(f)).unwrap(), &15); + * ~~~~ + */ +#[inline] +pub fn max<T: Ord>(iter: &fn(f: &fn(T) -> bool)) -> Option<T> { + let mut result = None; + for iter |x| { + match result { + Some(ref mut y) => { + if x > *y { + *y = x; + } + } + None => result = Some(x) + } + } + result +} + +/** + * Return the smallest item yielded by an iterator. Return `None` if the iterator is empty. + * + * # Example: + * + * ~~~~ + * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; + * assert_eq!(max(|f| xs.each(f)).unwrap(), &-5); + * ~~~~ + */ +#[inline] +pub fn min<T: Ord>(iter: &fn(f: &fn(T) -> bool)) -> Option<T> { + let mut result = None; + for iter |x| { + match result { + Some(ref mut y) => { + if x < *y { + *y = x; + } + } + None => result = Some(x) + } + } + result +} + #[cfg(test)] mod tests { use super::*; @@ -128,4 +203,22 @@ mod tests { assert!(all(|x: uint| x < 6, |f| uint::range(1, 6, f))); assert!(!all(|x: uint| x < 5, |f| uint::range(1, 6, f))); } + + #[test] + fn test_find() { + let xs = ~[1u, 2, 3, 4, 5, 6]; + assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.each(f)).unwrap(), 4); + } + + #[test] + fn test_max() { + let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; + assert_eq!(max(|f| xs.each(f)).unwrap(), &15); + } + + #[test] + fn test_min() { + let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; + assert_eq!(min(|f| xs.each(f)).unwrap(), &-5); + } } diff --git a/src/libcore/iterator.rs b/src/libcore/iterator.rs index 8bbf8430858..5e95485b273 100644 --- a/src/libcore/iterator.rs +++ b/src/libcore/iterator.rs @@ -29,7 +29,7 @@ pub trait Iterator<A> { /// /// In the future these will be default methods instead of a utility trait. pub trait IteratorUtil<A> { - fn chain(self, other: Self) -> ChainIterator<Self>; + fn chain<U: Iterator<A>>(self, other: U) -> ChainIterator<Self, U>; fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<Self, U>; // FIXME: #5898: should be called map fn transform<'r, B>(self, f: &'r fn(A) -> B) -> MapIterator<'r, A, B, Self>; @@ -50,7 +50,7 @@ pub trait IteratorUtil<A> { /// In the future these will be default methods instead of a utility trait. impl<A, T: Iterator<A>> IteratorUtil<A> for T { #[inline(always)] - fn chain(self, other: T) -> ChainIterator<T> { + fn chain<U: Iterator<A>>(self, other: U) -> ChainIterator<T, U> { ChainIterator{a: self, b: other, flag: false} } @@ -115,13 +115,13 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { } } -pub struct ChainIterator<T> { +pub struct ChainIterator<T, U> { priv a: T, - priv b: T, + priv b: U, priv flag: bool } -impl<A, T: Iterator<A>> Iterator<A> for ChainIterator<T> { +impl<A, T: Iterator<A>, U: Iterator<A>> Iterator<A> for ChainIterator<T, U> { #[inline] fn next(&mut self) -> Option<A> { if self.flag { @@ -385,7 +385,7 @@ mod tests { #[test] fn test_iterator_chain() { let xs = [0u, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; + let ys = [30u, 40, 50, 60]; let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; let mut it = xs.iter().chain(ys.iter()); let mut i = 0; @@ -394,6 +394,15 @@ mod tests { i += 1; } assert_eq!(i, expected.len()); + + let ys = Counter::new(30u, 10).take(4); + let mut it = xs.iter().transform(|&x| x).chain(ys); + let mut i = 0; + for it.advance |x: uint| { + assert_eq!(x, expected[i]); + i += 1; + } + assert_eq!(i, expected.len()); } #[test] diff --git a/src/libcore/libc.rs b/src/libcore/libc.rs index d7a9ab4d63b..6fb4572913d 100644 --- a/src/libcore/libc.rs +++ b/src/libcore/libc.rs @@ -104,6 +104,7 @@ pub use libc::funcs::posix88::unistd::*; pub use libc::funcs::posix01::stat_::*; pub use libc::funcs::posix01::unistd::*; +pub use libc::funcs::posix01::glob::*; pub use libc::funcs::posix08::unistd::*; pub use libc::funcs::bsd44::*; @@ -210,7 +211,21 @@ pub mod types { #[cfg(target_os = "android")] pub mod os { pub mod common { - pub mod posix01 {} + pub mod posix01 { + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{c_char, size_t}; + pub struct glob_t { + gl_pathc: size_t, + gl_pathv: **c_char, + gl_offs: size_t, + + __unused1: *c_void, + __unused2: *c_void, + __unused3: *c_void, + __unused4: *c_void, + __unused5: *c_void, + } + } } #[cfg(target_arch = "x86")] @@ -368,7 +383,25 @@ pub mod types { #[cfg(target_os = "freebsd")] pub mod os { pub mod common { - pub mod posix01 {} + pub mod posix01 { + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{c_char, c_int, size_t}; + pub struct glob_t { + gl_pathc: size_t, + __unused1: size_t, + gl_offs: size_t, + __unused2: c_int, + gl_pathv: **c_char, + + __unused3: *c_void, + + __unused4: *c_void, + __unused5: *c_void, + __unused6: *c_void, + __unused7: *c_void, + __unused8: *c_void, + } + } } #[cfg(target_arch = "x86_64")] @@ -548,12 +581,16 @@ pub mod types { pub type LPWSTR = *mut WCHAR; pub type LPSTR = *mut CHAR; + pub type LPTSTR = *mut CHAR; // Not really, but opaque to us. pub type LPSECURITY_ATTRIBUTES = LPVOID; pub type LPVOID = *mut c_void; + pub type LPBYTE = *mut BYTE; pub type LPWORD = *mut WORD; + pub type LPDWORD = *mut DWORD; + pub type LPHANDLE = *mut HANDLE; pub type LRESULT = LONG_PTR; pub type PBOOL = *mut BOOL; @@ -562,6 +599,36 @@ pub mod types { pub type time64_t = i64; pub type int64 = i64; + + pub struct STARTUPINFO { + cb: DWORD, + lpReserved: LPTSTR, + lpDesktop: LPTSTR, + lpTitle: LPTSTR, + dwX: DWORD, + dwY: DWORD, + dwXSize: DWORD, + dwYSize: DWORD, + dwXCountChars: DWORD, + dwYCountCharts: DWORD, + dwFillAttribute: DWORD, + dwFlags: DWORD, + wShowWindow: WORD, + cbReserved2: WORD, + lpReserved2: LPBYTE, + hStdInput: HANDLE, + hStdOutput: HANDLE, + hStdError: HANDLE + } + pub type LPSTARTUPINFO = *mut STARTUPINFO; + + pub struct PROCESS_INFORMATION { + hProcess: HANDLE, + hThread: HANDLE, + dwProcessId: DWORD, + dwThreadId: DWORD + } + pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION; } } } @@ -570,6 +637,23 @@ pub mod types { pub mod os { pub mod common { pub mod posix01 { + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{c_char, c_int, size_t}; + pub struct glob_t { + gl_pathc: size_t, + __unused1: c_int, + gl_offs: size_t, + __unused2: c_int, + gl_pathv: **c_char, + + __unused3: *c_void, + + __unused4: *c_void, + __unused5: *c_void, + __unused6: *c_void, + __unused7: *c_void, + __unused8: *c_void, + } } } @@ -797,6 +881,11 @@ pub mod consts { pub mod bsd44 { } pub mod extra { + use libc::types::os::arch::extra::{DWORD, BOOL}; + + pub static TRUE : BOOL = 1; + pub static FALSE : BOOL = 0; + pub static O_TEXT : int = 16384; pub static O_BINARY : int = 32768; pub static O_NOINHERIT: int = 128; @@ -804,6 +893,50 @@ pub mod consts { pub static ERROR_SUCCESS : int = 0; pub static ERROR_INSUFFICIENT_BUFFER : int = 122; pub static INVALID_HANDLE_VALUE: int = -1; + + pub static DELETE : DWORD = 0x00010000; + pub static READ_CONTROL : DWORD = 0x00020000; + pub static SYNCHRONIZE : DWORD = 0x00100000; + pub static WRITE_DAC : DWORD = 0x00040000; + pub static WRITE_OWNER : DWORD = 0x00080000; + + pub static PROCESS_CREATE_PROCESS : DWORD = 0x0080; + pub static PROCESS_CREATE_THREAD : DWORD = 0x0002; + pub static PROCESS_DUP_HANDLE : DWORD = 0x0040; + pub static PROCESS_QUERY_INFORMATION : DWORD = 0x0400; + pub static PROCESS_QUERY_LIMITED_INFORMATION : DWORD = 0x1000; + pub static PROCESS_SET_INFORMATION : DWORD = 0x0200; + pub static PROCESS_SET_QUOTA : DWORD = 0x0100; + pub static PROCESS_SUSPEND_RESUME : DWORD = 0x0800; + pub static PROCESS_TERMINATE : DWORD = 0x0001; + pub static PROCESS_VM_OPERATION : DWORD = 0x0008; + pub static PROCESS_VM_READ : DWORD = 0x0010; + pub static PROCESS_VM_WRITE : DWORD = 0x0020; + + pub static STARTF_FORCEONFEEDBACK : DWORD = 0x00000040; + pub static STARTF_FORCEOFFFEEDBACK : DWORD = 0x00000080; + pub static STARTF_PREVENTPINNING : DWORD = 0x00002000; + pub static STARTF_RUNFULLSCREEN : DWORD = 0x00000020; + pub static STARTF_TITLEISAPPID : DWORD = 0x00001000; + pub static STARTF_TITLEISLINKNAME : DWORD = 0x00000800; + pub static STARTF_USECOUNTCHARS : DWORD = 0x00000008; + pub static STARTF_USEFILLATTRIBUTE : DWORD = 0x00000010; + pub static STARTF_USEHOTKEY : DWORD = 0x00000200; + pub static STARTF_USEPOSITION : DWORD = 0x00000004; + pub static STARTF_USESHOWWINDOW : DWORD = 0x00000001; + pub static STARTF_USESIZE : DWORD = 0x00000002; + pub static STARTF_USESTDHANDLES : DWORD = 0x00000100; + + pub static WAIT_ABANDONED : DWORD = 0x00000080; + pub static WAIT_OBJECT_0 : DWORD = 0x00000000; + pub static WAIT_TIMEOUT : DWORD = 0x00000102; + pub static WAIT_FAILED : DWORD = -1; + + pub static DUPLICATE_CLOSE_SOURCE : DWORD = 0x00000001; + pub static DUPLICATE_SAME_ACCESS : DWORD = 0x00000002; + + pub static INFINITE : DWORD = -1; + pub static STILL_ACTIVE : DWORD = 259; } } @@ -876,6 +1009,18 @@ pub mod consts { } pub mod posix01 { pub static SIGTRAP : int = 5; + + pub static GLOB_ERR : int = 1 << 0; + pub static GLOB_MARK : int = 1 << 1; + pub static GLOB_NOSORT : int = 1 << 2; + pub static GLOB_DOOFFS : int = 1 << 3; + pub static GLOB_NOCHECK : int = 1 << 4; + pub static GLOB_APPEND : int = 1 << 5; + pub static GLOB_NOESCAPE : int = 1 << 6; + + pub static GLOB_NOSPACE : int = 1; + pub static GLOB_ABORTED : int = 2; + pub static GLOB_NOMATCH : int = 3; } pub mod posix08 { } @@ -955,6 +1100,18 @@ pub mod consts { } pub mod posix01 { pub static SIGTRAP : int = 5; + + pub static GLOB_APPEND : int = 0x0001; + pub static GLOB_DOOFFS : int = 0x0002; + pub static GLOB_ERR : int = 0x0004; + pub static GLOB_MARK : int = 0x0008; + pub static GLOB_NOCHECK : int = 0x0010; + pub static GLOB_NOSORT : int = 0x0020; + pub static GLOB_NOESCAPE : int = 0x2000; + + pub static GLOB_NOSPACE : int = -1; + pub static GLOB_ABORTED : int = -2; + pub static GLOB_NOMATCH : int = -3; } pub mod posix08 { } @@ -1035,6 +1192,18 @@ pub mod consts { } pub mod posix01 { pub static SIGTRAP : int = 5; + + pub static GLOB_APPEND : int = 0x0001; + pub static GLOB_DOOFFS : int = 0x0002; + pub static GLOB_ERR : int = 0x0004; + pub static GLOB_MARK : int = 0x0008; + pub static GLOB_NOCHECK : int = 0x0010; + pub static GLOB_NOSORT : int = 0x0020; + pub static GLOB_NOESCAPE : int = 0x2000; + + pub static GLOB_NOSPACE : int = -1; + pub static GLOB_ABORTED : int = -2; + pub static GLOB_NOMATCH : int = -3; } pub mod posix08 { } @@ -1605,6 +1774,21 @@ pub mod funcs { -> pid_t; } } + + #[nolink] + #[abi = "cdecl"] + pub mod glob { + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{c_char, c_int}; + use libc::types::os::common::posix01::{glob_t}; + + pub extern { + unsafe fn glob(pattern: *c_char, flags: c_int, + errfunc: *c_void, // XXX callback + pglob: *mut glob_t); + unsafe fn globfree(pglob: *mut glob_t); + } + } } #[cfg(target_os = "win32")] @@ -1614,6 +1798,9 @@ pub mod funcs { pub mod unistd { } + + pub mod glob { + } } @@ -1646,12 +1833,24 @@ pub mod funcs { unsafe fn sysctlnametomib(name: *c_char, mibp: *mut c_int, sizep: *mut size_t) -> c_int; + + unsafe fn getdtablesize() -> c_int; } } #[cfg(target_os = "linux")] #[cfg(target_os = "android")] + pub mod bsd44 { + use libc::types::os::arch::c95::{c_int}; + + #[abi = "cdecl"] + pub extern { + unsafe fn getdtablesize() -> c_int; + } + } + + #[cfg(target_os = "win32")] pub mod bsd44 { } @@ -1685,9 +1884,11 @@ pub mod funcs { pub mod kernel32 { use libc::types::os::arch::c95::{c_uint}; use libc::types::os::arch::extra::{BOOL, DWORD, HMODULE}; - use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPTCH}; - use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES}; - use libc::types::os::arch::extra::{HANDLE}; + use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPCTSTR, + LPTSTR, LPTCH, LPDWORD, LPVOID}; + use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, LPSTARTUPINFO, + LPPROCESS_INFORMATION}; + use libc::types::os::arch::extra::{HANDLE, LPHANDLE}; #[abi = "stdcall"] pub extern "stdcall" { @@ -1724,29 +1925,46 @@ pub mod funcs { findFileData: HANDLE) -> BOOL; unsafe fn FindClose(findFile: HANDLE) -> BOOL; + unsafe fn DuplicateHandle(hSourceProcessHandle: HANDLE, + hSourceHandle: HANDLE, + hTargetProcessHandle: HANDLE, + lpTargetHandle: LPHANDLE, + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwOptions: DWORD) -> BOOL; unsafe fn CloseHandle(hObject: HANDLE) -> BOOL; + unsafe fn OpenProcess(dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwProcessId: DWORD) -> HANDLE; + unsafe fn GetCurrentProcess() -> HANDLE; + unsafe fn CreateProcessA(lpApplicationName: LPCTSTR, + lpCommandLine: LPTSTR, + lpProcessAttributes: LPSECURITY_ATTRIBUTES, + lpThreadAttributes: LPSECURITY_ATTRIBUTES, + bInheritHandles: BOOL, + dwCreationFlags: DWORD, + lpEnvironment: LPVOID, + lpCurrentDirectory: LPCTSTR, + lpStartupInfo: LPSTARTUPINFO, + lpProcessInformation: LPPROCESS_INFORMATION) -> BOOL; + unsafe fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; unsafe fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) -> BOOL; + unsafe fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL; } } pub mod msvcrt { - use libc::types::os::arch::c95::c_int; + use libc::types::os::arch::c95::{c_int, c_long}; #[abi = "cdecl"] #[nolink] pub extern { #[link_name = "_commit"] unsafe fn commit(fd: c_int) -> c_int; + + #[link_name = "_get_osfhandle"] + unsafe fn get_osfhandle(fd: c_int) -> c_long; } } } } - - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/logging.rs b/src/libcore/logging.rs index ba976de50ab..afe8338f2ce 100644 --- a/src/libcore/logging.rs +++ b/src/libcore/logging.rs @@ -59,4 +59,3 @@ pub fn log_type<T>(level: u32, object: &T) { rustrt::rust_log_str(level, transmute(vec::raw::to_ptr(bytes)), len); } } - diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs new file mode 100644 index 00000000000..b19a753b715 --- /dev/null +++ b/src/libcore/macros.rs @@ -0,0 +1,39 @@ +// Copyright 2012 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[macro_escape]; + +// Some basic logging +macro_rules! rtdebug_ ( + ($( $arg:expr),+) => ( { + dumb_println(fmt!( $($arg),+ )); + + fn dumb_println(s: &str) { + use io::WriterUtil; + let dbg = ::libc::STDERR_FILENO as ::io::fd_t; + dbg.write_str(s); + dbg.write_str("\n"); + } + + } ) +) + +// An alternate version with no output, for turning off logging +macro_rules! rtdebug ( + ($( $arg:expr),+) => ( $(let _ = $arg)*; ) +) + +macro_rules! abort( + ($( $msg:expr),+) => ( { + rtdebug!($($msg),+); + + unsafe { ::libc::abort(); } + } ) +) diff --git a/src/libcore/num/cmath.rs b/src/libcore/num/cmath.rs index 30b0c54dc2d..8a0a88235d2 100644 --- a/src/libcore/num/cmath.rs +++ b/src/libcore/num/cmath.rs @@ -267,14 +267,3 @@ pub mod c_double_targ_consts { } */ - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// - diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 6398127a5fa..416ec2069b5 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -10,7 +10,6 @@ //! Operations and constants for `f32` -use from_str; use num::{Zero, One, strconv}; use prelude::*; @@ -123,7 +122,7 @@ pub fn sub(x: f32, y: f32) -> f32 { return x - y; } pub fn mul(x: f32, y: f32) -> f32 { return x * y; } #[inline(always)] -pub fn quot(x: f32, y: f32) -> f32 { return x / y; } +pub fn div(x: f32, y: f32) -> f32 { return x / y; } #[inline(always)] pub fn rem(x: f32, y: f32) -> f32 { return x % y; } @@ -278,11 +277,13 @@ impl Mul<f32,f32> for f32 { #[inline(always)] fn mul(&self, other: &f32) -> f32 { *self * *other } } + #[cfg(notest)] -impl Quot<f32,f32> for f32 { +impl Div<f32,f32> for f32 { #[inline(always)] - fn quot(&self, other: &f32) -> f32 { *self / *other } + fn div(&self, other: &f32) -> f32 { *self / *other } } + #[cfg(notest)] impl Rem<f32,f32> for f32 { #[inline(always)] @@ -791,7 +792,7 @@ pub fn from_str_radix(num: &str, rdx: uint) -> Option<f32> { strconv::ExpNone, false, false) } -impl from_str::FromStr for f32 { +impl FromStr for f32 { #[inline(always)] fn from_str(val: &str) -> Option<f32> { from_str(val) } } @@ -979,13 +980,3 @@ mod tests { assert_eq!(Primitive::bytes::<f32>(), sys::size_of::<f32>()); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 013f3c5095e..6e09ca61a7d 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -10,7 +10,6 @@ //! Operations and constants for `f64` -use from_str; use libc::c_int; use num::{Zero, One, strconv}; use prelude::*; @@ -149,7 +148,7 @@ pub fn sub(x: f64, y: f64) -> f64 { return x - y; } pub fn mul(x: f64, y: f64) -> f64 { return x * y; } #[inline(always)] -pub fn quot(x: f64, y: f64) -> f64 { return x / y; } +pub fn div(x: f64, y: f64) -> f64 { return x / y; } #[inline(always)] pub fn rem(x: f64, y: f64) -> f64 { return x % y; } @@ -297,9 +296,8 @@ impl Mul<f64,f64> for f64 { fn mul(&self, other: &f64) -> f64 { *self * *other } } #[cfg(notest)] -impl Quot<f64,f64> for f64 { - #[inline(always)] - fn quot(&self, other: &f64) -> f64 { *self / *other } +impl Div<f64,f64> for f64 { + fn div(&self, other: &f64) -> f64 { *self / *other } } #[cfg(notest)] impl Rem<f64,f64> for f64 { @@ -837,7 +835,7 @@ pub fn from_str_radix(num: &str, rdx: uint) -> Option<f64> { strconv::ExpNone, false, false) } -impl from_str::FromStr for f64 { +impl FromStr for f64 { #[inline(always)] fn from_str(val: &str) -> Option<f64> { from_str(val) } } @@ -1030,13 +1028,3 @@ mod tests { assert_eq!(Primitive::bytes::<f64>(), sys::size_of::<f64>()); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index 496ad4ec176..da9d03f6a7b 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -20,12 +20,11 @@ // PORT this must match in width according to architecture -use from_str; use libc::c_int; use num::{Zero, One, strconv}; use prelude::*; -pub use f64::{add, sub, mul, quot, rem, lt, le, eq, ne, ge, gt}; +pub use f64::{add, sub, mul, div, rem, lt, le, eq, ne, ge, gt}; pub use f64::logarithm; pub use f64::{acos, asin, atan2, cbrt, ceil, copysign, cosh, floor}; pub use f64::{erf, erfc, exp, expm1, exp2, abs_sub}; @@ -289,7 +288,7 @@ pub fn from_str_radix(num: &str, radix: uint) -> Option<float> { strconv::ExpNone, false, false) } -impl from_str::FromStr for float { +impl FromStr for float { #[inline(always)] fn from_str(val: &str) -> Option<float> { from_str(val) } } @@ -691,11 +690,13 @@ impl Mul<float,float> for float { #[inline(always)] fn mul(&self, other: &float) -> float { *self * *other } } + #[cfg(notest)] -impl Quot<float,float> for float { +impl Div<float,float> for float { #[inline(always)] - fn quot(&self, other: &float) -> float { *self / *other } + fn div(&self, other: &float) -> float { *self / *other } } + #[cfg(notest)] impl Rem<float,float> for float { #[inline(always)] @@ -1132,13 +1133,3 @@ mod tests { assert_eq!(to_str_digits(-infinity, 10u), ~"-inf"); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index 77b4eab1338..95c187a7be2 100644 --- a/src/libcore/num/int-template.rs +++ b/src/libcore/num/int-template.rs @@ -10,7 +10,6 @@ use T = self::inst::T; -use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::{Zero, One, strconv}; use prelude::*; @@ -30,7 +29,7 @@ pub fn sub(x: T, y: T) -> T { x - y } #[inline(always)] pub fn mul(x: T, y: T) -> T { x * y } #[inline(always)] -pub fn quot(x: T, y: T) -> T { x / y } +pub fn div(x: T, y: T) -> T { x / y } /// /// Returns the remainder of y / x. @@ -202,10 +201,10 @@ impl Mul<T,T> for T { } #[cfg(notest)] -impl Quot<T,T> for T { +impl Div<T,T> for T { /// - /// Returns the integer quotient, truncated towards 0. As this behaviour reflects - /// the underlying machine implementation it is more efficient than `Natural::div`. + /// Integer division, truncated towards 0. As this behaviour reflects the underlying + /// machine implementation it is more efficient than `Integer::div_floor`. /// /// # Examples /// @@ -222,7 +221,7 @@ impl Quot<T,T> for T { /// ~~~ /// #[inline(always)] - fn quot(&self, other: &T) -> T { *self / *other } + fn div(&self, other: &T) -> T { *self / *other } } #[cfg(notest)] @@ -297,25 +296,25 @@ impl Integer for T { /// # Examples /// /// ~~~ - /// assert!(( 8).div( 3) == 2); - /// assert!(( 8).div(-3) == -3); - /// assert!((-8).div( 3) == -3); - /// assert!((-8).div(-3) == 2); + /// assert!(( 8).div_floor( 3) == 2); + /// assert!(( 8).div_floor(-3) == -3); + /// assert!((-8).div_floor( 3) == -3); + /// assert!((-8).div_floor(-3) == 2); /// - /// assert!(( 1).div( 2) == 0); - /// assert!(( 1).div(-2) == -1); - /// assert!((-1).div( 2) == -1); - /// assert!((-1).div(-2) == 0); + /// assert!(( 1).div_floor( 2) == 0); + /// assert!(( 1).div_floor(-2) == -1); + /// assert!((-1).div_floor( 2) == -1); + /// assert!((-1).div_floor(-2) == 0); /// ~~~ /// #[inline(always)] - fn div(&self, other: &T) -> T { + 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.quot_rem(other) { - (q, r) if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => q - 1, - (q, _) => q, + match self.div_rem(other) { + (d, r) if (r > 0 && *other < 0) + || (r < 0 && *other > 0) => d - 1, + (d, _) => d, } } @@ -323,25 +322,25 @@ impl Integer for T { /// Integer modulo, satisfying: /// /// ~~~ - /// assert!(n.div(d) * d + n.modulo(d) == n) + /// assert!(n.div_floor(d) * d + n.mod_floor(d) == n) /// ~~~ /// /// # Examples /// /// ~~~ - /// assert!(( 8).modulo( 3) == 2); - /// assert!(( 8).modulo(-3) == -1); - /// assert!((-8).modulo( 3) == 1); - /// assert!((-8).modulo(-3) == -2); + /// assert!(( 8).mod_floor( 3) == 2); + /// assert!(( 8).mod_floor(-3) == -1); + /// assert!((-8).mod_floor( 3) == 1); + /// assert!((-8).mod_floor(-3) == -2); /// - /// assert!(( 1).modulo( 2) == 1); - /// assert!(( 1).modulo(-2) == -1); - /// assert!((-1).modulo( 2) == 1); - /// assert!((-1).modulo(-2) == -1); + /// assert!(( 1).mod_floor( 2) == 1); + /// assert!(( 1).mod_floor(-2) == -1); + /// assert!((-1).mod_floor( 2) == 1); + /// assert!((-1).mod_floor(-2) == -1); /// ~~~ /// #[inline(always)] - fn modulo(&self, other: &T) -> T { + 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 { @@ -351,21 +350,21 @@ impl Integer for T { } } - /// Calculates `div` and `modulo` simultaneously + /// Calculates `div_floor` and `mod_floor` simultaneously #[inline(always)] - fn div_mod(&self, other: &T) -> (T,T) { + 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.quot_rem(other) { - (q, r) if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => (q - 1, r + *other), - (q, r) => (q, r), + 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 `quot` (`\`) and `rem` (`%`) simultaneously + /// Calculates `div` (`\`) and `rem` (`%`) simultaneously #[inline(always)] - fn quot_rem(&self, other: &T) -> (T,T) { + fn div_rem(&self, other: &T) -> (T,T) { (*self / *other, *self % *other) } @@ -589,42 +588,42 @@ mod tests { } #[test] - fn test_quot_rem() { - fn test_nd_qr(nd: (T,T), qr: (T,T)) { + fn test_div_rem() { + fn test_nd_dr(nd: (T,T), qr: (T,T)) { let (n,d) = nd; - let separate_quot_rem = (n / d, n % d); - let combined_quot_rem = n.quot_rem(&d); + let separate_div_rem = (n / d, n % d); + let combined_div_rem = n.div_rem(&d); - assert_eq!(separate_quot_rem, qr); - assert_eq!(combined_quot_rem, qr); + assert_eq!(separate_div_rem, qr); + assert_eq!(combined_div_rem, qr); - test_division_rule(nd, separate_quot_rem); - test_division_rule(nd, combined_quot_rem); + test_division_rule(nd, separate_div_rem); + test_division_rule(nd, combined_div_rem); } - test_nd_qr(( 8, 3), ( 2, 2)); - test_nd_qr(( 8, -3), (-2, 2)); - test_nd_qr((-8, 3), (-2, -2)); - test_nd_qr((-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((-8, -3), ( 2, -2)); - test_nd_qr(( 1, 2), ( 0, 1)); - test_nd_qr(( 1, -2), ( 0, 1)); - test_nd_qr((-1, 2), ( 0, -1)); - test_nd_qr((-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_nd_dr((-1, -2), ( 0, -1)); } #[test] - fn test_div_mod() { + fn test_div_mod_floor() { fn test_nd_dm(nd: (T,T), dm: (T,T)) { let (n,d) = nd; - let separate_div_mod = (n.div(&d), n.modulo(&d)); - let combined_div_mod = n.div_mod(&d); + 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, dm); - assert_eq!(combined_div_mod, dm); + assert_eq!(separate_div_mod_floor, dm); + assert_eq!(combined_div_mod_floor, dm); - test_division_rule(nd, separate_div_mod); - test_division_rule(nd, combined_div_mod); + test_division_rule(nd, separate_div_mod_floor); + test_division_rule(nd, combined_div_mod_floor); } test_nd_dm(( 8, 3), ( 2, 2)); diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index 96fed51309e..1a59a069df7 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -10,7 +10,7 @@ //! An interface for numeric types use cmp::{Eq, Ord}; -use ops::{Add, Sub, Mul, Quot, Rem, Neg}; +use ops::{Add, Sub, Mul, Div, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use option::Option; use kinds::Copy; @@ -25,7 +25,7 @@ pub trait Num: Eq + Zero + One + Add<Self,Self> + Sub<Self,Self> + Mul<Self,Self> - + Quot<Self,Self> + + Div<Self,Self> + Rem<Self,Self> {} pub trait IntConvertible { @@ -69,12 +69,13 @@ pub fn abs<T:Ord + Zero + Neg<T>>(v: T) -> T { pub trait Integer: Num + Orderable - + Quot<Self,Self> + + Div<Self,Self> + Rem<Self,Self> { - fn div(&self, other: &Self) -> Self; - fn modulo(&self, other: &Self) -> Self; - fn div_mod(&self, other: &Self) -> (Self,Self); - fn quot_rem(&self, other: &Self) -> (Self,Self); + fn div_rem(&self, other: &Self) -> (Self,Self); + + fn div_floor(&self, other: &Self) -> Self; + fn mod_floor(&self, other: &Self) -> Self; + fn div_mod_floor(&self, other: &Self) -> (Self,Self); fn gcd(&self, other: &Self) -> Self; fn lcm(&self, other: &Self) -> Self; @@ -95,7 +96,7 @@ pub trait Round { pub trait Fractional: Num + Orderable + Round - + Quot<Self,Self> { + + Div<Self,Self> { fn recip(&self) -> Self; } @@ -219,7 +220,7 @@ pub trait Primitive: Num + Add<Self,Self> + Sub<Self,Self> + Mul<Self,Self> - + Quot<Self,Self> + + Div<Self,Self> + Rem<Self,Self> { // FIXME (#5527): These should be associated constants fn bits() -> uint; @@ -364,7 +365,7 @@ pub trait FromStrRadix { /// - If code written to use this function doesn't care about it, it's /// probably assuming that `x^0` always equals `1`. /// -pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Quot<T,T>+Mul<T,T>>( +pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>( radix: uint, pow: uint) -> T { let _0: T = Zero::zero(); let _1: T = One::one(); @@ -384,18 +385,19 @@ pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Quot<T,T>+Mul<T,T>>( total } +/// Helper function for testing numeric operations #[cfg(test)] pub fn test_num<T:Num + NumCast>(ten: T, two: T) { assert_eq!(ten.add(&two), cast(12)); assert_eq!(ten.sub(&two), cast(8)); assert_eq!(ten.mul(&two), cast(20)); - assert_eq!(ten.quot(&two), cast(5)); + assert_eq!(ten.div(&two), cast(5)); assert_eq!(ten.rem(&two), cast(0)); assert_eq!(ten.add(&two), ten + two); assert_eq!(ten.sub(&two), ten - two); assert_eq!(ten.mul(&two), ten * two); - assert_eq!(ten.quot(&two), ten / two); + assert_eq!(ten.div(&two), ten / two); assert_eq!(ten.rem(&two), ten % two); } diff --git a/src/libcore/num/strconv.rs b/src/libcore/num/strconv.rs index 004789e7fc1..c16a29f8295 100644 --- a/src/libcore/num/strconv.rs +++ b/src/libcore/num/strconv.rs @@ -9,7 +9,7 @@ // except according to those terms. use core::cmp::{Ord, Eq}; -use ops::{Add, Sub, Mul, Quot, Rem, Neg}; +use ops::{Add, Sub, Mul, Div, Rem, Neg}; use option::{None, Option, Some}; use char; use str; @@ -58,7 +58,7 @@ fn is_neg_inf<T:Eq+NumStrConv>(num: &T) -> bool { } #[inline(always)] -fn is_neg_zero<T:Eq+One+Zero+NumStrConv+Quot<T,T>>(num: &T) -> bool { +fn is_neg_zero<T:Eq+One+Zero+NumStrConv+Div<T,T>>(num: &T) -> bool { let _0: T = Zero::zero(); let _1: T = One::one(); @@ -171,7 +171,7 @@ static nan_buf: [u8, ..3] = ['N' as u8, 'a' as u8, 'N' as u8]; * - Fails if `radix` < 2 or `radix` > 36. */ pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+ - Quot<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>( + Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>( num: &T, radix: uint, negative_zero: bool, sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) { if (radix as int) < 2 { @@ -379,7 +379,7 @@ pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+ */ #[inline(always)] pub fn to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+ - Quot<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>( + Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>( num: &T, radix: uint, negative_zero: bool, sign: SignFormat, digits: SignificantDigits) -> (~str, bool) { let (bytes, special) = to_str_bytes_common(num, radix, @@ -432,7 +432,7 @@ priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u; * - Fails if `radix` > 18 and `special == true` due to conflict * between digit and lowest first character in `inf` and `NaN`, the `'i'`. */ -pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Quot<T,T>+ +pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+ Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>+ NumStrConv>( buf: &[u8], radix: uint, negative: bool, fractional: bool, @@ -629,7 +629,7 @@ pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Quot<T,T>+ * `from_str_bytes_common()`, for details see there. */ #[inline(always)] -pub fn from_str_common<T:NumCast+Zero+One+Eq+Ord+Copy+Quot<T,T>+Mul<T,T>+ +pub fn from_str_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+Mul<T,T>+ Sub<T,T>+Neg<T>+Add<T,T>+NumStrConv>( buf: &str, radix: uint, negative: bool, fractional: bool, special: bool, exponent: ExponentFormat, empty_zero: bool, diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs index 2d204449468..6d0f1fe1fc7 100644 --- a/src/libcore/num/uint-template.rs +++ b/src/libcore/num/uint-template.rs @@ -11,7 +11,6 @@ use T = self::inst::T; use T_SIGNED = self::inst::T_SIGNED; -use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::{Zero, One, strconv}; use prelude::*; @@ -31,7 +30,7 @@ pub fn sub(x: T, y: T) -> T { x - y } #[inline(always)] pub fn mul(x: T, y: T) -> T { x * y } #[inline(always)] -pub fn quot(x: T, y: T) -> T { x / y } +pub fn div(x: T, y: T) -> T { x / y } #[inline(always)] pub fn rem(x: T, y: T) -> T { x % y } @@ -167,9 +166,9 @@ impl Mul<T,T> for T { } #[cfg(notest)] -impl Quot<T,T> for T { +impl Div<T,T> for T { #[inline(always)] - fn quot(&self, other: &T) -> T { *self / *other } + fn div(&self, other: &T) -> T { *self / *other } } #[cfg(notest)] @@ -187,23 +186,23 @@ impl Neg<T> for T { impl Unsigned for T {} impl Integer for T { - /// Unsigned integer division. Returns the same result as `quot` (`/`). + /// Calculates `div` (`\`) and `rem` (`%`) simultaneously #[inline(always)] - fn div(&self, other: &T) -> T { *self / *other } + fn div_rem(&self, other: &T) -> (T,T) { + (*self / *other, *self % *other) + } - /// Unsigned integer modulo operation. Returns the same result as `rem` (`%`). + /// Unsigned integer division. Returns the same result as `div` (`/`). #[inline(always)] - fn modulo(&self, other: &T) -> T { *self / *other } + fn div_floor(&self, other: &T) -> T { *self / *other } - /// Calculates `div` and `modulo` simultaneously + /// Unsigned integer modulo operation. Returns the same result as `rem` (`%`). #[inline(always)] - fn div_mod(&self, other: &T) -> (T,T) { - (*self / *other, *self % *other) - } + fn mod_floor(&self, other: &T) -> T { *self / *other } - /// Calculates `quot` (`\`) and `rem` (`%`) simultaneously + /// Calculates `div_floor` and `modulo_floor` simultaneously #[inline(always)] - fn quot_rem(&self, other: &T) -> (T,T) { + fn div_mod_floor(&self, other: &T) -> (T,T) { (*self / *other, *self % *other) } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 18dcf34e49b..47ff45be687 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -30,9 +30,9 @@ pub trait Mul<RHS,Result> { fn mul(&self, rhs: &RHS) -> Result; } -#[lang="quot"] -pub trait Quot<RHS,Result> { - fn quot(&self, rhs: &RHS) -> Result; +#[lang="div"] +pub trait Div<RHS,Result> { + fn div(&self, rhs: &RHS) -> Result; } #[lang="rem"] diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 5abf376ddde..b7c51147fba 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -461,11 +461,3 @@ fn test_get_or_zero() { let no_stuff: Option<int> = None; assert!(no_stuff.get_or_zero() == 0); } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/os.rs b/src/libcore/os.rs index d5271ec228b..42c77a687e5 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -38,6 +38,7 @@ use ptr; use str; use task; use uint; +use unstable::finally::Finally; use vec; pub use libc::fclose; @@ -372,8 +373,9 @@ pub fn pipe() -> Pipe { // inheritance has to be handled in a different way that I do not // fully understand. Here we explicitly make the pipe non-inheritable, // which means to pass it to a subprocess they need to be duplicated - // first, as in rust_run_program. - let mut fds = Pipe {in: 0 as c_int, out: 0 as c_int}; + // first, as in core::run. + let mut fds = Pipe {in: 0 as c_int, + out: 0 as c_int }; let res = libc::pipe(&mut fds.in, 1024 as ::libc::c_uint, (libc::O_BINARY | libc::O_NOINHERIT) as c_int); assert!((res == 0 as c_int)); @@ -770,6 +772,28 @@ pub fn list_dir_path(p: &Path) -> ~[~Path] { list_dir(p).map(|f| ~p.push(*f)) } +/// Removes a directory at the specified path, after removing +/// all its contents. Use carefully! +pub fn remove_dir_recursive(p: &Path) -> bool { + let mut error_happened = false; + for walk_dir(p) |inner| { + if !error_happened { + if path_is_dir(inner) { + if !remove_dir_recursive(inner) { + error_happened = true; + } + } + else { + if !remove_file(inner) { + error_happened = true; + } + } + } + }; + // Directory should now be empty + !error_happened && remove_dir(p) +} + /// Removes a directory at the specified path pub fn remove_dir(p: &Path) -> bool { return rmdir(p); @@ -817,6 +841,36 @@ pub fn change_dir(p: &Path) -> bool { } } +/// Changes the current working directory to the specified +/// path while acquiring a global lock, then calls `action`. +/// If the change is successful, releases the lock and restores the +/// CWD to what it was before, returning true. +/// Returns false if the directory doesn't exist or if the directory change +/// is otherwise unsuccessful. +pub fn change_dir_locked(p: &Path, action: &fn()) -> bool { + use unstable::global::global_data_clone_create; + use unstable::{Exclusive, exclusive}; + + fn key(_: Exclusive<()>) { } + + let result = unsafe { + global_data_clone_create(key, || { + ~exclusive(()) + }) + }; + + do result.with_imm() |_| { + let old_dir = os::getcwd(); + if change_dir(p) { + action(); + change_dir(&old_dir) + } + else { + false + } + } +} + /// Copies a file from one location to another pub fn copy_file(from: &Path, to: &Path) -> bool { return do_copy_file(from, to); @@ -845,6 +899,10 @@ pub fn copy_file(from: &Path, to: &Path) -> bool { if istream as uint == 0u { return false; } + // Preserve permissions + let from_mode = from.get_mode().expect("copy_file: couldn't get permissions \ + for source file"); + let ostream = do as_c_charp(to.to_str()) |top| { do as_c_charp("w+b") |modebuf| { libc::fopen(top, modebuf) @@ -876,6 +934,15 @@ pub fn copy_file(from: &Path, to: &Path) -> bool { } fclose(istream); fclose(ostream); + + // Give the new file the old file's permissions + unsafe { + if do str::as_c_str(to.to_str()) |to_buf| { + libc::chmod(to_buf, from_mode as mode_t) + } != 0 { + return false; // should be a condition... + } + } return ok; } } @@ -1152,6 +1219,88 @@ pub fn set_args(new_args: ~[~str]) { } } +// FIXME #6100 we should really use an internal implementation of this - using +// the POSIX glob functions isn't portable to windows, probably has slight +// inconsistencies even where it is implemented, and makes extending +// functionality a lot more difficult +// FIXME #6101 also provide a non-allocating version - each_glob or so? +/// Returns a vector of Path objects that match the given glob pattern +#[cfg(target_os = "linux")] +#[cfg(target_os = "android")] +#[cfg(target_os = "freebsd")] +#[cfg(target_os = "macos")] +pub fn glob(pattern: &str) -> ~[Path] { + #[cfg(target_os = "linux")] + #[cfg(target_os = "android")] + fn default_glob_t () -> libc::glob_t { + libc::glob_t { + gl_pathc: 0, + gl_pathv: ptr::null(), + gl_offs: 0, + __unused1: ptr::null(), + __unused2: ptr::null(), + __unused3: ptr::null(), + __unused4: ptr::null(), + __unused5: ptr::null(), + } + } + + #[cfg(target_os = "freebsd")] + fn default_glob_t () -> libc::glob_t { + libc::glob_t { + gl_pathc: 0, + __unused1: 0, + gl_offs: 0, + __unused2: 0, + gl_pathv: ptr::null(), + __unused3: ptr::null(), + __unused4: ptr::null(), + __unused5: ptr::null(), + __unused6: ptr::null(), + __unused7: ptr::null(), + __unused8: ptr::null(), + } + } + + #[cfg(target_os = "macos")] + fn default_glob_t () -> libc::glob_t { + libc::glob_t { + gl_pathc: 0, + __unused1: 0, + gl_offs: 0, + __unused2: 0, + gl_pathv: ptr::null(), + __unused3: ptr::null(), + __unused4: ptr::null(), + __unused5: ptr::null(), + __unused6: ptr::null(), + __unused7: ptr::null(), + __unused8: ptr::null(), + } + } + + let mut g = default_glob_t(); + do str::as_c_str(pattern) |c_pattern| { + unsafe { libc::glob(c_pattern, 0, ptr::null(), &mut g) } + }; + do(|| { + let paths = unsafe { + vec::raw::from_buf_raw(g.gl_pathv, g.gl_pathc as uint) + }; + do paths.map |&c_str| { + Path(unsafe { str::raw::from_c_str(c_str) }) + } + }).finally { + unsafe { libc::globfree(&mut g) }; + } +} + +/// Returns a vector of Path objects that match the given glob pattern +#[cfg(target_os = "win32")] +pub fn glob(pattern: &str) -> ~[Path] { + fail!(~"glob() is unimplemented on Windows") +} + #[cfg(target_os = "macos")] extern { // These functions are in crt_externs.h. @@ -1480,6 +1629,7 @@ mod tests { == buf.len() as size_t)) } assert!((libc::fclose(ostream) == (0u as c_int))); + let in_mode = in.get_mode(); let rs = os::copy_file(&in, &out); if (!os::path_exists(&in)) { fail!(fmt!("%s doesn't exist", in.to_str())); @@ -1487,6 +1637,7 @@ mod tests { assert!((rs)); let rslt = run::run_program(~"diff", ~[in.to_str(), out.to_str()]); assert!((rslt == 0)); + assert!(out.get_mode() == in_mode); assert!((remove_file(&in))); assert!((remove_file(&out))); } diff --git a/src/libcore/owned.rs b/src/libcore/owned.rs index c483ec79e21..599591e2f6d 100644 --- a/src/libcore/owned.rs +++ b/src/libcore/owned.rs @@ -31,4 +31,3 @@ impl<T:Ord> Ord for ~T { #[inline(always)] fn gt(&self, other: &~T) -> bool { *(*self) > *(*other) } } - diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 95b24d20a4b..19674900f90 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -86,7 +86,9 @@ use cast::{forget, transmute, transmute_copy}; use either::{Either, Left, Right}; use kinds::Owned; use libc; +use ops::Drop; use option::{None, Option, Some}; +use unstable::finally::Finally; use unstable::intrinsics; use ptr; use task; @@ -301,7 +303,7 @@ struct BufferResource<T> { } #[unsafe_destructor] -impl<T> ::ops::Drop for BufferResource<T> { +impl<T> Drop for BufferResource<T> { fn finalize(&self) { unsafe { let b = move_it!(self.buffer); @@ -395,26 +397,22 @@ pub fn try_recv<T:Owned,Tbuffer:Owned>(p: RecvPacketBuffered<T, Tbuffer>) let p_ = p.unwrap(); let p = unsafe { &*p_ }; - #[unsafe_destructor] - struct DropState<'self> { - p: &'self PacketHeader, - - drop { - unsafe { - if task::failing() { - self.p.state = Terminated; - let old_task = swap_task(&mut self.p.blocked_task, - ptr::null()); - if !old_task.is_null() { - rustrt::rust_task_deref(old_task); - } + do (|| { + try_recv_(p) + }).finally { + unsafe { + if task::failing() { + p.header.state = Terminated; + let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); + if !old_task.is_null() { + rustrt::rust_task_deref(old_task); } } } - }; - - let _drop_state = DropState { p: &p.header }; + } +} +fn try_recv_<T:Owned>(p: &Packet<T>) -> Option<T> { // optimistic path match p.header.state { Full => { @@ -451,7 +449,7 @@ pub fn try_recv<T:Owned,Tbuffer:Owned>(p: RecvPacketBuffered<T, Tbuffer>) Blocked); match old_state { Empty => { - debug!("no data available on %?, going to sleep.", p_); + debug!("no data available on %?, going to sleep.", p); if count == 0 { wait_event(this); } @@ -641,7 +639,7 @@ pub struct SendPacketBuffered<T, Tbuffer> { } #[unsafe_destructor] -impl<T:Owned,Tbuffer:Owned> ::ops::Drop for SendPacketBuffered<T,Tbuffer> { +impl<T:Owned,Tbuffer:Owned> Drop for SendPacketBuffered<T,Tbuffer> { fn finalize(&self) { //if self.p != none { // debug!("drop send %?", option::get(self.p)); @@ -710,7 +708,7 @@ pub struct RecvPacketBuffered<T, Tbuffer> { } #[unsafe_destructor] -impl<T:Owned,Tbuffer:Owned> ::ops::Drop for RecvPacketBuffered<T,Tbuffer> { +impl<T:Owned,Tbuffer:Owned> Drop for RecvPacketBuffered<T,Tbuffer> { fn finalize(&self) { //if self.p != none { // debug!("drop recv %?", option::get(self.p)); diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 318725d2822..42401ae5a1f 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -14,7 +14,7 @@ pub use either::{Either, Left, Right}; pub use kinds::{Const, Copy, Owned, Durable}; -pub use ops::{Add, Sub, Mul, Quot, Rem, Neg, Not}; +pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Drop}; pub use ops::{Shl, Shr, Index}; @@ -28,7 +28,7 @@ pub use io::{print, println}; /* Reexported types and traits */ pub use clone::Clone; -pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; +pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv}; pub use container::{Container, Mutable, Map, Set}; pub use hash::Hash; pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter}; @@ -48,6 +48,7 @@ pub use path::WindowsPath; pub use ptr::Ptr; pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr}; pub use str::{StrSlice, OwnedStr}; +pub use from_str::{FromStr}; pub use to_bytes::IterBytes; pub use to_str::{ToStr, ToStrConsume}; pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps}; diff --git a/src/libcore/rand.rs b/src/libcore/rand.rs index 9fa099cabbf..80f69f067eb 100644 --- a/src/libcore/rand.rs +++ b/src/libcore/rand.rs @@ -16,6 +16,9 @@ and so can be used to generate any type that implements `Rand`. Type inference means that often a simple call to `rand::random()` or `rng.gen()` will suffice, but sometimes an annotation is required, e.g. `rand::random::<float>()`. +See the `distributions` submodule for sampling random numbers from +distributions like normal and exponential. + # Examples ~~~ use core::rand::RngUtil; @@ -47,6 +50,9 @@ use util; use vec; use libc::size_t; +#[path="rand/distributions.rs"] +pub mod distributions; + /// A type that can be randomly generated using an Rng pub trait Rand { fn rand<R: Rng>(rng: &R) -> Self; @@ -1067,12 +1073,3 @@ mod tests { } } } - - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/rand/distributions.rs b/src/libcore/rand/distributions.rs new file mode 100644 index 00000000000..a644f60db69 --- /dev/null +++ b/src/libcore/rand/distributions.rs @@ -0,0 +1,148 @@ +// Copyright 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Sampling from random distributions + +// Some implementations use the Ziggurat method +// https://en.wikipedia.org/wiki/Ziggurat_algorithm +// +// The version used here is ZIGNOR [Doornik 2005, "An Improved +// Ziggurat Method to Generate Normal Random Samples"] which is slower +// (about double, it generates an extra random number) than the +// canonical version [Marsaglia & Tsang 2000, "The Ziggurat Method for +// Generating Random Variables"], but more robust. If one wanted, one +// could implement VIZIGNOR the ZIGNOR paper for more speed. + +use prelude::*; +use rand::{Rng,Rand}; + +mod ziggurat_tables; + +// inlining should mean there is no performance penalty for this +#[inline(always)] +fn ziggurat<R:Rng>(rng: &R, + center_u: bool, + X: ziggurat_tables::ZigTable, + F: ziggurat_tables::ZigTable, + F_DIFF: ziggurat_tables::ZigTable, + pdf: &'static fn(f64) -> f64, // probability density function + zero_case: &'static fn(&R, f64) -> f64) -> f64 { + loop { + let u = if center_u {2.0 * rng.gen() - 1.0} else {rng.gen()}; + let i: uint = rng.gen::<uint>() & 0xff; + let x = u * X[i]; + + let test_x = if center_u {f64::abs(x)} else {x}; + + // algebraically equivalent to |u| < X[i+1]/X[i] (or u < X[i+1]/X[i]) + if test_x < X[i + 1] { + return x; + } + if i == 0 { + return zero_case(rng, u); + } + // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1 + if F[i+1] + F_DIFF[i+1] * rng.gen() < pdf(x) { + return x; + } + } +} + +/// A wrapper around an `f64` to generate N(0, 1) random numbers (a.k.a. a +/// standard normal, or Gaussian). Multiplying the generated values by the +/// desired standard deviation `sigma` then adding the desired mean `mu` will +/// give N(mu, sigma^2) distributed random numbers. +/// +/// Note that this has to be unwrapped before use as an `f64` (using either +/// `*` or `cast::transmute` is safe). +/// +/// # Example +/// +/// ~~~ +/// use core::rand::distributions::StandardNormal; +/// +/// fn main() { +/// let normal = 2.0 + (*rand::random::<StandardNormal>()) * 3.0; +/// println(fmt!("%f is from a N(2, 9) distribution", normal)) +/// } +/// ~~~ +pub struct StandardNormal(f64); + +impl Rand for StandardNormal { + fn rand<R:Rng>(rng: &R) -> StandardNormal { + #[inline(always)] + fn pdf(x: f64) -> f64 { + f64::exp((-x*x/2.0) as f64) as f64 + } + #[inline(always)] + fn zero_case<R:Rng>(rng: &R, u: f64) -> f64 { + // compute a random number in the tail by hand + + // strange initial conditions, because the loop is not + // do-while, so the condition should be true on the first + // run, they get overwritten anyway (0 < 1, so these are + // good). + let mut x = 1.0, y = 0.0; + + // XXX infinities? + while -2.0*y < x * x { + x = f64::ln(rng.gen()) / ziggurat_tables::ZIG_NORM_R; + y = f64::ln(rng.gen()); + } + if u < 0.0 {x-ziggurat_tables::ZIG_NORM_R} else {ziggurat_tables::ZIG_NORM_R-x} + } + + StandardNormal(ziggurat( + rng, + true, // this is symmetric + &ziggurat_tables::ZIG_NORM_X, + &ziggurat_tables::ZIG_NORM_F, &ziggurat_tables::ZIG_NORM_F_DIFF, + pdf, zero_case)) + } +} + +/// A wrapper around an `f64` to generate Exp(1) random numbers. Dividing by +/// the desired rate `lambda` will give Exp(lambda) distributed random +/// numbers. +/// +/// Note that this has to be unwrapped before use as an `f64` (using either +/// `*` or `cast::transmute` is safe). +/// +/// # Example +/// +/// ~~~ +/// use core::rand::distributions::Exp1; +/// +/// fn main() { +/// let exp2 = (*rand::random::<Exp1>()) * 0.5; +/// println(fmt!("%f is from a Exp(2) distribution", exp2)); +/// } +/// ~~~ +pub struct Exp1(f64); + +// This could be done via `-f64::ln(rng.gen::<f64>())` but that is slower. +impl Rand for Exp1 { + #[inline] + fn rand<R:Rng>(rng: &R) -> Exp1 { + #[inline(always)] + fn pdf(x: f64) -> f64 { + f64::exp(-x) + } + #[inline(always)] + fn zero_case<R:Rng>(rng: &R, _u: f64) -> f64 { + ziggurat_tables::ZIG_EXP_R - f64::ln(rng.gen()) + } + + Exp1(ziggurat(rng, false, + &ziggurat_tables::ZIG_EXP_X, + &ziggurat_tables::ZIG_EXP_F, &ziggurat_tables::ZIG_EXP_F_DIFF, + pdf, zero_case)) + } +} diff --git a/src/libcore/rand/ziggurat_tables.rs b/src/libcore/rand/ziggurat_tables.rs new file mode 100644 index 00000000000..aca2457cac4 --- /dev/null +++ b/src/libcore/rand/ziggurat_tables.rs @@ -0,0 +1,412 @@ +// Copyright 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tables for distributions which are sampled using the ziggurat +// algorithm. Autogenerated by `ziggurat_tables.py`. + +pub type ZigTable = &'static [f64, .. 257]; +pub static ZIG_NORM_R: f64 = 3.654152885361008796; +pub static ZIG_NORM_X: [f64, .. 257] = + [3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074, + 3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434, + 2.978603279880844834, 2.934366867207854224, 2.894121053612348060, 2.857138730872132548, + 2.822877396825325125, 2.790921174000785765, 2.760944005278822555, 2.732685359042827056, + 2.705933656121858100, 2.680514643284522158, 2.656283037575502437, 2.633116393630324570, + 2.610910518487548515, 2.589575986706995181, 2.569035452680536569, 2.549221550323460761, + 2.530075232158516929, 2.511544441625342294, 2.493583041269680667, 2.476149939669143318, + 2.459208374333311298, 2.442725318198956774, 2.426670984935725972, 2.411018413899685520, + 2.395743119780480601, 2.380822795170626005, 2.366237056715818632, 2.351967227377659952, + 2.337996148795031370, 2.324308018869623016, 2.310888250599850036, 2.297723348901329565, + 2.284800802722946056, 2.272108990226823888, 2.259637095172217780, 2.247375032945807760, + 2.235313384928327984, 2.223443340090905718, 2.211756642882544366, 2.200245546609647995, + 2.188902771624720689, 2.177721467738641614, 2.166695180352645966, 2.155817819875063268, + 2.145083634046203613, 2.134487182844320152, 2.124023315687815661, 2.113687150684933957, + 2.103474055713146829, 2.093379631137050279, 2.083399693996551783, 2.073530263516978778, + 2.063767547809956415, 2.054107931648864849, 2.044547965215732788, 2.035084353727808715, + 2.025713947862032960, 2.016433734904371722, 2.007240830558684852, 1.998132471356564244, + 1.989106007615571325, 1.980158896898598364, 1.971288697931769640, 1.962493064942461896, + 1.953769742382734043, 1.945116560006753925, 1.936531428273758904, 1.928012334050718257, + 1.919557336591228847, 1.911164563769282232, 1.902832208548446369, 1.894558525668710081, + 1.886341828534776388, 1.878180486290977669, 1.870072921069236838, 1.862017605397632281, + 1.854013059758148119, 1.846057850283119750, 1.838150586580728607, 1.830289919680666566, + 1.822474540091783224, 1.814703175964167636, 1.806974591348693426, 1.799287584547580199, + 1.791640986550010028, 1.784033659547276329, 1.776464495522344977, 1.768932414909077933, + 1.761436365316706665, 1.753975320315455111, 1.746548278279492994, 1.739154261283669012, + 1.731792314050707216, 1.724461502945775715, 1.717160915015540690, 1.709889657069006086, + 1.702646854797613907, 1.695431651932238548, 1.688243209434858727, 1.681080704722823338, + 1.673943330923760353, 1.666830296159286684, 1.659740822855789499, 1.652674147080648526, + 1.645629517902360339, 1.638606196773111146, 1.631603456932422036, 1.624620582830568427, + 1.617656869570534228, 1.610711622367333673, 1.603784156023583041, 1.596873794420261339, + 1.589979870021648534, 1.583101723393471438, 1.576238702733332886, 1.569390163412534456, + 1.562555467528439657, 1.555733983466554893, 1.548925085471535512, 1.542128153226347553, + 1.535342571438843118, 1.528567729435024614, 1.521803020758293101, 1.515047842773992404, + 1.508301596278571965, 1.501563685112706548, 1.494833515777718391, 1.488110497054654369, + 1.481394039625375747, 1.474683555695025516, 1.467978458615230908, 1.461278162507407830, + 1.454582081885523293, 1.447889631277669675, 1.441200224845798017, 1.434513276002946425, + 1.427828197027290358, 1.421144398672323117, 1.414461289772464658, 1.407778276843371534, + 1.401094763676202559, 1.394410150925071257, 1.387723835686884621, 1.381035211072741964, + 1.374343665770030531, 1.367648583594317957, 1.360949343030101844, 1.354245316759430606, + 1.347535871177359290, 1.340820365893152122, 1.334098153216083604, 1.327368577624624679, + 1.320630975217730096, 1.313884673146868964, 1.307128989027353860, 1.300363230327433728, + 1.293586693733517645, 1.286798664489786415, 1.279998415710333237, 1.273185207661843732, + 1.266358287014688333, 1.259516886060144225, 1.252660221891297887, 1.245787495544997903, + 1.238897891102027415, 1.231990574742445110, 1.225064693752808020, 1.218119375481726552, + 1.211153726239911244, 1.204166830140560140, 1.197157747875585931, 1.190125515422801650, + 1.183069142678760732, 1.175987612011489825, 1.168879876726833800, 1.161744859441574240, + 1.154581450355851802, 1.147388505416733873, 1.140164844363995789, 1.132909248648336975, + 1.125620459211294389, 1.118297174115062909, 1.110938046009249502, 1.103541679420268151, + 1.096106627847603487, 1.088631390649514197, 1.081114409698889389, 1.073554065787871714, + 1.065948674757506653, 1.058296483326006454, 1.050595664586207123, 1.042844313139370538, + 1.035040439828605274, 1.027181966030751292, 1.019266717460529215, 1.011292417434978441, + 1.003256679539591412, 0.995156999629943084, 0.986990747093846266, 0.978755155288937750, + 0.970447311058864615, 0.962064143217605250, 0.953602409875572654, 0.945058684462571130, + 0.936429340280896860, 0.927710533396234771, 0.918898183643734989, 0.909987953490768997, + 0.900975224455174528, 0.891855070726792376, 0.882622229578910122, 0.873271068082494550, + 0.863795545546826915, 0.854189171001560554, 0.844444954902423661, 0.834555354079518752, + 0.824512208745288633, 0.814306670128064347, 0.803929116982664893, 0.793369058833152785, + 0.782615023299588763, 0.771654424216739354, 0.760473406422083165, 0.749056662009581653, + 0.737387211425838629, 0.725446140901303549, 0.713212285182022732, 0.700661841097584448, + 0.687767892786257717, 0.674499822827436479, 0.660822574234205984, 0.646695714884388928, + 0.632072236375024632, 0.616896989996235545, 0.601104617743940417, 0.584616766093722262, + 0.567338257040473026, 0.549151702313026790, 0.529909720646495108, 0.509423329585933393, + 0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746, + 0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806, + 0.000000000000000000]; +pub static ZIG_NORM_F: [f64, .. 257] = + [0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872, + 0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100, + 0.011842757857943104, 0.013497450601780807, 0.015177088307982072, 0.016880083152595839, + 0.018605121275783350, 0.020351096230109354, 0.022117062707379922, 0.023902203305873237, + 0.025705804008632656, 0.027527235669693315, 0.029365939758230111, 0.031221417192023690, + 0.033093219458688698, 0.034980941461833073, 0.036884215688691151, 0.038802707404656918, + 0.040736110656078753, 0.042684144916619378, 0.044646552251446536, 0.046623094902089664, + 0.048613553216035145, 0.050617723861121788, 0.052635418276973649, 0.054666461325077916, + 0.056710690106399467, 0.058767952921137984, 0.060838108349751806, 0.062921024437977854, + 0.065016577971470438, 0.067124653828023989, 0.069245144397250269, 0.071377949059141965, + 0.073522973714240991, 0.075680130359194964, 0.077849336702372207, 0.080030515814947509, + 0.082223595813495684, 0.084428509570654661, 0.086645194450867782, 0.088873592068594229, + 0.091113648066700734, 0.093365311913026619, 0.095628536713353335, 0.097903279039215627, + 0.100189498769172020, 0.102487158942306270, 0.104796225622867056, 0.107116667775072880, + 0.109448457147210021, 0.111791568164245583, 0.114145977828255210, 0.116511665626037014, + 0.118888613443345698, 0.121276805485235437, 0.123676228202051403, 0.126086870220650349, + 0.128508722280473636, 0.130941777174128166, 0.133386029692162844, 0.135841476571757352, + 0.138308116449064322, 0.140785949814968309, 0.143274978974047118, 0.145775208006537926, + 0.148286642733128721, 0.150809290682410169, 0.153343161060837674, 0.155888264725064563, + 0.158444614156520225, 0.161012223438117663, 0.163591108232982951, 0.166181285765110071, + 0.168782774801850333, 0.171395595638155623, 0.174019770082499359, 0.176655321444406654, + 0.179302274523530397, 0.181960655600216487, 0.184630492427504539, 0.187311814224516926, + 0.190004651671193070, 0.192709036904328807, 0.195425003514885592, 0.198152586546538112, + 0.200891822495431333, 0.203642749311121501, 0.206405406398679298, 0.209179834621935651, + 0.211966076307852941, 0.214764175252008499, 0.217574176725178370, 0.220396127481011589, + 0.223230075764789593, 0.226076071323264877, 0.228934165415577484, 0.231804410825248525, + 0.234686861873252689, 0.237581574432173676, 0.240488605941449107, 0.243408015423711988, + 0.246339863502238771, 0.249284212419516704, 0.252241126056943765, 0.255210669955677150, + 0.258192911338648023, 0.261187919133763713, 0.264195763998317568, 0.267216518344631837, + 0.270250256366959984, 0.273297054069675804, 0.276356989296781264, 0.279430141762765316, + 0.282516593084849388, 0.285616426816658109, 0.288729728483353931, 0.291856585618280984, + 0.294997087801162572, 0.298151326697901342, 0.301319396102034120, 0.304501391977896274, + 0.307697412505553769, 0.310907558127563710, 0.314131931597630143, 0.317370638031222396, + 0.320623784958230129, 0.323891482377732021, 0.327173842814958593, 0.330470981380537099, + 0.333783015832108509, 0.337110066638412809, 0.340452257045945450, 0.343809713148291340, + 0.347182563958251478, 0.350570941482881204, 0.353974980801569250, 0.357394820147290515, + 0.360830600991175754, 0.364282468130549597, 0.367750569780596226, 0.371235057669821344, + 0.374736087139491414, 0.378253817247238111, 0.381788410875031348, 0.385340034841733958, + 0.388908860020464597, 0.392495061461010764, 0.396098818517547080, 0.399720314981931668, + 0.403359739222868885, 0.407017284331247953, 0.410693148271983222, 0.414387534042706784, + 0.418100649839684591, 0.421832709231353298, 0.425583931339900579, 0.429354541031341519, + 0.433144769114574058, 0.436954852549929273, 0.440785034667769915, 0.444635565397727750, + 0.448506701509214067, 0.452398706863882505, 0.456311852680773566, 0.460246417814923481, + 0.464202689050278838, 0.468180961407822172, 0.472181538469883255, 0.476204732721683788, + 0.480250865911249714, 0.484320269428911598, 0.488413284707712059, 0.492530263646148658, + 0.496671569054796314, 0.500837575128482149, 0.505028667945828791, 0.509245245998136142, + 0.513487720749743026, 0.517756517232200619, 0.522052074674794864, 0.526374847174186700, + 0.530725304406193921, 0.535103932383019565, 0.539511234259544614, 0.543947731192649941, + 0.548413963257921133, 0.552910490428519918, 0.557437893621486324, 0.561996775817277916, + 0.566587763258951771, 0.571211506738074970, 0.575868682975210544, 0.580559996103683473, + 0.585286179266300333, 0.590047996335791969, 0.594846243770991268, 0.599681752622167719, + 0.604555390700549533, 0.609468064928895381, 0.614420723892076803, 0.619414360609039205, + 0.624450015550274240, 0.629528779928128279, 0.634651799290960050, 0.639820277456438991, + 0.645035480824251883, 0.650298743114294586, 0.655611470583224665, 0.660975147780241357, + 0.666391343912380640, 0.671861719900766374, 0.677388036222513090, 0.682972161648791376, + 0.688616083008527058, 0.694321916130032579, 0.700091918140490099, 0.705928501336797409, + 0.711834248882358467, 0.717811932634901395, 0.723864533472881599, 0.729995264565802437, + 0.736207598131266683, 0.742505296344636245, 0.748892447223726720, 0.755373506511754500, + 0.761953346841546475, 0.768637315803334831, 0.775431304986138326, 0.782341832659861902, + 0.789376143571198563, 0.796542330428254619, 0.803849483176389490, 0.811307874318219935, + 0.818929191609414797, 0.826726833952094231, 0.834716292992930375, 0.842915653118441077, + 0.851346258465123684, 0.860033621203008636, 0.869008688043793165, 0.878309655816146839, + 0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247, + 0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328, + 1.000000000000000000]; +pub static ZIG_NORM_F_DIFF: [f64, .. 257] = + [0.000000000000000000, 0.000782818165911943, 0.001348786815607765, 0.001428899847265509, + 0.001484430705892882, 0.001528472172127356, 0.001565707298030807, 0.001598388670308183, + 0.001627786418212004, 0.001654692743837703, 0.001679637706201265, 0.001702994844613767, + 0.001725038123187510, 0.001745974954326004, 0.001765966477270568, 0.001785140598493315, + 0.001803600702759419, 0.001821431661060659, 0.001838704088536796, 0.001855477433793579, + 0.001871802266665008, 0.001887722003144375, 0.001903274226858077, 0.001918491715965767, + 0.001933403251421835, 0.001948034260540625, 0.001962407334827158, 0.001976542650643127, + 0.001990458313945481, 0.002004170645086643, 0.002017694415851860, 0.002031043048104267, + 0.002044228781321551, 0.002057262814738517, 0.002070155428613822, 0.002082916088226049, + 0.002095553533492583, 0.002108075856553551, 0.002120490569226280, 0.002132804661891696, + 0.002145024655099026, 0.002157156644953973, 0.002169206343177243, 0.002181179112575302, + 0.002193079998548175, 0.002204913757158977, 0.002216684880213121, 0.002228397617726446, + 0.002240055998106505, 0.002251663846325885, 0.002263224800326716, 0.002274742325862292, + 0.002286219729956393, 0.002297660173134250, 0.002309066680560787, 0.002320442152205823, + 0.002331789372137141, 0.002343111017035562, 0.002354409664009627, 0.002365687797781804, + 0.002376947817308683, 0.002388192041889739, 0.002399422716815966, 0.002410642018598946, + 0.002421852059823287, 0.002433054893654529, 0.002444252518034679, 0.002455446879594508, + 0.002466639877306970, 0.002477833365903986, 0.002489029159078809, 0.002500229032490808, + 0.002511434726590794, 0.002522647949281448, 0.002533870378427505, 0.002545103664226889, + 0.002556349431455662, 0.002567609281597438, 0.002578884794865288, 0.002590177532127119, + 0.002601489036740262, 0.002612820836305291, 0.002624174444343735, 0.002635551361907296, + 0.002646953079123743, 0.002658381076686089, 0.002669836827288052, 0.002681321797012387, + 0.002692837446676144, 0.002704385233135737, 0.002715966610556786, 0.002727583031652520, + 0.002739235948893221, 0.002750926815690169, 0.002762657087557796, 0.002774428223256353, + 0.002786241685917290, 0.002798098944155558, 0.002810001473169871, 0.002821950755833219, + 0.002833948283778004, 0.002845995558475284, 0.002858094092312607, 0.002870245409671041, + 0.002882451048004164, 0.002894712558920987, 0.002907031509275432, 0.002919409482262880, + 0.002931848078526783, 0.002944348917277934, 0.002956913637427061, 0.002969543898733384, + 0.002982241382970874, 0.002995007795115689, 0.003007844864553855, 0.003020754346314269, + 0.003033738022328147, 0.003046797702715820, 0.003059935227105459, 0.003073152465984053, + 0.003086451322084072, 0.003099833731808721, 0.003113301666695822, 0.003126857134927052, + 0.003140502182881588, 0.003154238896738770, 0.003168069404132778, 0.003181995875862154, + 0.003196020527657495, 0.003210145622009941, 0.003224373470066433, 0.003238706433592253, + 0.003253146927007733, 0.003267697419501892, 0.003282360437226572, 0.003297138565578506, + 0.003312034451571411, 0.003327050806304299, 0.003342190407532641, 0.003357456102345890, + 0.003372850809960137, 0.003388377524629727, 0.003404039318688046, 0.003419839345721265, + 0.003435780843885239, 0.003451867139373843, 0.003468101650046629, 0.003484487889225119, + 0.003501029469670069, 0.003517730107746697, 0.003534593627793237, 0.003551623966702611, + 0.003568825178730639, 0.003586201440546166, 0.003603757056536316, 0.003621496464384588, + 0.003639424240937217, 0.003657545108379068, 0.003675863940735269, 0.003694385770723563, + 0.003713115796977806, 0.003732059391668707, 0.003751222108547281, 0.003770609691440940, + 0.003790228083232539, 0.003810083435355216, 0.003830182117840641, 0.003850530729957835, + 0.003871136111486317, 0.003892005354668437, 0.003913145816891062, 0.003934565134149914, + 0.003956271235355358, 0.003978272357543333, 0.004000577062061084, 0.004023194251800533, + 0.004046133189565926, 0.004069403517661885, 0.004093015278800460, 0.004116978938436600, + 0.004141305408647655, 0.004166006073685835, 0.004191092817346642, 0.004216578052307351, + 0.004242474751606884, 0.004268796482457593, 0.004295557442594244, 0.004322772499391836, + 0.004350457232007221, 0.004378627976825644, 0.004407301876525049, 0.004436496933105327, + 0.004466232065271192, 0.004496527170598785, 0.004527403192966406, 0.004558882195791591, + 0.004590987441673855, 0.004623743479123199, 0.004657176237135574, 0.004691313128472929, + 0.004726183162616859, 0.004761817069491636, 0.004798247435199299, 0.004835508851176451, + 0.004873638078381815, 0.004912674228345848, 0.004952658963181422, 0.004993636716962402, + 0.005035654941235035, 0.005078764377854039, 0.005123019362831771, 0.005168478165478940, + 0.005215203367812893, 0.005263262290042703, 0.005312727468930079, 0.005363677197016692, + 0.005416196132139284, 0.005470375988385734, 0.005526316321746716, 0.005584125426278286, + 0.005643921359735682, 0.005705833121505521, 0.005770002010457520, 0.005836583196307310, + 0.005905747545561058, 0.005977683752542928, 0.006052600837980204, 0.006130731092920838, + 0.006212333565464245, 0.006297698213369562, 0.006387150879090475, 0.006481059288027780, + 0.006579840329791975, 0.006683968961788356, 0.006793989182803495, 0.006910527673723577, + 0.007034310911336661, 0.007166186857056056, 0.007307152748134871, 0.007458391141830445, + 0.007621317291194862, 0.007797642342679434, 0.007989459040836144, 0.008199360125510702, + 0.008430605346682607, 0.008687362737884952, 0.008975066840784529, 0.009300967772353674, + 0.009675004947253041, 0.010111261142904171, 0.010630518154258861, 0.011265064987797335, + 0.012068570920629962, 0.013138877484087819, 0.014680138359337902, 0.017222609470315398, + 0.022898298717268672]; +pub static ZIG_EXP_R: f64 = 7.697117470131050077; +pub static ZIG_EXP_X: [f64, .. 257] = + [8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696, + 6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488, + 5.323090505754398016, 5.181487281301500047, 5.054288489981304089, 4.938777085901250530, + 4.832939741025112035, 4.735242996601741083, 4.644491885420085175, 4.559737061707351380, + 4.480211746528421912, 4.405287693473573185, 4.334443680317273007, 4.267242480277365857, + 4.203313713735184365, 4.142340865664051464, 4.084051310408297830, 4.028208544647936762, + 3.974606066673788796, 3.923062500135489739, 3.873417670399509127, 3.825529418522336744, + 3.779270992411667862, 3.734528894039797375, 3.691201090237418825, 3.649195515760853770, + 3.608428813128909507, 3.568825265648337020, 3.530315889129343354, 3.492837654774059608, + 3.456332821132760191, 3.420748357251119920, 3.386035442460300970, 3.352149030900109405, + 3.319047470970748037, 3.286692171599068679, 3.255047308570449882, 3.224079565286264160, + 3.193757903212240290, 3.164053358025972873, 3.134938858084440394, 3.106389062339824481, + 3.078380215254090224, 3.050890016615455114, 3.023897504455676621, 2.997382949516130601, + 2.971327759921089662, 2.945714394895045718, 2.920526286512740821, 2.895747768600141825, + 2.871364012015536371, 2.847360965635188812, 2.823725302450035279, 2.800444370250737780, + 2.777506146439756574, 2.754899196562344610, 2.732612636194700073, 2.710636095867928752, + 2.688959688741803689, 2.667573980773266573, 2.646469963151809157, 2.625639026797788489, + 2.605072938740835564, 2.584763820214140750, 2.564704126316905253, 2.544886627111869970, + 2.525304390037828028, 2.505950763528594027, 2.486819361740209455, 2.467904050297364815, + 2.449198932978249754, 2.430698339264419694, 2.412396812688870629, 2.394289099921457886, + 2.376370140536140596, 2.358635057409337321, 2.341079147703034380, 2.323697874390196372, + 2.306486858283579799, 2.289441870532269441, 2.272558825553154804, 2.255833774367219213, + 2.239262898312909034, 2.222842503111036816, 2.206569013257663858, 2.190438966723220027, + 2.174449009937774679, 2.158595893043885994, 2.142876465399842001, 2.127287671317368289, + 2.111826546019042183, 2.096490211801715020, 2.081275874393225145, 2.066180819490575526, + 2.051202409468584786, 2.036338080248769611, 2.021585338318926173, 2.006941757894518563, + 1.992404978213576650, 1.977972700957360441, 1.963642687789548313, 1.949412758007184943, + 1.935280786297051359, 1.921244700591528076, 1.907302480018387536, 1.893452152939308242, + 1.879691795072211180, 1.866019527692827973, 1.852433515911175554, 1.838931967018879954, + 1.825513128903519799, 1.812175288526390649, 1.798916770460290859, 1.785735935484126014, + 1.772631179231305643, 1.759600930889074766, 1.746643651946074405, 1.733757834985571566, + 1.720942002521935299, 1.708194705878057773, 1.695514524101537912, 1.682900062917553896, + 1.670349953716452118, 1.657862852574172763, 1.645437439303723659, 1.633072416535991334, + 1.620766508828257901, 1.608518461798858379, 1.596327041286483395, 1.584191032532688892, + 1.572109239386229707, 1.560080483527888084, 1.548103603714513499, 1.536177455041032092, + 1.524300908219226258, 1.512472848872117082, 1.500692176842816750, 1.488957805516746058, + 1.477268661156133867, 1.465623682245745352, 1.454021818848793446, 1.442462031972012504, + 1.430943292938879674, 1.419464582769983219, 1.408024891569535697, 1.396623217917042137, + 1.385258568263121992, 1.373929956328490576, 1.362636402505086775, 1.351376933258335189, + 1.340150580529504643, 1.328956381137116560, 1.317793376176324749, 1.306660610415174117, + 1.295557131686601027, 1.284481990275012642, 1.273434238296241139, 1.262412929069615330, + 1.251417116480852521, 1.240445854334406572, 1.229498195693849105, 1.218573192208790124, + 1.207669893426761121, 1.196787346088403092, 1.185924593404202199, 1.175080674310911677, + 1.164254622705678921, 1.153445466655774743, 1.142652227581672841, 1.131873919411078511, + 1.121109547701330200, 1.110358108727411031, 1.099618588532597308, 1.088889961938546813, + 1.078171191511372307, 1.067461226479967662, 1.056759001602551429, 1.046063435977044209, + 1.035373431790528542, 1.024687873002617211, 1.014005623957096480, 1.003325527915696735, + 0.992646405507275897, 0.981967053085062602, 0.971286240983903260, 0.960602711668666509, + 0.949915177764075969, 0.939222319955262286, 0.928522784747210395, 0.917815182070044311, + 0.907098082715690257, 0.896370015589889935, 0.885629464761751528, 0.874874866291025066, + 0.864104604811004484, 0.853317009842373353, 0.842510351810368485, 0.831682837734273206, + 0.820832606554411814, 0.809957724057418282, 0.799056177355487174, 0.788125868869492430, + 0.777164609759129710, 0.766170112735434672, 0.755139984181982249, 0.744071715500508102, + 0.732962673584365398, 0.721810090308756203, 0.710611050909655040, 0.699362481103231959, + 0.688061132773747808, 0.676703568029522584, 0.665286141392677943, 0.653804979847664947, + 0.642255960424536365, 0.630634684933490286, 0.618936451394876075, 0.607156221620300030, + 0.595288584291502887, 0.583327712748769489, 0.571267316532588332, 0.559100585511540626, + 0.546820125163310577, 0.534417881237165604, 0.521885051592135052, 0.509211982443654398, + 0.496388045518671162, 0.483401491653461857, 0.470239275082169006, 0.456886840931420235, + 0.443327866073552401, 0.429543940225410703, 0.415514169600356364, 0.401214678896277765, + 0.386617977941119573, 0.371692145329917234, 0.356399760258393816, 0.340696481064849122, + 0.324529117016909452, 0.307832954674932158, 0.290527955491230394, 0.272513185478464703, + 0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842, + 0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570, + 0.000000000000000000]; +pub static ZIG_EXP_F: [f64, .. 257] = + [0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573, + 0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797, + 0.004877655983542396, 0.005619642207205489, 0.006381905937319183, 0.007163353183634991, + 0.007963077438017043, 0.008780314985808977, 0.009614413642502212, 0.010464810181029981, + 0.011331013597834600, 0.012212592426255378, 0.013109164931254991, 0.014020391403181943, + 0.014945968011691148, 0.015885621839973156, 0.016839106826039941, 0.017806200410911355, + 0.018786700744696024, 0.019780424338009740, 0.020787204072578114, 0.021806887504283581, + 0.022839335406385240, 0.023884420511558174, 0.024942026419731787, 0.026012046645134221, + 0.027094383780955803, 0.028188948763978646, 0.029295660224637411, 0.030414443910466622, + 0.031545232172893622, 0.032687963508959555, 0.033842582150874358, 0.035009037697397431, + 0.036187284781931443, 0.037377282772959382, 0.038578995503074871, 0.039792391023374139, + 0.041017441380414840, 0.042254122413316254, 0.043502413568888197, 0.044762297732943289, + 0.046033761076175184, 0.047316792913181561, 0.048611385573379504, 0.049917534282706379, + 0.051235237055126281, 0.052564494593071685, 0.053905310196046080, 0.055257689676697030, + 0.056621641283742870, 0.057997175631200659, 0.059384305633420280, 0.060783046445479660, + 0.062193415408541036, 0.063615431999807376, 0.065049117786753805, 0.066494496385339816, + 0.067951593421936643, 0.069420436498728783, 0.070901055162371843, 0.072393480875708752, + 0.073897746992364746, 0.075413888734058410, 0.076941943170480517, 0.078481949201606435, + 0.080033947542319905, 0.081597980709237419, 0.083174093009632397, 0.084762330532368146, + 0.086362741140756927, 0.087975374467270231, 0.089600281910032886, 0.091237516631040197, + 0.092887133556043569, 0.094549189376055873, 0.096223742550432825, 0.097910853311492213, + 0.099610583670637132, 0.101322997425953631, 0.103048160171257702, 0.104786139306570145, + 0.106537004050001632, 0.108300825451033755, 0.110077676405185357, 0.111867631670056283, + 0.113670767882744286, 0.115487163578633506, 0.117316899211555525, 0.119160057175327641, + 0.121016721826674792, 0.122886979509545108, 0.124770918580830933, 0.126668629437510671, + 0.128580204545228199, 0.130505738468330773, 0.132445327901387494, 0.134399071702213602, + 0.136367070926428829, 0.138349428863580176, 0.140346251074862399, 0.142357645432472146, + 0.144383722160634720, 0.146424593878344889, 0.148480375643866735, 0.150551185001039839, + 0.152637142027442801, 0.154738369384468027, 0.156854992369365148, 0.158987138969314129, + 0.161134939917591952, 0.163298528751901734, 0.165478041874935922, 0.167673618617250081, + 0.169885401302527550, 0.172113535315319977, 0.174358169171353411, 0.176619454590494829, + 0.178897546572478278, 0.181192603475496261, 0.183504787097767436, 0.185834262762197083, + 0.188181199404254262, 0.190545769663195363, 0.192928149976771296, 0.195328520679563189, + 0.197747066105098818, 0.200183974691911210, 0.202639439093708962, 0.205113656293837654, + 0.207606827724221982, 0.210119159388988230, 0.212650861992978224, 0.215202151075378628, + 0.217773247148700472, 0.220364375843359439, 0.222975768058120111, 0.225607660116683956, + 0.228260293930716618, 0.230933917169627356, 0.233628783437433291, 0.236345152457059560, + 0.239083290262449094, 0.241843469398877131, 0.244625969131892024, 0.247431075665327543, + 0.250259082368862240, 0.253110290015629402, 0.255985007030415324, 0.258883549749016173, + 0.261806242689362922, 0.264753418835062149, 0.267725419932044739, 0.270722596799059967, + 0.273745309652802915, 0.276793928448517301, 0.279868833236972869, 0.282970414538780746, + 0.286099073737076826, 0.289255223489677693, 0.292439288161892630, 0.295651704281261252, + 0.298892921015581847, 0.302163400675693528, 0.305463619244590256, 0.308794066934560185, + 0.312155248774179606, 0.315547685227128949, 0.318971912844957239, 0.322428484956089223, + 0.325917972393556354, 0.329440964264136438, 0.332998068761809096, 0.336589914028677717, + 0.340217149066780189, 0.343880444704502575, 0.347580494621637148, 0.351318016437483449, + 0.355093752866787626, 0.358908472948750001, 0.362762973354817997, 0.366658079781514379, + 0.370594648435146223, 0.374573567615902381, 0.378595759409581067, 0.382662181496010056, + 0.386773829084137932, 0.390931736984797384, 0.395136981833290435, 0.399390684475231350, + 0.403694012530530555, 0.408048183152032673, 0.412454465997161457, 0.416914186433003209, + 0.421428728997616908, 0.425999541143034677, 0.430628137288459167, 0.435316103215636907, + 0.440065100842354173, 0.444876873414548846, 0.449753251162755330, 0.454696157474615836, + 0.459707615642138023, 0.464789756250426511, 0.469944825283960310, 0.475175193037377708, + 0.480483363930454543, 0.485871987341885248, 0.491343869594032867, 0.496901987241549881, + 0.502549501841348056, 0.508289776410643213, 0.514126393814748894, 0.520063177368233931, + 0.526104213983620062, 0.532253880263043655, 0.538516872002862246, 0.544898237672440056, + 0.551403416540641733, 0.558038282262587892, 0.564809192912400615, 0.571723048664826150, + 0.578787358602845359, 0.586010318477268366, 0.593400901691733762, 0.600968966365232560, + 0.608725382079622346, 0.616682180915207878, 0.624852738703666200, 0.633251994214366398, + 0.641896716427266423, 0.650805833414571433, 0.660000841079000145, 0.669506316731925177, + 0.679350572264765806, 0.689566496117078431, 0.700192655082788606, 0.711274760805076456, + 0.722867659593572465, 0.735038092431424039, 0.747868621985195658, 0.761463388849896838, + 0.775956852040116218, 0.791527636972496285, 0.808421651523009044, 0.826993296643051101, + 0.847785500623990496, 0.871704332381204705, 0.900469929925747703, 0.938143680862176477, + 1.000000000000000000]; +pub static ZIG_EXP_F_DIFF: [f64, .. 257] = + [0.000000000000000000, 0.000287067661533533, 0.000513134928485678, 0.000569030497974398, + 0.000609667963417335, 0.000642831049855169, 0.000671465984262828, 0.000697030342996893, + 0.000720360862708599, 0.000741986223663093, 0.000762263730113694, 0.000781447246315807, + 0.000799724254382053, 0.000817237547791934, 0.000834098656693235, 0.000850396538527769, + 0.000866203416804620, 0.000881578828420777, 0.000896572504999613, 0.000911226471926952, + 0.000925576608509206, 0.000939653828282008, 0.000953484986066785, 0.000967093584871414, + 0.000980500333784669, 0.000993723593313716, 0.001006779734568374, 0.001019683431705467, + 0.001032447902101660, 0.001045085105172934, 0.001057605908173612, 0.001070020225402434, + 0.001082337135821582, 0.001094564983022843, 0.001106711460658764, 0.001118783685829211, + 0.001130788262427001, 0.001142731336065933, 0.001154618641914802, 0.001166455546523074, + 0.001178247084534012, 0.001189997991027938, 0.001201712730115490, 0.001213395520299268, + 0.001225050357040701, 0.001236681032901414, 0.001248291155571943, 0.001259884164055092, + 0.001271463343231895, 0.001283031837006378, 0.001294592660197942, 0.001306148709326875, + 0.001317702772419903, 0.001329257537945404, 0.001340815602974395, 0.001352379480650950, + 0.001363951607045839, 0.001375534347457789, 0.001387130002219621, 0.001398740812059381, + 0.001410368963061376, 0.001422016591266340, 0.001433685786946429, 0.001445378598586011, + 0.001457097036596827, 0.001468843076792140, 0.001480618663643060, 0.001492425713336909, + 0.001504266116655995, 0.001516141741693663, 0.001528054436422108, 0.001540006031125918, + 0.001551998340713470, 0.001564033166917514, 0.001576112300394977, 0.001588237522735750, + 0.001600410608388780, 0.001612633326513305, 0.001624907442762655, 0.001637234721007311, + 0.001649616925003372, 0.001662055820012304, 0.001674553174376953, 0.001687110761059388, + 0.001699730359144919, 0.001712413755316500, 0.001725162745304071, 0.001737979135312442, + 0.001750864743431488, 0.001763821401032123, 0.001776850954151601, 0.001789955264870927, + 0.001803136212688003, 0.001816395695889220, 0.001829735632922019, 0.001843157963772116, + 0.001856664651347151, 0.001870257682870316, 0.001883939071285826, 0.001897710856679738, + 0.001911575107717528, 0.001925533923102574, 0.001939589433056721, 0.001953743800826108, + 0.001967999224215228, 0.001982357937151347, 0.001996822211282223, 0.002011394357609747, + 0.002026076728162574, 0.002040871717710169, 0.002055781765521847, 0.002070809357173103, + 0.002085957026402963, 0.002101227357025226, 0.002116622984897121, 0.002132146599948981, + 0.002147800948277823, 0.002163588834309782, 0.002179513123034188, 0.002195576742314159, + 0.002211782685277469, 0.002228134012792427, 0.002244633856033434, 0.002261285419141418, + 0.002278091981983449, 0.002295056903017983, 0.002312183622271174, 0.002329475664429648, + 0.002346936642057179, 0.002364570258941101, 0.002382380313575932, 0.002400370702791893, + 0.002418545425535629, 0.002436908586812392, 0.002455464401797752, 0.002474217200128692, + 0.002493171430384328, 0.002512331664766249, 0.002531702603989994, 0.002551289082400404, + 0.002571096073321844, 0.002591128694658967, 0.002611392214760672, 0.002631892058563845, + 0.002652633814032662, 0.002673623238910738, 0.002694866267805934, 0.002716369019626269, + 0.002738137805389534, 0.002760179136428037, 0.002782499733014893, 0.002805106533435520, + 0.002828006703534697, 0.002851207646767162, 0.002874717014785921, 0.002898542718600849, + 0.002922692940346749, 0.002947176145699226, 0.002972001096982591, 0.002997176867015228, + 0.003022712853742948, 0.003048618795714386, 0.003074904788455568, 0.003101581301807876, + 0.003128659198296080, 0.003156149752600867, 0.003184064672214937, 0.003212416119368622, + 0.003241216734320596, 0.003270479660111680, 0.003300218568896729, 0.003330447689969929, + 0.003361181839619420, 0.003392436452949343, 0.003424227617828290, 0.003456572111131984, + 0.003489487437467131, 0.003522991870580083, 0.003557104497672658, 0.003591845266868621, + 0.003627235038102472, 0.003663295637722386, 0.003700049917134574, 0.003737521815846301, + 0.003775736429304177, 0.003814720081962375, 0.003854500406067995, 0.003895106426696382, + 0.003936568653631844, 0.003978919180756157, 0.004022191793678687, 0.004066422086428989, + 0.004111647588127876, 0.004157907900659452, 0.004205244848493050, 0.004253702641940915, + 0.004303328055299205, 0.004354170621502118, 0.004406282845128784, 0.004459720435841752, + 0.004514542564613699, 0.004570812145417769, 0.004628596145424491, 0.004687965927177740, + 0.004748997626717266, 0.004811772572194672, 0.004876377748206484, 0.004942906311860507, + 0.005011458167522187, 0.005082140608288488, 0.005155069033533799, 0.005230367753417398, + 0.005308170893076836, 0.005388623411430704, 0.005471882252147620, 0.005558117647517014, + 0.005647514599798176, 0.005740274569295156, 0.005836617404105682, 0.005936783553485037, + 0.006041036615386131, 0.006149666279423593, 0.006262991739818591, 0.006381365669577810, + 0.006505178868201678, 0.006634865721946159, 0.006770910649812723, 0.006913855752425535, + 0.007064309938019209, 0.007222959874423007, 0.007390583214465396, 0.007568064673498798, + 0.007756415714389786, 0.007956798835585532, 0.008170557788458321, 0.008399255510700199, + 0.008644722212900025, 0.008909116987305010, 0.009195007664428712, 0.009505475652925033, + 0.009844255532840629, 0.010215923852312625, 0.010626158965710175, 0.011082105722287849, + 0.011592898788496009, 0.012170432837851575, 0.012830529553771619, 0.013594766864701180, + 0.014493463190219380, 0.015570784932380066, 0.016894014550512759, 0.018571645120042057, + 0.020792203980939394, 0.023918831757214210, 0.028765597544542998, 0.037673750936428774, + 0.061856319137823523]; diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs index abcb727809e..3d525993259 100644 --- a/src/libcore/repr.rs +++ b/src/libcore/repr.rs @@ -564,7 +564,7 @@ pub fn write_repr<T>(writer: @Writer, object: &T) { } } -#[test] +#[cfg(test)] struct P {a: int, b: float} #[test] diff --git a/src/libcore/rt/context.rs b/src/libcore/rt/context.rs index 4714be9e3d5..9c1e566f218 100644 --- a/src/libcore/rt/context.rs +++ b/src/libcore/rt/context.rs @@ -207,4 +207,3 @@ pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T { use core::sys::size_of; (ptr as int + count * (size_of::<T>() as int)) as *mut T } - diff --git a/src/libcore/rt/io/comm_adapters.rs b/src/libcore/rt/io/comm_adapters.rs index 1d6893b3ca6..7e891f1718e 100644 --- a/src/libcore/rt/io/comm_adapters.rs +++ b/src/libcore/rt/io/comm_adapters.rs @@ -56,4 +56,3 @@ impl<W: Writer> WriterChan<W> { impl<W: Writer> GenericChan<~[u8]> for WriterChan<W> { fn send(&self, _x: ~[u8]) { fail!() } } - diff --git a/src/libcore/rt/io/util.rs b/src/libcore/rt/io/extensions.rs index cff224a80be..cff224a80be 100644 --- a/src/libcore/rt/io/util.rs +++ b/src/libcore/rt/io/extensions.rs diff --git a/src/libcore/rt/io/file.rs b/src/libcore/rt/io/file.rs index e041183b584..85dc180452f 100644 --- a/src/libcore/rt/io/file.rs +++ b/src/libcore/rt/io/file.rs @@ -9,13 +9,9 @@ // except according to those terms. use prelude::*; -use super::misc::PathLike; +use super::support::PathLike; use super::{Reader, Writer, Seek, Close}; -use super::{IoError, SeekStyle}; - -/// Open a file with the default FileMode and FileAccess -/// # XXX are there sane defaults here? -pub fn open_file<P: PathLike>(_path: &P) -> FileStream { fail!() } +use super::SeekStyle; /// # XXX /// * Ugh, this is ridiculous. What is the best way to represent these options? @@ -46,7 +42,7 @@ impl FileStream { pub fn open<P: PathLike>(_path: &P, _mode: FileMode, _access: FileAccess - ) -> Result<FileStream, IoError> { + ) -> Option<FileStream> { fail!() } } diff --git a/src/libcore/rt/io/mem.rs b/src/libcore/rt/io/mem.rs index 600968a3c71..06e1466831d 100644 --- a/src/libcore/rt/io/mem.rs +++ b/src/libcore/rt/io/mem.rs @@ -17,7 +17,7 @@ use prelude::*; use super::*; - +use cmp::min; /// Writes to an owned, growable byte vector pub struct MemWriter { @@ -29,13 +29,15 @@ impl MemWriter { } impl Writer for MemWriter { - fn write(&mut self, _buf: &[u8]) { fail!() } + fn write(&mut self, buf: &[u8]) { + self.buf.push_all(buf) + } fn flush(&mut self) { /* no-op */ } } impl Seek for MemWriter { - fn tell(&self) -> u64 { fail!() } + fn tell(&self) -> u64 { self.buf.len() as u64 } fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } } @@ -77,13 +79,27 @@ impl MemReader { } impl Reader for MemReader { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } + fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + { if self.eof() { return None; } } + + let write_len = min(buf.len(), self.buf.len() - self.pos); + { + let input = self.buf.slice(self.pos, self.pos + write_len); + let output = vec::mut_slice(buf, 0, write_len); + assert!(input.len() == output.len()); + vec::bytes::copy_memory(output, input, write_len); + } + self.pos += write_len; + assert!(self.pos <= self.buf.len()); - fn eof(&mut self) -> bool { fail!() } + return Some(write_len); + } + + fn eof(&mut self) -> bool { self.pos == self.buf.len() } } impl Seek for MemReader { - fn tell(&self) -> u64 { fail!() } + fn tell(&self) -> u64 { self.pos as u64 } fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } } @@ -163,4 +179,43 @@ impl<'self> Seek for BufReader<'self> { fn tell(&self) -> u64 { fail!() } fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} \ No newline at end of file +} + +#[cfg(test)] +mod test { + use prelude::*; + use super::*; + + #[test] + fn test_mem_writer() { + let mut writer = MemWriter::new(); + assert!(writer.tell() == 0); + writer.write([0]); + assert!(writer.tell() == 1); + writer.write([1, 2, 3]); + writer.write([4, 5, 6, 7]); + assert!(writer.tell() == 8); + assert!(writer.inner() == ~[0, 1, 2, 3, 4, 5 , 6, 7]); + } + + #[test] + fn test_mem_reader() { + let mut reader = MemReader::new(~[0, 1, 2, 3, 4, 5, 6, 7]); + let mut buf = []; + assert!(reader.read(buf) == Some(0)); + assert!(reader.tell() == 0); + let mut buf = [0]; + assert!(reader.read(buf) == Some(1)); + assert!(reader.tell() == 1); + assert!(buf == [0]); + let mut buf = [0, ..4]; + assert!(reader.read(buf) == Some(4)); + assert!(reader.tell() == 5); + assert!(buf == [1, 2, 3, 4]); + assert!(reader.read(buf) == Some(3)); + assert!(buf.slice(0, 3) == [5, 6, 7]); + assert!(reader.eof()); + assert!(reader.read(buf) == None); + assert!(reader.eof()); + } +} diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs index cb00b02d9d1..97b3ee3e30e 100644 --- a/src/libcore/rt/io/mod.rs +++ b/src/libcore/rt/io/mod.rs @@ -11,7 +11,13 @@ /*! Synchronous I/O This module defines the Rust interface for synchronous I/O. -It supports file access, +It models byte-oriented input and output with the Reader and Writer traits. +Types that implement both `Reader` and `Writer` and called 'streams', +and automatically implement trait `Stream`. +Implementations are provided for common I/O streams like +file, TCP, UDP, Unix domain sockets. +Readers and Writers may be composed to add capabilities like string +parsing, encoding, and compression. This will likely live in core::io, not core::rt::io. @@ -27,44 +33,177 @@ Some examples of obvious things you might want to do * Read a complete file to a string, (converting newlines?) - let contents = open("message.txt").read_to_str(); // read_to_str?? + let contents = File::open("message.txt").read_to_str(); // read_to_str?? * Write a line to a file - let file = FileStream::open("message.txt", Create, Write); + let file = File::open("message.txt", Create, Write); file.write_line("hello, file!"); * Iterate over the lines of a file + do File::open("message.txt").each_line |line| { + println(line) + } + * Pull the lines of a file into a vector of strings + let lines = File::open("message.txt").line_iter().to_vec(); + +* Make an simple HTTP request + + let socket = TcpStream::open("localhost:8080"); + socket.write_line("GET / HTTP/1.0"); + socket.write_line(""); + let response = socket.read_to_end(); + * Connect based on URL? Requires thinking about where the URL type lives and how to make protocol handlers extensible, e.g. the "tcp" protocol yields a `TcpStream`. - connect("tcp://localhost:8080").write_line("HTTP 1.0 GET /"); + connect("tcp://localhost:8080"); # Terms -* reader -* writer -* stream -* Blocking vs. non-blocking -* synchrony and asynchrony - -I tend to call this implementation non-blocking, because performing I/O -doesn't block the progress of other tasks. Is that how we want to present -it, 'synchronous but non-blocking'? +* Reader - An I/O source, reads bytes into a buffer +* Writer - An I/O sink, writes bytes from a buffer +* Stream - Typical I/O sources like files and sockets are both Readers and Writers, + and are collectively referred to a `streams`. +* Decorator - A Reader or Writer that composes with others to add additional capabilities + such as encoding or decoding + +# Blocking and synchrony + +When discussing I/O you often hear the terms 'synchronous' and +'asynchronous', along with 'blocking' and 'non-blocking' compared and +contrasted. A synchronous I/O interface performs each I/O operation to +completion before proceeding to the next. Synchronous interfaces are +usually used in imperative style as a sequence of commands. An +asynchronous interface allows multiple I/O requests to be issued +simultaneously, without waiting for each to complete before proceeding +to the next. + +Asynchronous interfaces are used to achieve 'non-blocking' I/O. In +traditional single-threaded systems, performing a synchronous I/O +operation means that the program stops all activity (it 'blocks') +until the I/O is complete. Blocking is bad for performance when +there are other computations that could be done. + +Asynchronous interfaces are most often associated with the callback +(continuation-passing) style popularised by node.js. Such systems rely +on all computations being run inside an event loop which maintains a +list of all pending I/O events; when one completes the registered +callback is run and the code that made the I/O request continiues. +Such interfaces achieve non-blocking at the expense of being more +difficult to reason about. + +Rust's I/O interface is synchronous - easy to read - and non-blocking by default. + +Remember that Rust tasks are 'green threads', lightweight threads that +are multiplexed onto a single operating system thread. If that system +thread blocks then no other task may proceed. Rust tasks are +relatively cheap to create, so as long as other tasks are free to +execute then non-blocking code may be written by simply creating a new +task. + +When discussing blocking in regards to Rust's I/O model, we are +concerned with whether performing I/O blocks other Rust tasks from +proceeding. In other words, when a task calls `read`, it must then +wait (or 'sleep', or 'block') until the call to `read` is complete. +During this time, other tasks may or may not be executed, depending on +how `read` is implemented. + + +Rust's default I/O implementation is non-blocking; by cooperating +directly with the task scheduler it arranges to never block progress +of *other* tasks. Under the hood, Rust uses asynchronous I/O via a +per-scheduler (and hence per-thread) event loop. Synchronous I/O +requests are implemented by descheduling the running task and +performing an asynchronous request; the task is only resumed once the +asynchronous request completes. + +For blocking (but possibly more efficient) implementations, look +in the `io::native` module. # Error Handling +I/O is an area where nearly every operation can result in unexpected +errors. It should allow errors to be handled efficiently. +It needs to be convenient to use I/O when you don't care +about dealing with specific errors. + +Rust's I/O employs a combination of techniques to reduce boilerplate +while still providing feedback about errors. The basic strategy: + +* Errors are fatal by default, resulting in task failure +* Errors raise the `io_error` conditon which provides an opportunity to inspect + an IoError object containing details. +* Return values must have a sensible null or zero value which is returned + if a condition is handled successfully. This may be an `Option`, an empty + vector, or other designated error value. +* Common traits are implemented for `Option`, e.g. `impl<R: Reader> Reader for Option<R>`, + so that nullable values do not have to be 'unwrapped' before use. + +These features combine in the API to allow for expressions like +`File::new("diary.txt").write_line("met a girl")` without having to +worry about whether "diary.txt" exists or whether the write +succeeds. As written, if either `new` or `write_line` encounters +an error the task will fail. + +If you wanted to handle the error though you might write + + let mut error = None; + do io_error::cond(|e: IoError| { + error = Some(e); + }).in { + File::new("diary.txt").write_line("met a girl"); + } + + if error.is_some() { + println("failed to write my diary"); + } + +XXX: Need better condition handling syntax + +In this case the condition handler will have the opportunity to +inspect the IoError raised by either the call to `new` or the call to +`write_line`, but then execution will continue. + +So what actually happens if `new` encounters an error? To understand +that it's important to know that what `new` returns is not a `File` +but an `Option<File>`. If the file does not open, and the condition +is handled, then `new` will simply return `None`. Because there is an +implementation of `Writer` (the trait required ultimately required for +types to implement `write_line`) there is no need to inspect or unwrap +the `Option<File>` and we simply call `write_line` on it. If `new` +returned a `None` then the followup call to `write_line` will also +raise an error. + +## Concerns about this strategy + +This structure will encourage a programming style that is prone +to errors similar to null pointer dereferences. +In particular code written to ignore errors and expect conditions to be unhandled +will start passing around null or zero objects when wrapped in a condition handler. + +* XXX: How should we use condition handlers that return values? + + +# Issues withi/o scheduler affinity, work stealing, task pinning + # Resource management * `close` vs. RAII -# Paths and URLs +# Paths, URLs and overloaded constructors + + + +# Scope -# std +In scope for core + +* Url? Some I/O things don't belong in core @@ -73,7 +212,12 @@ Some I/O things don't belong in core - http - flate -# XXX +Out of scope + +* Async I/O. We'll probably want it eventually + + +# XXX Questions and issues * Should default constructors take `Path` or `&str`? `Path` makes simple cases verbose. Overloading would be nice. @@ -83,6 +227,7 @@ Some I/O things don't belong in core * fsync * relationship with filesystem querying, Directory, File types etc. * Rename Reader/Writer to ByteReader/Writer, make Reader/Writer generic? +* Can Port and Chan be implementations of a generic Reader<T>/Writer<T>? * Trait for things that are both readers and writers, Stream? * How to handle newline conversion * String conversion @@ -92,6 +237,7 @@ Some I/O things don't belong in core * Do we need `close` at all? dtors might be good enough * How does I/O relate to the Iterator trait? * std::base64 filters +* Using conditions is a big unknown since we don't have much experience with them */ @@ -104,25 +250,29 @@ pub use self::stdio::stderr; pub use self::stdio::print; pub use self::stdio::println; -pub use self::file::open_file; pub use self::file::FileStream; -pub use self::net::Listener; pub use self::net::ip::IpAddr; pub use self::net::tcp::TcpListener; pub use self::net::tcp::TcpStream; pub use self::net::udp::UdpStream; // Some extension traits that all Readers and Writers get. -pub use self::util::ReaderUtil; -pub use self::util::ReaderByteConversions; -pub use self::util::WriterByteConversions; +pub use self::extensions::ReaderUtil; +pub use self::extensions::ReaderByteConversions; +pub use self::extensions::WriterByteConversions; /// Synchronous, non-blocking file I/O. pub mod file; /// Synchronous, non-blocking network I/O. -#[path = "net/mod.rs"] -pub mod net; +pub mod net { + pub mod tcp; + pub mod udp; + pub mod ip; + #[cfg(unix)] + pub mod unix; + pub mod http; +} /// Readers and Writers for memory buffers and strings. pub mod mem; @@ -130,6 +280,10 @@ pub mod mem; /// Non-blocking access to stdin, stdout, stderr pub mod stdio; +/// Implementations for Option +#[cfg(not(stage0))] // Requires condition! fixes +mod option; + /// Basic stream compression. XXX: Belongs with other flate code pub mod flate; @@ -137,10 +291,10 @@ pub mod flate; pub mod comm_adapters; /// Extension traits -mod util; +mod extensions; /// Non-I/O things needed by the I/O module -mod misc; +mod support; /// Thread-blocking implementations pub mod native { @@ -170,12 +324,14 @@ pub struct IoError { detail: Option<~str> } +#[deriving(Eq)] pub enum IoErrorKind { FileNotFound, FilePermission, ConnectionFailed, Closed, - OtherIoError + OtherIoError, + PreviousIoError } // XXX: Can't put doc comments on macros @@ -208,9 +364,9 @@ pub trait Reader { /// println(reader.read_line()); /// } /// - /// # XXX + /// # Failue /// - /// What does this return if the Reader is in an error state? + /// Returns `true` on failure. fn eof(&mut self) -> bool; } @@ -250,9 +406,30 @@ pub enum SeekStyle { /// * Are `u64` and `i64` the right choices? pub trait Seek { fn tell(&self) -> u64; + + /// Seek to an offset in a stream + /// + /// A successful seek clears the EOF indicator. + /// + /// # XXX + /// + /// * What is the behavior when seeking past the end of a stream? fn seek(&mut self, pos: i64, style: SeekStyle); } +/// A listener is a value that listens for connections +pub trait Listener<S> { + /// Wait for and accept an incoming connection + /// + /// Returns `None` on timeout. + /// + /// # Failure + /// + /// Raises `io_error` condition. If the condition is handled, + /// then `accept` returns `None`. + fn accept(&mut self) -> Option<S>; +} + /// Common trait for decorator types. /// /// Provides accessors to get the inner, 'decorated' values. The I/O library @@ -278,3 +455,16 @@ pub trait Decorator<T> { /// Take a mutable reference to the decorated value fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T; } + +pub fn standard_error(kind: IoErrorKind) -> IoError { + match kind { + PreviousIoError => { + IoError { + kind: PreviousIoError, + desc: "Failing due to a previous I/O error", + detail: None + } + } + _ => fail!() + } +} diff --git a/src/libcore/rt/io/net/ip.rs b/src/libcore/rt/io/net/ip.rs index d9b7f4e6e40..df1dfe4d38a 100644 --- a/src/libcore/rt/io/net/ip.rs +++ b/src/libcore/rt/io/net/ip.rs @@ -12,4 +12,3 @@ pub enum IpAddr { Ipv4(u8, u8, u8, u8, u16), Ipv6 } - diff --git a/src/libcore/rt/io/net/mod.rs b/src/libcore/rt/io/net/mod.rs deleted file mode 100644 index 130ff6b38fa..00000000000 --- a/src/libcore/rt/io/net/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; - -pub mod tcp; -pub mod udp; -pub mod ip; -#[cfg(unix)] -pub mod unix; -pub mod http; - -/// A listener is a value that listens for connections -pub trait Listener<S> { - /// Wait for and accept an incoming connection - /// - /// Returns `None` on timeout. - /// - /// # Failure - /// - /// Raises `io_error` condition. If the condition is handled, - /// then `accept` returns `None`. - fn accept(&mut self) -> Option<S>; -} diff --git a/src/libcore/rt/io/net/tcp.rs b/src/libcore/rt/io/net/tcp.rs index e3f71dca8c8..c95b4344fe7 100644 --- a/src/libcore/rt/io/net/tcp.rs +++ b/src/libcore/rt/io/net/tcp.rs @@ -9,14 +9,13 @@ // except according to those terms. use prelude::*; -use super::*; use super::super::*; use super::ip::IpAddr; pub struct TcpStream; impl TcpStream { - pub fn connect(_addr: IpAddr) -> Result<TcpStream, IoError> { + pub fn connect(_addr: IpAddr) -> Option<TcpStream> { fail!() } } @@ -40,7 +39,7 @@ impl Close for TcpStream { pub struct TcpListener; impl TcpListener { - pub fn new(_addr: IpAddr) -> TcpListener { + pub fn bind(_addr: IpAddr) -> Option<TcpListener> { fail!() } } @@ -48,3 +47,28 @@ impl TcpListener { impl Listener<TcpStream> for TcpListener { fn accept(&mut self) -> Option<TcpStream> { fail!() } } + +#[cfg(test)] +mod test { + + #[test] #[ignore] + fn smoke_test() { + /*do run_in_newsched_task { + let addr = next_test_ip4(); + + do spawn_immediately { + let listener = TcpListener::bind(addr); + do listener.accept() { + let mut buf = [0]; + listener.read(buf); + assert!(buf[0] == 99); + } + } + + do spawn_immediately { + let stream = TcpStream::connect(addr); + stream.write([99]); + } + }*/ + } +} diff --git a/src/libcore/rt/io/net/udp.rs b/src/libcore/rt/io/net/udp.rs index f76bb58a45e..1f1254a7029 100644 --- a/src/libcore/rt/io/net/udp.rs +++ b/src/libcore/rt/io/net/udp.rs @@ -9,14 +9,13 @@ // except according to those terms. use prelude::*; -use super::*; use super::super::*; use super::ip::IpAddr; pub struct UdpStream; impl UdpStream { - pub fn connect(_addr: IpAddr) -> Result<UdpStream, IoError> { + pub fn connect(_addr: IpAddr) -> Option<UdpStream> { fail!() } } @@ -40,7 +39,7 @@ impl Close for UdpStream { pub struct UdpListener; impl UdpListener { - pub fn new(_addr: IpAddr) -> UdpListener { + pub fn bind(_addr: IpAddr) -> Option<UdpListener> { fail!() } } @@ -48,4 +47,3 @@ impl UdpListener { impl Listener<UdpStream> for UdpListener { fn accept(&mut self) -> Option<UdpStream> { fail!() } } - diff --git a/src/libcore/rt/io/net/unix.rs b/src/libcore/rt/io/net/unix.rs index 35eabe21b2a..f449a857467 100644 --- a/src/libcore/rt/io/net/unix.rs +++ b/src/libcore/rt/io/net/unix.rs @@ -9,14 +9,13 @@ // except according to those terms. use prelude::*; -use super::*; use super::super::*; -use super::super::misc::PathLike; +use super::super::support::PathLike; pub struct UnixStream; impl UnixStream { - pub fn connect<P: PathLike>(_path: &P) -> Result<UnixStream, IoError> { + pub fn connect<P: PathLike>(_path: &P) -> Option<UnixStream> { fail!() } } @@ -40,7 +39,7 @@ impl Close for UnixStream { pub struct UnixListener; impl UnixListener { - pub fn new<P: PathLike>(_path: &P) -> UnixListener { + pub fn bind<P: PathLike>(_path: &P) -> Option<UnixListener> { fail!() } } @@ -48,4 +47,3 @@ impl UnixListener { impl Listener<UnixStream> for UnixListener { fn accept(&mut self) -> Option<UnixStream> { fail!() } } - diff --git a/src/libcore/rt/io/option.rs b/src/libcore/rt/io/option.rs new file mode 100644 index 00000000000..95f8711cb5b --- /dev/null +++ b/src/libcore/rt/io/option.rs @@ -0,0 +1,153 @@ +// Copyright 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementations of I/O traits for the Option type +//! +//! I/O constructors return option types to allow errors to be handled. +//! These implementations allow e.g. `Option<FileStream>` to be used +//! as a `Reader` without unwrapping the option first. +//! +//! # XXX Seek and Close + +use option::*; +use super::{Reader, Writer, Listener}; +use super::{standard_error, PreviousIoError, io_error, IoError}; + +fn prev_io_error() -> IoError { + standard_error(PreviousIoError) +} + +impl<W: Writer> Writer for Option<W> { + fn write(&mut self, buf: &[u8]) { + match *self { + Some(ref mut writer) => writer.write(buf), + None => io_error::cond.raise(prev_io_error()) + } + } + + fn flush(&mut self) { + match *self { + Some(ref mut writer) => writer.flush(), + None => io_error::cond.raise(prev_io_error()) + } + } +} + +impl<R: Reader> Reader for Option<R> { + fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + match *self { + Some(ref mut reader) => reader.read(buf), + None => { + io_error::cond.raise(prev_io_error()); + None + } + } + } + + fn eof(&mut self) -> bool { + match *self { + Some(ref mut reader) => reader.eof(), + None => { + io_error::cond.raise(prev_io_error()); + true + } + } + } +} + +impl<L: Listener<S>, S> Listener<S> for Option<L> { + fn accept(&mut self) -> Option<S> { + match *self { + Some(ref mut listener) => listener.accept(), + None => { + io_error::cond.raise(prev_io_error()); + None + } + } + } +} + +#[cfg(test)] +mod test { + use option::*; + use super::super::mem::*; + use rt::test::*; + use super::super::{PreviousIoError, io_error}; + + #[test] + fn test_option_writer() { + do run_in_newsched_task { + let mut writer: Option<MemWriter> = Some(MemWriter::new()); + writer.write([0, 1, 2]); + writer.flush(); + assert!(writer.unwrap().inner() == ~[0, 1, 2]); + } + } + + #[test] + fn test_option_writer_error() { + do run_in_newsched_task { + let mut writer: Option<MemWriter> = None; + + let mut called = false; + do io_error::cond.trap(|err| { + assert!(err.kind == PreviousIoError); + called = true; + }).in { + writer.write([0, 0, 0]); + } + assert!(called); + + let mut called = false; + do io_error::cond.trap(|err| { + assert!(err.kind == PreviousIoError); + called = true; + }).in { + writer.flush(); + } + assert!(called); + } + } + + #[test] + fn test_option_reader() { + do run_in_newsched_task { + let mut reader: Option<MemReader> = Some(MemReader::new(~[0, 1, 2, 3])); + let mut buf = [0, 0]; + reader.read(buf); + assert!(buf == [0, 1]); + assert!(!reader.eof()); + } + } + + #[test] + fn test_option_reader_error() { + let mut reader: Option<MemReader> = None; + let mut buf = []; + + let mut called = false; + do io_error::cond.trap(|err| { + assert!(err.kind == PreviousIoError); + called = true; + }).in { + reader.read(buf); + } + assert!(called); + + let mut called = false; + do io_error::cond.trap(|err| { + assert!(err.kind == PreviousIoError); + called = true; + }).in { + assert!(reader.eof()); + } + assert!(called); + } +} diff --git a/src/libcore/rt/io/misc.rs b/src/libcore/rt/io/support.rs index 7bace5d6df2..7bace5d6df2 100644 --- a/src/libcore/rt/io/misc.rs +++ b/src/libcore/rt/io/support.rs diff --git a/src/libcore/rt/local_heap.rs b/src/libcore/rt/local_heap.rs new file mode 100644 index 00000000000..6bf228a1b22 --- /dev/null +++ b/src/libcore/rt/local_heap.rs @@ -0,0 +1,80 @@ +// Copyright 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The local, garbage collected heap + +use libc::{c_void, uintptr_t, size_t}; +use ops::Drop; + +type MemoryRegion = c_void; +type BoxedRegion = c_void; + +pub type OpaqueBox = c_void; +pub type TypeDesc = c_void; + +pub struct LocalHeap { + memory_region: *MemoryRegion, + boxed_region: *BoxedRegion +} + +impl LocalHeap { + pub fn new() -> LocalHeap { + unsafe { + // Don't need synchronization for the single-threaded local heap + let synchronized = false as uintptr_t; + // XXX: These usually come from the environment + let detailed_leaks = false as uintptr_t; + let poison_on_free = false as uintptr_t; + let region = rust_new_memory_region(synchronized, detailed_leaks, poison_on_free); + assert!(region.is_not_null()); + let boxed = rust_new_boxed_region(region, poison_on_free); + assert!(boxed.is_not_null()); + LocalHeap { + memory_region: region, + boxed_region: boxed + } + } + } + + pub fn alloc(&mut self, td: *TypeDesc, size: uint) -> *OpaqueBox { + unsafe { + return rust_boxed_region_malloc(self.boxed_region, td, size as size_t); + } + } + + pub fn free(&mut self, box: *OpaqueBox) { + unsafe { + return rust_boxed_region_free(self.boxed_region, box); + } + } +} + +impl Drop for LocalHeap { + fn finalize(&self) { + unsafe { + rust_delete_boxed_region(self.boxed_region); + rust_delete_memory_region(self.memory_region); + } + } +} + +extern { + fn rust_new_memory_region(synchronized: uintptr_t, + detailed_leaks: uintptr_t, + poison_on_free: uintptr_t) -> *MemoryRegion; + fn rust_delete_memory_region(region: *MemoryRegion); + fn rust_new_boxed_region(region: *MemoryRegion, + poison_on_free: uintptr_t) -> *BoxedRegion; + fn rust_delete_boxed_region(region: *BoxedRegion); + fn rust_boxed_region_malloc(region: *BoxedRegion, + td: *TypeDesc, + size: size_t) -> *OpaqueBox; + fn rust_boxed_region_free(region: *BoxedRegion, box: *OpaqueBox); +} diff --git a/src/libcore/rt/local_services.rs b/src/libcore/rt/local_services.rs new file mode 100644 index 00000000000..a03bc6c409f --- /dev/null +++ b/src/libcore/rt/local_services.rs @@ -0,0 +1,223 @@ +// Copyright 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Language-level runtime services that should reasonably expected +//! to be available 'everywhere'. Local heaps, GC, unwinding, +//! local storage, and logging. Even a 'freestanding' Rust would likely want +//! to implement this. + +//! Local services may exist in at least three different contexts: +//! when running as a task, when running in the scheduler's context, +//! or when running outside of a scheduler but with local services +//! (freestanding rust with local services?). + +use prelude::*; +use libc::{c_void, uintptr_t}; +use cast::transmute; +use super::sched::local_sched; +use super::local_heap::LocalHeap; + +pub struct LocalServices { + heap: LocalHeap, + gc: GarbageCollector, + storage: LocalStorage, + logger: Logger, + unwinder: Option<Unwinder>, + destroyed: bool +} + +pub struct GarbageCollector; +pub struct LocalStorage(*c_void, Option<~fn(*c_void)>); +pub struct Logger; + +pub struct Unwinder { + unwinding: bool, +} + +impl LocalServices { + pub fn new() -> LocalServices { + LocalServices { + heap: LocalHeap::new(), + gc: GarbageCollector, + storage: LocalStorage(ptr::null(), None), + logger: Logger, + unwinder: Some(Unwinder { unwinding: false }), + destroyed: false + } + } + + pub fn without_unwinding() -> LocalServices { + LocalServices { + heap: LocalHeap::new(), + gc: GarbageCollector, + storage: LocalStorage(ptr::null(), None), + logger: Logger, + unwinder: None, + destroyed: false + } + } + + pub fn run(&mut self, f: &fn()) { + // This is just an assertion that `run` was called unsafely + // and this instance of LocalServices is still accessible. + do borrow_local_services |sched| { + assert!(ptr::ref_eq(sched, self)); + } + + match self.unwinder { + Some(ref mut unwinder) => { + // If there's an unwinder then set up the catch block + unwinder.try(f); + } + None => { + // Otherwise, just run the body + f() + } + } + self.destroy(); + } + + /// Must be called manually before finalization to clean up + /// thread-local resources. Some of the routines here expect + /// LocalServices to be available recursively so this must be + /// called unsafely, without removing LocalServices from + /// thread-local-storage. + fn destroy(&mut self) { + // This is just an assertion that `destroy` was called unsafely + // and this instance of LocalServices is still accessible. + do borrow_local_services |sched| { + assert!(ptr::ref_eq(sched, self)); + } + match self.storage { + LocalStorage(ptr, Some(ref dtor)) => { + (*dtor)(ptr) + } + _ => () + } + self.destroyed = true; + } +} + +impl Drop for LocalServices { + fn finalize(&self) { assert!(self.destroyed) } +} + +// Just a sanity check to make sure we are catching a Rust-thrown exception +static UNWIND_TOKEN: uintptr_t = 839147; + +impl Unwinder { + pub fn try(&mut self, f: &fn()) { + use sys::Closure; + + unsafe { + let closure: Closure = transmute(f); + let code = transmute(closure.code); + let env = transmute(closure.env); + + let token = rust_try(try_fn, code, env); + assert!(token == 0 || token == UNWIND_TOKEN); + } + + extern fn try_fn(code: *c_void, env: *c_void) { + unsafe { + let closure: Closure = Closure { + code: transmute(code), + env: transmute(env), + }; + let closure: &fn() = transmute(closure); + closure(); + } + } + + extern { + #[rust_stack] + fn rust_try(f: *u8, code: *c_void, data: *c_void) -> uintptr_t; + } + } + + pub fn begin_unwind(&mut self) -> ! { + self.unwinding = true; + unsafe { + rust_begin_unwind(UNWIND_TOKEN); + return transmute(()); + } + extern { + fn rust_begin_unwind(token: uintptr_t); + } + } +} + +/// Borrow a pointer to the installed local services. +/// Fails (likely aborting the process) if local services are not available. +pub fn borrow_local_services(f: &fn(&mut LocalServices)) { + do local_sched::borrow |sched| { + match sched.current_task { + Some(~ref mut task) => { + f(&mut task.local_services) + } + None => { + fail!(~"no local services for schedulers yet") + } + } + } +} + +pub unsafe fn unsafe_borrow_local_services() -> &mut LocalServices { + use cast::transmute_mut_region; + + match local_sched::unsafe_borrow().current_task { + Some(~ref mut task) => { + transmute_mut_region(&mut task.local_services) + } + None => { + fail!(~"no local services for schedulers yet") + } + } +} + +#[cfg(test)] +mod test { + use rt::test::*; + + #[test] + fn local_heap() { + do run_in_newsched_task() { + let a = @5; + let b = a; + assert!(*a == 5); + assert!(*b == 5); + } + } + + #[test] + fn tls() { + use task::local_data::*; + do run_in_newsched_task() { + unsafe { + fn key(_x: @~str) { } + local_data_set(key, @~"data"); + assert!(*local_data_get(key).get() == ~"data"); + fn key2(_x: @~str) { } + local_data_set(key2, @~"data"); + assert!(*local_data_get(key2).get() == ~"data"); + } + } + } + + #[test] + fn unwind() { + do run_in_newsched_task() { + let result = spawntask_try(||()); + assert!(result.is_ok()); + let result = spawntask_try(|| fail!()); + assert!(result.is_err()); + } + } +} \ No newline at end of file diff --git a/src/libcore/rt/mod.rs b/src/libcore/rt/mod.rs index e77ec82637e..a072fccd33d 100644 --- a/src/libcore/rt/mod.rs +++ b/src/libcore/rt/mod.rs @@ -8,30 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/*! The Rust runtime, including the scheduler and I/O interface */ + #[doc(hidden)]; use libc::c_char; -// Some basic logging -macro_rules! rtdebug_ ( - ($( $arg:expr),+) => ( { - dumb_println(fmt!( $($arg),+ )); - - fn dumb_println(s: &str) { - use io::WriterUtil; - let dbg = ::libc::STDERR_FILENO as ::io::fd_t; - dbg.write_str(s); - dbg.write_str("\n"); - } - - } ) -) - -// An alternate version with no output, for turning off logging -macro_rules! rtdebug ( - ($( $arg:expr),+) => ( $(let _ = $arg)*; ) -) - #[path = "sched/mod.rs"] mod sched; mod rtio; @@ -48,6 +30,12 @@ mod stack; mod context; mod thread; pub mod env; +pub mod local_services; +mod local_heap; + +/// Tools for testing the runtime +#[cfg(test)] +pub mod test; pub fn start(main: *u8, _argc: int, _argv: **c_char, _crate_map: *u8) -> int { use self::sched::{Scheduler, Task}; @@ -72,7 +60,7 @@ pub fn start(main: *u8, _argc: int, _argv: **c_char, _crate_map: *u8) -> int { /// Different runtime services are available depending on context. #[deriving(Eq)] pub enum RuntimeContext { - // Only default services, e.g. exchange heap + // Only the exchange heap is available GlobalContext, // The scheduler may be accessed SchedulerContext, @@ -139,24 +127,3 @@ fn test_context() { sched.run(); } } - -// For setting up tests of the new scheduler -#[cfg(test)] -pub fn run_in_newsched_task(f: ~fn()) { - use cell::Cell; - use unstable::run_in_bare_thread; - use self::sched::Task; - use self::uvio::UvEventLoop; - - let f = Cell(Cell(f)); - - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); - let f = f.take(); - let task = ~do Task::new(&mut sched.stack_pool) { - (f.take())(); - }; - sched.task_queue.push_back(task); - sched.run(); - } -} diff --git a/src/libcore/rt/sched/local_sched.rs b/src/libcore/rt/sched/local_sched.rs index 2d1e06163be..a7e02f30e01 100644 --- a/src/libcore/rt/sched/local_sched.rs +++ b/src/libcore/rt/sched/local_sched.rs @@ -143,4 +143,3 @@ fn borrow_smoke_test() { } let _scheduler = take(); } - diff --git a/src/libcore/rt/sched/mod.rs b/src/libcore/rt/sched/mod.rs index 333146394ee..663fe3e62d0 100644 --- a/src/libcore/rt/sched/mod.rs +++ b/src/libcore/rt/sched/mod.rs @@ -16,6 +16,7 @@ use super::work_queue::WorkQueue; use super::stack::{StackPool, StackSegment}; use super::rtio::{EventLoop, EventLoopObject}; use super::context::Context; +use super::local_services::LocalServices; use cell::Cell; #[cfg(test)] use super::uvio::UvEventLoop; @@ -38,7 +39,7 @@ pub struct Scheduler { /// Always valid when a task is executing, otherwise not priv saved_context: Context, /// The currently executing task - priv current_task: Option<~Task>, + current_task: Option<~Task>, /// An action performed after a context switch on behalf of the /// code running before the context switch priv cleanup_job: Option<CleanupJob> @@ -147,7 +148,7 @@ pub impl Scheduler { } } - // Control never reaches here + abort!("control reached end of task"); } fn schedule_new_task(~self, task: ~Task) { @@ -324,10 +325,18 @@ pub struct Task { /// These are always valid when the task is not running, unless /// the task is dead priv saved_context: Context, + /// The heap, GC, unwinding, local storage, logging + local_services: LocalServices } pub impl Task { fn new(stack_pool: &mut StackPool, start: ~fn()) -> Task { + Task::with_local(stack_pool, LocalServices::new(), start) + } + + fn with_local(stack_pool: &mut StackPool, + local_services: LocalServices, + start: ~fn()) -> Task { let start = Task::build_start_wrapper(start); let mut stack = stack_pool.take_segment(TASK_MIN_STACK_SIZE); // NB: Context holds a pointer to that ~fn @@ -335,6 +344,7 @@ pub impl Task { return Task { current_stack_segment: stack, saved_context: initial_context, + local_services: local_services }; } @@ -347,9 +357,12 @@ pub impl Task { unsafe { let sched = local_sched::unsafe_borrow(); sched.run_cleanup_job(); - } - start(); + let sched = local_sched::unsafe_borrow(); + let task = sched.current_task.get_mut_ref(); + // FIXME #6141: shouldn't neet to put `start()` in another closure + task.local_services.run(||start()); + } let sched = local_sched::take(); sched.terminate_current_task(); diff --git a/src/libcore/rt/test.rs b/src/libcore/rt/test.rs new file mode 100644 index 00000000000..63db7054088 --- /dev/null +++ b/src/libcore/rt/test.rs @@ -0,0 +1,120 @@ +// Copyright 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cell::Cell; +use result::{Result, Ok, Err}; +use super::io::net::ip::{IpAddr, Ipv4}; +use rt::local_services::LocalServices; + +/// Creates a new scheduler in a new thread and runs a task in it, +/// then waits for the scheduler to exit. Failure of the task +/// will abort the process. +pub fn run_in_newsched_task(f: ~fn()) { + use unstable::run_in_bare_thread; + use super::sched::Task; + use super::uvio::UvEventLoop; + + let f = Cell(f); + + do run_in_bare_thread { + let mut sched = ~UvEventLoop::new_scheduler(); + let task = ~Task::with_local(&mut sched.stack_pool, + LocalServices::without_unwinding(), + f.take()); + sched.task_queue.push_back(task); + sched.run(); + } +} + +/// Test tasks will abort on failure instead of unwinding +pub fn spawntask(f: ~fn()) { + use super::sched::*; + + let mut sched = local_sched::take(); + let task = ~Task::with_local(&mut sched.stack_pool, + LocalServices::without_unwinding(), + f); + do sched.switch_running_tasks_and_then(task) |task| { + let task = Cell(task); + let sched = local_sched::take(); + sched.schedule_new_task(task.take()); + } +} + +/// Create a new task and run it right now. Aborts on failure +pub fn spawntask_immediately(f: ~fn()) { + use super::sched::*; + + let mut sched = local_sched::take(); + let task = ~Task::with_local(&mut sched.stack_pool, + LocalServices::without_unwinding(), + f); + do sched.switch_running_tasks_and_then(task) |task| { + let task = Cell(task); + do local_sched::borrow |sched| { + sched.task_queue.push_front(task.take()); + } + } +} + +/// Spawn a task and wait for it to finish, returning whether it completed successfully or failed +pub fn spawntask_try(f: ~fn()) -> Result<(), ()> { + use cell::Cell; + use super::sched::*; + use task; + use unstable::finally::Finally; + + // Our status variables will be filled in from the scheduler context + let mut failed = false; + let failed_ptr: *mut bool = &mut failed; + + // Switch to the scheduler + let f = Cell(Cell(f)); + let mut sched = local_sched::take(); + do sched.deschedule_running_task_and_then() |old_task| { + let old_task = Cell(old_task); + let f = f.take(); + let mut sched = local_sched::take(); + let new_task = ~do Task::new(&mut sched.stack_pool) { + do (|| { + (f.take())() + }).finally { + // Check for failure then resume the parent task + unsafe { *failed_ptr = task::failing(); } + let sched = local_sched::take(); + do sched.switch_running_tasks_and_then(old_task.take()) |new_task| { + let new_task = Cell(new_task); + do local_sched::borrow |sched| { + sched.task_queue.push_front(new_task.take()); + } + } + } + }; + + sched.resume_task_immediately(new_task); + } + + if !failed { Ok(()) } else { Err(()) } +} + +/// Get a port number, starting at 9600, for use in tests +pub fn next_test_port() -> u16 { + unsafe { + return rust_dbg_next_port() as u16; + } + extern { + fn rust_dbg_next_port() -> ::libc::uintptr_t; + } +} + +/// Get a unique localhost:port pair starting at 9600 +pub fn next_test_ip4() -> IpAddr { + Ipv4(127, 0, 0, 1, next_test_port()) +} diff --git a/src/libcore/rt/uv/mod.rs b/src/libcore/rt/uv/mod.rs index cb7925abdcd..013a28abf28 100644 --- a/src/libcore/rt/uv/mod.rs +++ b/src/libcore/rt/uv/mod.rs @@ -301,7 +301,8 @@ struct WatcherData { write_cb: Option<ConnectionCallback>, connect_cb: Option<ConnectionCallback>, close_cb: Option<NullCallback>, - alloc_cb: Option<AllocCallback> + alloc_cb: Option<AllocCallback>, + buf: Option<Buf> } pub fn install_watcher_data<H, W: Watcher + NativeHandle<*H>>(watcher: &mut W) { @@ -311,7 +312,8 @@ pub fn install_watcher_data<H, W: Watcher + NativeHandle<*H>>(watcher: &mut W) { write_cb: None, connect_cb: None, close_cb: None, - alloc_cb: None + alloc_cb: None, + buf: None }; let data = transmute::<~WatcherData, *c_void>(data); uvll::set_data_for_uv_handle(watcher.native_handle(), data); diff --git a/src/libcore/rt/uv/net.rs b/src/libcore/rt/uv/net.rs index bcfe8b2cfdf..04b9008b067 100644 --- a/src/libcore/rt/uv/net.rs +++ b/src/libcore/rt/uv/net.rs @@ -19,12 +19,10 @@ use super::{Loop, Watcher, Request, UvError, Buf, Callback, NativeHandle, NullCa vec_to_uv_buf, vec_from_uv_buf}; use super::super::io::net::ip::{IpAddr, Ipv4, Ipv6}; -#[cfg(test)] -use unstable::run_in_bare_thread; -#[cfg(test)] -use super::super::thread::Thread; -#[cfg(test)] -use cell::Cell; +#[cfg(test)] use cell::Cell; +#[cfg(test)] use unstable::run_in_bare_thread; +#[cfg(test)] use super::super::thread::Thread; +#[cfg(test)] use super::super::test::*; fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in)) { match addr { @@ -109,21 +107,25 @@ pub impl StreamWatcher { let req = WriteRequest::new(); let buf = vec_to_uv_buf(msg); - // XXX: Allocation - let bufs = ~[buf]; + assert!(data.buf.is_none()); + data.buf = Some(buf); + let bufs = [buf]; unsafe { assert!(0 == uvll::write(req.native_handle(), self.native_handle(), - &bufs, write_cb)); + bufs, write_cb)); } - // XXX: Freeing immediately after write. Is this ok? - let _v = vec_from_uv_buf(buf); extern fn write_cb(req: *uvll::uv_write_t, status: c_int) { let write_request: WriteRequest = NativeHandle::from_native_handle(req); let mut stream_watcher = write_request.stream(); write_request.delete(); - let cb = get_watcher_data(&mut stream_watcher).write_cb.swap_unwrap(); + let cb = { + let data = get_watcher_data(&mut stream_watcher); + let _vec = vec_from_uv_buf(data.buf.swap_unwrap()); + let cb = data.write_cb.swap_unwrap(); + cb + }; let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status); cb(stream_watcher, status); } @@ -361,7 +363,7 @@ fn connect_close() { let mut loop_ = Loop::new(); let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; // Connect to a port where nobody is listening - let addr = Ipv4(127, 0, 0, 1, 2923); + let addr = next_test_ip4(); do tcp_watcher.connect(addr) |stream_watcher, status| { rtdebug!("tcp_watcher.connect!"); assert!(status.is_some()); @@ -374,46 +376,12 @@ fn connect_close() { } #[test] -#[ignore(reason = "need a server to connect to")] -fn connect_read() { - do run_in_bare_thread() { - let mut loop_ = Loop::new(); - let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; - let addr = Ipv4(127, 0, 0, 1, 2924); - do tcp_watcher.connect(addr) |stream_watcher, status| { - let mut stream_watcher = stream_watcher; - rtdebug!("tcp_watcher.connect!"); - assert!(status.is_none()); - let alloc: AllocCallback = |size| { - vec_to_uv_buf(vec::from_elem(size, 0)) - }; - do stream_watcher.read_start(alloc) - |stream_watcher, _nread, buf, status| { - - let buf = vec_from_uv_buf(buf); - rtdebug!("read cb!"); - if status.is_none() { - let _bytes = buf.unwrap(); - rtdebug!("%s", bytes.slice(0, nread as uint).to_str()); - } else { - rtdebug!("status after read: %s", status.get().to_str()); - rtdebug!("closing"); - stream_watcher.close(||()); - } - } - } - loop_.run(); - loop_.close(); - } -} - -#[test] fn listen() { do run_in_bare_thread() { static MAX: int = 10; let mut loop_ = Loop::new(); let mut server_tcp_watcher = { TcpWatcher::new(&mut loop_) }; - let addr = Ipv4(127, 0, 0, 1, 2925); + let addr = next_test_ip4(); server_tcp_watcher.bind(addr); let loop_ = loop_; rtdebug!("listening"); diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index fba91dd7d8a..ab8aea2b63c 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -19,10 +19,9 @@ use cell::{Cell, empty_cell}; use cast::transmute; use super::sched::{Scheduler, local_sched}; -#[cfg(test)] use super::io::net::ip::Ipv4; -#[cfg(test)] use super::sched::Task; -#[cfg(test)] use unstable::run_in_bare_thread; #[cfg(test)] use uint; +#[cfg(test)] use unstable::run_in_bare_thread; +#[cfg(test)] use super::test::*; pub struct UvEventLoop { uvio: UvIoFactory @@ -319,38 +318,22 @@ impl Stream for UvStream { } #[test] -#[ignore(reason = "ffi struct issues")] fn test_simple_io_no_connect() { - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); - let task = ~do Task::new(&mut sched.stack_pool) { - let io = unsafe { local_sched::unsafe_borrow_io() }; - let addr = Ipv4(127, 0, 0, 1, 2926); - let maybe_chan = io.connect(addr); - assert!(maybe_chan.is_none()); - }; - sched.task_queue.push_back(task); - sched.run(); + do run_in_newsched_task { + let io = unsafe { local_sched::unsafe_borrow_io() }; + let addr = next_test_ip4(); + let maybe_chan = io.connect(addr); + assert!(maybe_chan.is_none()); } } #[test] -#[ignore(reason = "ffi struct issues")] fn test_simple_tcp_server_and_client() { - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); - let addr = Ipv4(127, 0, 0, 1, 2929); - - let client_task = ~do Task::new(&mut sched.stack_pool) { - unsafe { - let io = local_sched::unsafe_borrow_io(); - let mut stream = io.connect(addr).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.close(); - } - }; + do run_in_newsched_task { + let addr = next_test_ip4(); - let server_task = ~do Task::new(&mut sched.stack_pool) { + // Start the server first so it's listening when we connect + do spawntask_immediately { unsafe { let io = local_sched::unsafe_borrow_io(); let mut listener = io.bind(addr).unwrap(); @@ -365,32 +348,25 @@ fn test_simple_tcp_server_and_client() { stream.close(); listener.close(); } - }; + } - // Start the server first so it listens before the client connects - sched.task_queue.push_back(server_task); - sched.task_queue.push_back(client_task); - sched.run(); + do spawntask_immediately { + unsafe { + let io = local_sched::unsafe_borrow_io(); + let mut stream = io.connect(addr).unwrap(); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.close(); + } + } } } #[test] #[ignore(reason = "busted")] fn test_read_and_block() { - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); - let addr = Ipv4(127, 0, 0, 1, 2930); + do run_in_newsched_task { + let addr = next_test_ip4(); - let client_task = ~do Task::new(&mut sched.stack_pool) { - let io = unsafe { local_sched::unsafe_borrow_io() }; - let mut stream = io.connect(addr).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.close(); - }; - - let server_task = ~do Task::new(&mut sched.stack_pool) { + do spawntask_immediately { let io = unsafe { local_sched::unsafe_borrow_io() }; let mut listener = io.bind(addr).unwrap(); let mut stream = listener.listen().unwrap(); @@ -426,36 +402,58 @@ fn test_read_and_block() { stream.close(); listener.close(); - }; + } + + do spawntask_immediately { + let io = unsafe { local_sched::unsafe_borrow_io() }; + let mut stream = io.connect(addr).unwrap(); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.close(); + } - // Start the server first so it listens before the client connects - sched.task_queue.push_back(server_task); - sched.task_queue.push_back(client_task); - sched.run(); } } -#[test] #[ignore(reason = "needs server")] +#[test] fn test_read_read_read() { - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); - let addr = Ipv4(127, 0, 0, 1, 2931); + do run_in_newsched_task { + let addr = next_test_ip4(); + static MAX: uint = 500000; - let client_task = ~do Task::new(&mut sched.stack_pool) { + do spawntask_immediately { + unsafe { + let io = local_sched::unsafe_borrow_io(); + let mut listener = io.bind(addr).unwrap(); + let mut stream = listener.listen().unwrap(); + let mut buf = [1, .. 2048]; + let mut total_bytes_written = 0; + while total_bytes_written < MAX { + stream.write(buf); + total_bytes_written += buf.len(); + } + stream.close(); + listener.close(); + } + } + + do spawntask_immediately { let io = unsafe { local_sched::unsafe_borrow_io() }; let mut stream = io.connect(addr).unwrap(); let mut buf = [0, .. 2048]; let mut total_bytes_read = 0; - while total_bytes_read < 500000000 { + while total_bytes_read < MAX { let nread = stream.read(buf).unwrap(); rtdebug!("read %u bytes", nread as uint); total_bytes_read += nread; + for uint::range(0, nread) |i| { + assert!(buf[i] == 1); + } } - rtdebug_!("read %u bytes total", total_bytes_read as uint); + rtdebug!("read %u bytes total", total_bytes_read as uint); stream.close(); - }; - - sched.task_queue.push_back(client_task); - sched.run(); + } } } diff --git a/src/libcore/rt/uvll.rs b/src/libcore/rt/uvll.rs index c9a696fcd15..3eb7f8006b9 100644 --- a/src/libcore/rt/uvll.rs +++ b/src/libcore/rt/uvll.rs @@ -219,9 +219,9 @@ pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int { return rust_uv_accept(server as *c_void, client as *c_void); } -pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: *~[uv_buf_t], cb: *u8) -> c_int { - let buf_ptr = vec::raw::to_ptr(*buf_in); - let buf_cnt = vec::len(*buf_in) as i32; +pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int { + let buf_ptr = vec::raw::to_ptr(buf_in); + let buf_cnt = vec::len(buf_in) as i32; return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb); } pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8, on_read: *u8) -> c_int { diff --git a/src/libcore/run.rs b/src/libcore/run.rs index 37401788ca2..7e73b3a3f80 100644 --- a/src/libcore/run.rs +++ b/src/libcore/run.rs @@ -22,31 +22,6 @@ use str; use task; use vec; -pub mod rustrt { - use libc::{c_int, c_void}; - use libc; - use run; - - #[abi = "cdecl"] - pub extern { - unsafe fn rust_run_program(argv: **libc::c_char, - envp: *c_void, - dir: *libc::c_char, - in_fd: c_int, - out_fd: c_int, - err_fd: c_int) -> run::RunProgramResult; - unsafe fn rust_process_wait(pid: c_int) -> c_int; - } -} - -pub struct RunProgramResult { - // the process id of the program, or -1 if in case of errors - pid: pid_t, - // a handle to the process - on unix this will always be NULL, but on windows it will be a - // HANDLE to the process, which will prevent the pid being re-used until the handle is closed. - handle: *(), -} - /// A value representing a child process pub struct Program { priv pid: pid_t, @@ -191,21 +166,262 @@ pub fn spawn_process(prog: &str, args: &[~str], return res.pid; } +struct RunProgramResult { + // the process id of the program (this should never be negative) + pid: pid_t, + // a handle to the process - on unix this will always be NULL, but on windows it will be a + // HANDLE to the process, which will prevent the pid being re-used until the handle is closed. + handle: *(), +} + +#[cfg(windows)] fn spawn_process_internal(prog: &str, args: &[~str], env: &Option<~[(~str,~str)]>, dir: &Option<~str>, in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult { + + use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO}; + use libc::consts::os::extra::{ + TRUE, FALSE, + STARTF_USESTDHANDLES, + INVALID_HANDLE_VALUE, + DUPLICATE_SAME_ACCESS + }; + use libc::funcs::extra::kernel32::{ + GetCurrentProcess, + DuplicateHandle, + CloseHandle, + CreateProcessA + }; + use libc::funcs::extra::msvcrt::get_osfhandle; + unsafe { - do with_argv(prog, args) |argv| { - do with_envp(env) |envp| { - do with_dirp(dir) |dirp| { - rustrt::rust_run_program(argv, envp, dirp, in_fd, out_fd, err_fd) + + let mut si = zeroed_startupinfo(); + si.cb = sys::size_of::<STARTUPINFO>() as DWORD; + si.dwFlags = STARTF_USESTDHANDLES; + + let cur_proc = GetCurrentProcess(); + + let orig_std_in = get_osfhandle(if in_fd > 0 { in_fd } else { 0 }) as HANDLE; + if orig_std_in == INVALID_HANDLE_VALUE as HANDLE { + fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error())); + } + if DuplicateHandle(cur_proc, orig_std_in, cur_proc, &mut si.hStdInput, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { + fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error())); + } + + let orig_std_out = get_osfhandle(if out_fd > 0 { out_fd } else { 1 }) as HANDLE; + if orig_std_out == INVALID_HANDLE_VALUE as HANDLE { + fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error())); + } + if DuplicateHandle(cur_proc, orig_std_out, cur_proc, &mut si.hStdOutput, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { + fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error())); + } + + let orig_std_err = get_osfhandle(if err_fd > 0 { err_fd } else { 2 }) as HANDLE; + if orig_std_err as HANDLE == INVALID_HANDLE_VALUE as HANDLE { + fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error())); + } + if DuplicateHandle(cur_proc, orig_std_err, cur_proc, &mut si.hStdError, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { + fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error())); + } + + let cmd = make_command_line(prog, args); + let mut pi = zeroed_process_information(); + let mut create_err = None; + + do with_envp(env) |envp| { + do with_dirp(dir) |dirp| { + do str::as_c_str(cmd) |cmdp| { + let created = CreateProcessA(ptr::null(), cast::transmute(cmdp), + ptr::mut_null(), ptr::mut_null(), TRUE, + 0, envp, dirp, &mut si, &mut pi); + if created == FALSE { + create_err = Some(os::last_os_error()); + } } } } + + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + + for create_err.each |msg| { + fail!(fmt!("failure in CreateProcess: %s", *msg)); + } + + // We close the thread handle because we don't care about keeping the thread id valid, + // and we aren't keeping the thread handle around to be able to close it later. We don't + // close the process handle however because we want the process id to stay valid at least + // until the calling code closes the process handle. + CloseHandle(pi.hThread); + + RunProgramResult { + pid: pi.dwProcessId as pid_t, + handle: pi.hProcess as *() + } + } +} + +#[cfg(windows)] +fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO { + libc::types::os::arch::extra::STARTUPINFO { + cb: 0, + lpReserved: ptr::mut_null(), + lpDesktop: ptr::mut_null(), + lpTitle: ptr::mut_null(), + dwX: 0, + dwY: 0, + dwXSize: 0, + dwYSize: 0, + dwXCountChars: 0, + dwYCountCharts: 0, + dwFillAttribute: 0, + dwFlags: 0, + wShowWindow: 0, + cbReserved2: 0, + lpReserved2: ptr::mut_null(), + hStdInput: ptr::mut_null(), + hStdOutput: ptr::mut_null(), + hStdError: ptr::mut_null() } } +#[cfg(windows)] +fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION { + libc::types::os::arch::extra::PROCESS_INFORMATION { + hProcess: ptr::mut_null(), + hThread: ptr::mut_null(), + dwProcessId: 0, + dwThreadId: 0 + } +} + +// FIXME: this is only pub so it can be tested (see issue #4536) +#[cfg(windows)] +pub fn make_command_line(prog: &str, args: &[~str]) -> ~str { + + let mut cmd = ~""; + append_arg(&mut cmd, prog); + for args.each |arg| { + cmd.push_char(' '); + append_arg(&mut cmd, *arg); + } + return cmd; + + fn append_arg(cmd: &mut ~str, arg: &str) { + let quote = arg.any(|c| c == ' ' || c == '\t'); + if quote { + cmd.push_char('"'); + } + for uint::range(0, arg.len()) |i| { + append_char_at(cmd, arg, i); + } + if quote { + cmd.push_char('"'); + } + } + + fn append_char_at(cmd: &mut ~str, arg: &str, i: uint) { + match arg[i] as char { + '"' => { + // Escape quotes. + cmd.push_str("\\\""); + } + '\\' => { + if backslash_run_ends_in_quote(arg, i) { + // Double all backslashes that are in runs before quotes. + cmd.push_str("\\\\"); + } else { + // Pass other backslashes through unescaped. + cmd.push_char('\\'); + } + } + c => { + cmd.push_char(c); + } + } + } + + fn backslash_run_ends_in_quote(s: &str, mut i: uint) -> bool { + while i < s.len() && s[i] as char == '\\' { + i += 1; + } + return i < s.len() && s[i] as char == '"'; + } +} + +#[cfg(unix)] +fn spawn_process_internal(prog: &str, args: &[~str], + env: &Option<~[(~str,~str)]>, + dir: &Option<~str>, + in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult { + + use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; + use libc::funcs::bsd44::getdtablesize; + + mod rustrt { + use libc::c_void; + + #[abi = "cdecl"] + pub extern { + unsafe fn rust_unset_sigprocmask(); + unsafe fn rust_set_environ(envp: *c_void); + } + } + + unsafe { + + let pid = fork(); + if pid < 0 { + fail!(fmt!("failure in fork: %s", os::last_os_error())); + } else if pid > 0 { + return RunProgramResult {pid: pid, handle: ptr::null()}; + } + + rustrt::rust_unset_sigprocmask(); + + if in_fd > 0 && dup2(in_fd, 0) == -1 { + fail!(fmt!("failure in dup2(in_fd, 0): %s", os::last_os_error())); + } + if out_fd > 0 && dup2(out_fd, 1) == -1 { + fail!(fmt!("failure in dup2(out_fd, 1): %s", os::last_os_error())); + } + if err_fd > 0 && dup2(err_fd, 2) == -1 { + fail!(fmt!("failure in dup3(err_fd, 2): %s", os::last_os_error())); + } + // close all other fds + for int::range_rev(getdtablesize() as int - 1, 2) |fd| { + close(fd as c_int); + } + + for dir.each |dir| { + do str::as_c_str(*dir) |dirp| { + if chdir(dirp) == -1 { + fail!(fmt!("failure in chdir: %s", os::last_os_error())); + } + } + } + + do with_envp(env) |envp| { + if !envp.is_null() { + rustrt::rust_set_environ(envp); + } + do with_argv(prog, args) |argv| { + execvp(*argv, argv); + // execvp only returns if an error occurred + fail!(fmt!("failure in execvp: %s", os::last_os_error())); + } + } + } +} + +#[cfg(unix)] fn with_argv<T>(prog: &str, args: &[~str], cb: &fn(**libc::c_char) -> T) -> T { let mut argptrs = str::as_c_str(prog, |b| ~[b]); @@ -246,7 +462,7 @@ fn with_envp<T>(env: &Option<~[(~str,~str)]>, #[cfg(windows)] fn with_envp<T>(env: &Option<~[(~str,~str)]>, - cb: &fn(*c_void) -> T) -> T { + cb: &fn(*mut c_void) -> T) -> T { // On win32 we pass an "environment block" which is not a char**, but // rather a concatenation of null-terminated k=v\0 sequences, with a final // \0 to terminate. @@ -264,11 +480,12 @@ fn with_envp<T>(env: &Option<~[(~str,~str)]>, blk += ~[0_u8]; vec::as_imm_buf(blk, |p, _len| cb(::cast::transmute(p))) } - _ => cb(ptr::null()) + _ => cb(ptr::mut_null()) } } } +#[cfg(windows)] fn with_dirp<T>(d: &Option<~str>, cb: &fn(*libc::c_char) -> T) -> T { match *d { @@ -312,8 +529,6 @@ priv fn free_handle(_handle: *()) { pub fn run_program(prog: &str, args: &[~str]) -> int { let res = spawn_process_internal(prog, args, &None, &None, 0i32, 0i32, 0i32); - if res.pid == -1 as pid_t { fail!(); } - let code = waitpid(res.pid); free_handle(res.handle); return code; @@ -345,7 +560,6 @@ pub fn start_program(prog: &str, args: &[~str]) -> Program { pipe_err.out); unsafe { - if res.pid == -1 as pid_t { fail!(); } libc::close(pipe_input.in); libc::close(pipe_output.out); libc::close(pipe_err.out); @@ -398,13 +612,6 @@ pub fn program_output(prog: &str, args: &[~str]) -> ProgramOutput { os::close(pipe_in.in); os::close(pipe_out.out); os::close(pipe_err.out); - if res.pid == -1i32 { - os::close(pipe_in.out); - os::close(pipe_out.in); - os::close(pipe_err.in); - fail!(); - } - os::close(pipe_in.out); // Spawn two entire schedulers to read both stdout and sterr @@ -485,11 +692,46 @@ pub fn waitpid(pid: pid_t) -> int { #[cfg(windows)] fn waitpid_os(pid: pid_t) -> int { - let status = unsafe { rustrt::rust_process_wait(pid) }; - if status < 0 { - fail!(fmt!("failure in rust_process_wait: %s", os::last_os_error())); + + use libc::types::os::arch::extra::DWORD; + use libc::consts::os::extra::{ + SYNCHRONIZE, + PROCESS_QUERY_INFORMATION, + FALSE, + STILL_ACTIVE, + INFINITE, + WAIT_FAILED + }; + use libc::funcs::extra::kernel32::{ + OpenProcess, + GetExitCodeProcess, + CloseHandle, + WaitForSingleObject + }; + + unsafe { + + let proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD); + if proc.is_null() { + fail!(fmt!("failure in OpenProcess: %s", os::last_os_error())); + } + + loop { + let mut status = 0; + if GetExitCodeProcess(proc, &mut status) == FALSE { + CloseHandle(proc); + fail!(fmt!("failure in GetExitCodeProcess: %s", os::last_os_error())); + } + if status != STILL_ACTIVE { + CloseHandle(proc); + return status as int; + } + if WaitForSingleObject(proc, INFINITE) == WAIT_FAILED { + CloseHandle(proc); + fail!(fmt!("failure in WaitForSingleObject: %s", os::last_os_error())); + } + } } - return status as int; } #[cfg(unix)] @@ -539,10 +781,30 @@ mod tests { use libc; use option::None; use os; - use path::Path; use run::{readclose, writeclose}; use run; + #[test] + #[cfg(windows)] + fn test_make_command_line() { + assert_eq!( + run::make_command_line("prog", [~"aaa", ~"bbb", ~"ccc"]), + ~"prog aaa bbb ccc" + ); + assert_eq!( + run::make_command_line("C:\\Program Files\\blah\\blah.exe", [~"aaa"]), + ~"\"C:\\Program Files\\blah\\blah.exe\" aaa" + ); + assert_eq!( + run::make_command_line("C:\\Program Files\\test", [~"aa\"bb"]), + ~"\"C:\\Program Files\\test\" aa\\\"bb" + ); + assert_eq!( + run::make_command_line("echo", [~"a b c"]), + ~"echo \"a b c\"" + ); + } + // Regression test for memory leaks #[test] fn test_leaks() { @@ -607,43 +869,60 @@ mod tests { p.destroy(); // ...and nor should this (and nor should the destructor) } - #[cfg(unix)] // there is no way to sleep on windows from inside libcore... fn test_destroy_actually_kills(force: bool) { - let path = Path(fmt!("test/core-run-test-destroy-actually-kills-%?.tmp", force)); - os::remove_file(&path); + #[cfg(unix)] + static BLOCK_COMMAND: &'static str = "cat"; - let cmd = fmt!("sleep 5 && echo MurderDeathKill > %s", path.to_str()); - let mut p = run::start_program("sh", [~"-c", cmd]); + #[cfg(windows)] + static BLOCK_COMMAND: &'static str = "cmd"; - p.destroy(); // destroy the program before it has a chance to echo its message + #[cfg(unix)] + fn process_exists(pid: libc::pid_t) -> bool { + run::program_output("ps", [~"-p", pid.to_str()]).out.contains(pid.to_str()) + } - unsafe { - // wait to ensure the program is really destroyed and not just waiting itself - libc::sleep(10); + #[cfg(windows)] + fn process_exists(pid: libc::pid_t) -> bool { + + use libc::types::os::arch::extra::DWORD; + use libc::funcs::extra::kernel32::{CloseHandle, GetExitCodeProcess, OpenProcess}; + use libc::consts::os::extra::{FALSE, PROCESS_QUERY_INFORMATION, STILL_ACTIVE }; + + unsafe { + let proc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD); + if proc.is_null() { + return false; + } + // proc will be non-null if the process is alive, or if it died recently + let mut status = 0; + GetExitCodeProcess(proc, &mut status); + CloseHandle(proc); + return status == STILL_ACTIVE; + } } - // the program should not have had chance to echo its message - assert!(!path.exists()); + // this program will stay alive indefinitely trying to read from stdin + let mut p = run::start_program(BLOCK_COMMAND, []); + + assert!(process_exists(p.get_id())); + + if force { + p.force_destroy(); + } else { + p.destroy(); + } + + assert!(!process_exists(p.get_id())); } #[test] - #[cfg(unix)] fn test_unforced_destroy_actually_kills() { test_destroy_actually_kills(false); } #[test] - #[cfg(unix)] fn test_forced_destroy_actually_kills() { test_destroy_actually_kills(true); } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/stackwalk.rs b/src/libcore/stackwalk.rs index ebf36e4e09a..987d4064ab9 100644 --- a/src/libcore/stackwalk.rs +++ b/src/libcore/stackwalk.rs @@ -93,10 +93,6 @@ pub mod rustrt { pub mod rusti { #[abi = "rust-intrinsic"] pub extern "rust-intrinsic" { - #[cfg(stage0)] - pub fn frame_address(f: &once fn(x: *u8)); - #[cfg(not(stage0))] pub fn frame_address(+f: &once fn(x: *u8)); } } - diff --git a/src/libcore/str.rs b/src/libcore/str.rs index f4430ca669f..a41c99b266b 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -77,6 +77,7 @@ pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str { } /// Copy a slice into a new unique str +#[inline(always)] pub fn from_slice(s: &str) -> ~str { unsafe { raw::slice_bytes_owned(s, 0, len(s)) } } @@ -240,38 +241,132 @@ pub fn append(lhs: ~str, rhs: &str) -> ~str { /// Concatenate a vector of strings pub fn concat(v: &[~str]) -> ~str { - let mut s: ~str = ~""; - for vec::each(v) |ss| { - push_str(&mut s, *ss); + if v.is_empty() { return ~""; } + + let mut len = 0; + for v.each |ss| { + len += ss.len(); + } + let mut s = ~""; + + reserve(&mut s, len); + + unsafe { + do as_buf(s) |buf, _len| { + let mut buf = ::cast::transmute_mut_unsafe(buf); + for v.each |ss| { + do as_buf(*ss) |ssbuf, sslen| { + let sslen = sslen - 1; + ptr::copy_memory(buf, ssbuf, sslen); + buf = buf.offset(sslen); + } + } + } + raw::set_len(&mut s, len); } s } /// Concatenate a vector of strings, placing a given separator between each pub fn connect(v: &[~str], sep: &str) -> ~str { + if v.is_empty() { return ~""; } + + // concat is faster + if sep.is_empty() { return concat(v); } + + // this is wrong without the guarantee that v is non-empty + let mut len = sep.len() * (v.len() - 1); + for v.each |ss| { + len += ss.len(); + } let mut s = ~"", first = true; - for vec::each(v) |ss| { - if first { first = false; } else { push_str(&mut s, sep); } - push_str(&mut s, *ss); + + reserve(&mut s, len); + + unsafe { + do as_buf(s) |buf, _len| { + do as_buf(sep) |sepbuf, seplen| { + let seplen = seplen - 1; + let mut buf = ::cast::transmute_mut_unsafe(buf); + for v.each |ss| { + do as_buf(*ss) |ssbuf, sslen| { + let sslen = sslen - 1; + if first { + first = false; + } else { + ptr::copy_memory(buf, sepbuf, seplen); + buf = buf.offset(seplen); + } + ptr::copy_memory(buf, ssbuf, sslen); + buf = buf.offset(sslen); + } + } + } + } + raw::set_len(&mut s, len); } s } /// Concatenate a vector of strings, placing a given separator between each pub fn connect_slices(v: &[&str], sep: &str) -> ~str { + if v.is_empty() { return ~""; } + + // this is wrong without the guarantee that v is non-empty + let mut len = sep.len() * (v.len() - 1); + for v.each |ss| { + len += ss.len(); + } let mut s = ~"", first = true; - for vec::each(v) |ss| { - if first { first = false; } else { push_str(&mut s, sep); } - push_str(&mut s, *ss); + + reserve(&mut s, len); + + unsafe { + do as_buf(s) |buf, _len| { + do as_buf(sep) |sepbuf, seplen| { + let seplen = seplen - 1; + let mut buf = ::cast::transmute_mut_unsafe(buf); + for vec::each(v) |ss| { + do as_buf(*ss) |ssbuf, sslen| { + let sslen = sslen - 1; + if first { + first = false; + } else if seplen > 0 { + ptr::copy_memory(buf, sepbuf, seplen); + buf = buf.offset(seplen); + } + ptr::copy_memory(buf, ssbuf, sslen); + buf = buf.offset(sslen); + } + } + } + } + raw::set_len(&mut s, len); } s } /// Given a string, make a new string with repeated copies of it pub fn repeat(ss: &str, nn: uint) -> ~str { - let mut acc = ~""; - for nn.times { acc += ss; } - acc + do as_buf(ss) |buf, len| { + let mut ret = ~""; + // ignore the NULL terminator + let len = len - 1; + reserve(&mut ret, nn * len); + + unsafe { + do as_buf(ret) |rbuf, _len| { + let mut rbuf = ::cast::transmute_mut_unsafe(rbuf); + + for nn.times { + ptr::copy_memory(rbuf, buf, len); + rbuf = rbuf.offset(len); + } + } + raw::set_len(&mut ret, nn * len); + } + ret + } } /* @@ -820,6 +915,7 @@ Section: Comparing strings /// Bytewise slice equality #[cfg(notest)] #[lang="str_eq"] +#[inline] pub fn eq_slice(a: &str, b: &str) -> bool { do as_buf(a) |ap, alen| { do as_buf(b) |bp, blen| { @@ -836,6 +932,7 @@ pub fn eq_slice(a: &str, b: &str) -> bool { } #[cfg(test)] +#[inline] pub fn eq_slice(a: &str, b: &str) -> bool { do as_buf(a) |ap, alen| { do as_buf(b) |bp, blen| { @@ -854,15 +951,18 @@ pub fn eq_slice(a: &str, b: &str) -> bool { /// Bytewise string equality #[cfg(notest)] #[lang="uniq_str_eq"] +#[inline] pub fn eq(a: &~str, b: &~str) -> bool { eq_slice(*a, *b) } #[cfg(test)] +#[inline] pub fn eq(a: &~str, b: &~str) -> bool { eq_slice(*a, *b) } +#[inline] fn cmp(a: &str, b: &str) -> Ordering { let low = uint::min(a.len(), b.len()); @@ -879,20 +979,24 @@ fn cmp(a: &str, b: &str) -> Ordering { #[cfg(notest)] impl<'self> TotalOrd for &'self str { + #[inline] fn cmp(&self, other: & &'self str) -> Ordering { cmp(*self, *other) } } #[cfg(notest)] impl TotalOrd for ~str { + #[inline] fn cmp(&self, other: &~str) -> Ordering { cmp(*self, *other) } } #[cfg(notest)] impl TotalOrd for @str { + #[inline] fn cmp(&self, other: &@str) -> Ordering { cmp(*self, *other) } } /// Bytewise slice less than +#[inline] fn lt(a: &str, b: &str) -> bool { let (a_len, b_len) = (a.len(), b.len()); let end = uint::min(a_len, b_len); @@ -909,16 +1013,19 @@ fn lt(a: &str, b: &str) -> bool { } /// Bytewise less than or equal +#[inline] pub fn le(a: &str, b: &str) -> bool { !lt(b, a) } /// Bytewise greater than or equal +#[inline] fn ge(a: &str, b: &str) -> bool { !lt(a, b) } /// Bytewise greater than +#[inline] fn gt(a: &str, b: &str) -> bool { !le(a, b) } @@ -1595,6 +1702,7 @@ Section: String properties */ /// Returns true if the string has length 0 +#[inline(always)] pub fn is_empty(s: &str) -> bool { len(s) == 0u } /** @@ -1616,11 +1724,13 @@ fn is_alphanumeric(s: &str) -> bool { } /// Returns the string length/size in bytes not counting the null terminator +#[inline(always)] pub fn len(s: &str) -> uint { do as_buf(s) |_p, n| { n - 1u } } /// Returns the number of characters that a string holds +#[inline(always)] pub fn char_len(s: &str) -> uint { count_chars(s, 0u, len(s)) } /* @@ -1752,7 +1862,8 @@ pub fn count_chars(s: &str, start: uint, end: uint) -> uint { return len; } -/// Counts the number of bytes taken by the `n` in `s` starting from `start`. +/// Counts the number of bytes taken by the first `n` chars in `s` +/// starting from `start`. pub fn count_bytes<'b>(s: &'b str, start: uint, n: uint) -> uint { assert!(is_char_boundary(s, start)); let mut end = start, cnt = n; @@ -1988,6 +2099,7 @@ static tag_six_b: uint = 252u; * let i = str::as_bytes("Hello World") { |bytes| vec::len(bytes) }; * ~~~ */ +#[inline] pub fn as_bytes<T>(s: &const ~str, f: &fn(&~[u8]) -> T) -> T { unsafe { let v: *~[u8] = cast::transmute(copy s); @@ -2023,6 +2135,7 @@ pub fn as_bytes_slice<'a>(s: &'a str) -> &'a [u8] { * let s = str::as_c_str("PATH", { |path| libc::getenv(path) }); * ~~~ */ +#[inline] pub fn as_c_str<T>(s: &str, f: &fn(*libc::c_char) -> T) -> T { do as_buf(s) |buf, len| { // NB: len includes the trailing null. @@ -2099,6 +2212,7 @@ pub fn subslice_offset(outer: &str, inner: &str) -> uint { * * s - A string * * n - The number of bytes to reserve space for */ +#[inline(always)] pub fn reserve(s: &mut ~str, n: uint) { unsafe { let v: *mut ~[u8] = cast::transmute(s); @@ -2126,6 +2240,7 @@ pub fn reserve(s: &mut ~str, n: uint) { * * s - A string * * n - The number of bytes to reserve space for */ +#[inline(always)] pub fn reserve_at_least(s: &mut ~str, n: uint) { reserve(s, uint::next_power_of_two(n + 1u) - 1u) } @@ -2314,6 +2429,7 @@ pub mod raw { } /// Sets the length of the string and adds the null terminator + #[inline] pub unsafe fn set_len(v: &mut ~str, new_len: uint) { let v: **mut vec::raw::VecRepr = cast::transmute(v); let repr: *mut vec::raw::VecRepr = *v; @@ -2483,7 +2599,7 @@ impl<'self> StrSlice<'self> for &'self str { #[inline] fn is_alphanumeric(&self) -> bool { is_alphanumeric(*self) } /// Returns the size in bytes not counting the null terminator - #[inline] + #[inline(always)] fn len(&self) -> uint { len(*self) } /// Returns the number of characters that a string holds #[inline] @@ -2593,10 +2709,11 @@ pub trait OwnedStr { } impl OwnedStr for ~str { + #[inline] fn push_str(&mut self, v: &str) { push_str(self, v); } - + #[inline] fn push_char(&mut self, c: char) { push_char(self, c); } diff --git a/src/libcore/str/ascii.rs b/src/libcore/str/ascii.rs index 9180c995ca2..73f556518fa 100644 --- a/src/libcore/str/ascii.rs +++ b/src/libcore/str/ascii.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Operations on ASCII strings and characters. + use to_str::{ToStr,ToStrConsume}; use str; use cast; diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs index 8cad0a22886..4eca7ebbb37 100644 --- a/src/libcore/sys.rs +++ b/src/libcore/sys.rs @@ -10,6 +10,7 @@ //! Misc low level stuff +use option::{Some, None}; use cast; use cmp::{Eq, Ord}; use gc; @@ -199,36 +200,33 @@ impl FailWithCause for &'static str { } } -// NOTE: remove function after snapshot -#[cfg(stage0)] -pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! { - do str::as_buf(msg) |msg_buf, _msg_len| { - do str::as_buf(file) |file_buf, _file_len| { +// FIXME #4427: Temporary until rt::rt_fail_ goes away +pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { + use rt::{context, OldTaskContext}; + use rt::local_services::unsafe_borrow_local_services; + + match context() { + OldTaskContext => { unsafe { - let msg_buf = cast::transmute(msg_buf); - let file_buf = cast::transmute(file_buf); - begin_unwind_(msg_buf, file_buf, line as libc::size_t) + gc::cleanup_stack_for_failure(); + rustrt::rust_upcall_fail(msg, file, line); + cast::transmute(()) + } + } + _ => { + // XXX: Need to print the failure message + gc::cleanup_stack_for_failure(); + unsafe { + let local_services = unsafe_borrow_local_services(); + match local_services.unwinder { + Some(ref mut unwinder) => unwinder.begin_unwind(), + None => abort!("failure without unwinder. aborting process") + } } } } } -// FIXME #4427: Temporary until rt::rt_fail_ goes away -pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { - unsafe { - gc::cleanup_stack_for_failure(); - rustrt::rust_upcall_fail(msg, file, line); - cast::transmute(()) - } -} - -// NOTE: remove function after snapshot -#[cfg(stage0)] -pub fn fail_assert(msg: &str, file: &str, line: uint) -> ! { - let (msg, file) = (msg.to_owned(), file.to_owned()); - begin_unwind(~"assertion failed: " + msg, file, line) -} - #[cfg(test)] mod tests { use cast; @@ -343,11 +341,3 @@ mod tests { #[should_fail] fn fail_owned() { FailWithCause::fail_with(~"cause", file!(), line!()) } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/task/local_data.rs b/src/libcore/task/local_data.rs index 6050aca6dc1..dff5908c047 100644 --- a/src/libcore/task/local_data.rs +++ b/src/libcore/task/local_data.rs @@ -27,8 +27,7 @@ magic. */ use prelude::*; -use task::local_data_priv::{local_get, local_pop, local_modify, local_set}; -use task::rt; +use task::local_data_priv::{local_get, local_pop, local_modify, local_set, Handle}; /** * Indexes a task-local data slot. The function's code pointer is used for @@ -53,7 +52,7 @@ pub type LocalDataKey<'self,T> = &'self fn(v: @T); pub unsafe fn local_data_pop<T:Durable>( key: LocalDataKey<T>) -> Option<@T> { - local_pop(rt::rust_get_task(), key) + local_pop(Handle::new(), key) } /** * Retrieve a task-local data value. It will also be kept alive in the @@ -62,7 +61,7 @@ pub unsafe fn local_data_pop<T:Durable>( pub unsafe fn local_data_get<T:Durable>( key: LocalDataKey<T>) -> Option<@T> { - local_get(rt::rust_get_task(), key) + local_get(Handle::new(), key) } /** * Store a value in task-local data. If this key already has a value, @@ -71,7 +70,7 @@ pub unsafe fn local_data_get<T:Durable>( pub unsafe fn local_data_set<T:Durable>( key: LocalDataKey<T>, data: @T) { - local_set(rt::rust_get_task(), key, data) + local_set(Handle::new(), key, data) } /** * Modify a task-local data value. If the function returns 'None', the @@ -81,7 +80,7 @@ pub unsafe fn local_data_modify<T:Durable>( key: LocalDataKey<T>, modify_fn: &fn(Option<@T>) -> Option<@T>) { - local_modify(rt::rust_get_task(), key, modify_fn) + local_modify(Handle::new(), key, modify_fn) } #[test] diff --git a/src/libcore/task/local_data_priv.rs b/src/libcore/task/local_data_priv.rs index 67bc3adeb41..10a40887e57 100644 --- a/src/libcore/task/local_data_priv.rs +++ b/src/libcore/task/local_data_priv.rs @@ -18,6 +18,30 @@ use task::rt; use task::local_data::LocalDataKey; use super::rt::rust_task; +use rt::local_services::LocalStorage; + +pub enum Handle { + OldHandle(*rust_task), + NewHandle(*mut LocalStorage) +} + +impl Handle { + pub fn new() -> Handle { + use rt::{context, OldTaskContext}; + use rt::local_services::unsafe_borrow_local_services; + unsafe { + match context() { + OldTaskContext => { + OldHandle(rt::rust_get_task()) + } + _ => { + let local_services = unsafe_borrow_local_services(); + NewHandle(&mut local_services.storage) + } + } + } + } +} pub trait LocalData { } impl<T:Durable> LocalData for @T { } @@ -25,8 +49,8 @@ impl<T:Durable> LocalData for @T { } impl Eq for @LocalData { fn eq(&self, other: &@LocalData) -> bool { unsafe { - let ptr_a: (uint, uint) = cast::transmute(*self); - let ptr_b: (uint, uint) = cast::transmute(*other); + let ptr_a: &(uint, uint) = cast::transmute(self); + let ptr_b: &(uint, uint) = cast::transmute(other); return ptr_a == ptr_b; } } @@ -39,7 +63,7 @@ type TaskLocalElement = (*libc::c_void, *libc::c_void, @LocalData); // Has to be a pointer at outermost layer; the foreign call returns void *. type TaskLocalMap = @mut ~[Option<TaskLocalElement>]; -extern fn cleanup_task_local_map(map_ptr: *libc::c_void) { +fn cleanup_task_local_map(map_ptr: *libc::c_void) { unsafe { assert!(!map_ptr.is_null()); // Get and keep the single reference that was created at the @@ -50,8 +74,19 @@ extern fn cleanup_task_local_map(map_ptr: *libc::c_void) { } // Gets the map from the runtime. Lazily initialises if not done so already. +unsafe fn get_local_map(handle: Handle) -> TaskLocalMap { + match handle { + OldHandle(task) => get_task_local_map(task), + NewHandle(local_storage) => get_newsched_local_map(local_storage) + } +} + unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap { + extern fn cleanup_task_local_map_extern_cb(map_ptr: *libc::c_void) { + cleanup_task_local_map(map_ptr); + } + // Relies on the runtime initialising the pointer to null. // Note: The map's box lives in TLS invisibly referenced once. Each time // we retrieve it for get/set, we make another reference, which get/set @@ -60,7 +95,7 @@ unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap { if map_ptr.is_null() { let map: TaskLocalMap = @mut ~[]; rt::rust_set_task_local_data(task, cast::transmute(map)); - rt::rust_task_local_data_atexit(task, cleanup_task_local_map); + rt::rust_task_local_data_atexit(task, cleanup_task_local_map_extern_cb); // Also need to reference it an extra time to keep it for now. let nonmut = cast::transmute::<TaskLocalMap, @~[Option<TaskLocalElement>]>(map); @@ -75,6 +110,27 @@ unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap { } } +unsafe fn get_newsched_local_map(local: *mut LocalStorage) -> TaskLocalMap { + match &mut *local { + &LocalStorage(map_ptr, Some(_)) => { + assert!(map_ptr.is_not_null()); + let map = cast::transmute(map_ptr); + let nonmut = cast::transmute::<TaskLocalMap, + @~[Option<TaskLocalElement>]>(map); + cast::bump_box_refcount(nonmut); + return map; + } + &LocalStorage(ref mut map_ptr, ref mut at_exit) => { + assert!((*map_ptr).is_null()); + let map: TaskLocalMap = @mut ~[]; + *map_ptr = cast::transmute(map); + let at_exit_fn: ~fn(*libc::c_void) = |p|cleanup_task_local_map(p); + *at_exit = Some(at_exit_fn); + return map; + } + } +} + unsafe fn key_to_key_value<T:Durable>(key: LocalDataKey<T>) -> *libc::c_void { // Keys are closures, which are (fnptr,envptr) pairs. Use fnptr. // Use reintepret_cast -- transmute would leak (forget) the closure. @@ -102,10 +158,10 @@ unsafe fn local_data_lookup<T:Durable>( } unsafe fn local_get_helper<T:Durable>( - task: *rust_task, key: LocalDataKey<T>, + handle: Handle, key: LocalDataKey<T>, do_pop: bool) -> Option<@T> { - let map = get_task_local_map(task); + let map = get_local_map(handle); // Interpreturn our findings from the map do local_data_lookup(map, key).map |result| { // A reference count magically appears on 'data' out of thin air. It @@ -124,23 +180,23 @@ unsafe fn local_get_helper<T:Durable>( pub unsafe fn local_pop<T:Durable>( - task: *rust_task, + handle: Handle, key: LocalDataKey<T>) -> Option<@T> { - local_get_helper(task, key, true) + local_get_helper(handle, key, true) } pub unsafe fn local_get<T:Durable>( - task: *rust_task, + handle: Handle, key: LocalDataKey<T>) -> Option<@T> { - local_get_helper(task, key, false) + local_get_helper(handle, key, false) } pub unsafe fn local_set<T:Durable>( - task: *rust_task, key: LocalDataKey<T>, data: @T) { + handle: Handle, key: LocalDataKey<T>, data: @T) { - let map = get_task_local_map(task); + let map = get_local_map(handle); // Store key+data as *voids. Data is invisibly referenced once; key isn't. let keyval = key_to_key_value(key); // We keep the data in two forms: one as an unsafe pointer, so we can get @@ -148,7 +204,7 @@ pub unsafe fn local_set<T:Durable>( // own on it can be dropped when the box is destroyed. The unsafe pointer // does not have a reference associated with it, so it may become invalid // when the box is destroyed. - let data_ptr = cast::transmute(data); + let data_ptr = *cast::transmute::<&@T, &*libc::c_void>(&data); let data_box = @data as @LocalData; // Construct new entry to store in the map. let new_entry = Some((keyval, data_ptr, data_box)); @@ -170,12 +226,12 @@ pub unsafe fn local_set<T:Durable>( } pub unsafe fn local_modify<T:Durable>( - task: *rust_task, key: LocalDataKey<T>, + handle: Handle, key: LocalDataKey<T>, modify_fn: &fn(Option<@T>) -> Option<@T>) { // Could be more efficient by doing the lookup work, but this is easy. - let newdata = modify_fn(local_pop(task, key)); + let newdata = modify_fn(local_pop(handle, key)); if newdata.is_some() { - local_set(task, key, newdata.unwrap()); + local_set(handle, key, newdata.unwrap()); } } diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 96429932b18..fd695c16ea7 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -39,9 +39,10 @@ use result::Result; use comm::{stream, Chan, GenericChan, GenericPort, Port}; use prelude::*; use result; -use task::rt::{task_id, sched_id, rust_task}; +use task::rt::{task_id, sched_id}; use util; use util::replace; +use unstable::finally::Finally; #[cfg(test)] use comm::SharedChan; @@ -558,8 +559,31 @@ pub fn yield() { pub fn failing() -> bool { //! True if the running task has failed - unsafe { - rt::rust_task_is_unwinding(rt::rust_get_task()) + use rt::{context, OldTaskContext}; + use rt::local_services::borrow_local_services; + + match context() { + OldTaskContext => { + unsafe { + rt::rust_task_is_unwinding(rt::rust_get_task()) + } + } + _ => { + let mut unwinding = false; + do borrow_local_services |local| { + unwinding = match local.unwinder { + Some(unwinder) => { + unwinder.unwinding + } + None => { + // Because there is no unwinder we can't be unwinding. + // (The process will abort on failure) + false + } + } + } + return unwinding; + } } } @@ -591,48 +615,24 @@ pub fn get_scheduler() -> Scheduler { * ~~~ */ pub unsafe fn unkillable<U>(f: &fn() -> U) -> U { - struct AllowFailure { - t: *rust_task, - drop { - unsafe { - rt::rust_task_allow_kill(self.t); - } - } - } - - fn AllowFailure(t: *rust_task) -> AllowFailure{ - AllowFailure { - t: t - } - } - let t = rt::rust_get_task(); - let _allow_failure = AllowFailure(t); - rt::rust_task_inhibit_kill(t); - f() + do (|| { + rt::rust_task_inhibit_kill(t); + f() + }).finally { + rt::rust_task_allow_kill(t); + } } /// The inverse of unkillable. Only ever to be used nested in unkillable(). pub unsafe fn rekillable<U>(f: &fn() -> U) -> U { - struct DisallowFailure { - t: *rust_task, - drop { - unsafe { - rt::rust_task_inhibit_kill(self.t); - } - } - } - - fn DisallowFailure(t: *rust_task) -> DisallowFailure { - DisallowFailure { - t: t - } - } - let t = rt::rust_get_task(); - let _allow_failure = DisallowFailure(t); - rt::rust_task_allow_kill(t); - f() + do (|| { + rt::rust_task_allow_kill(t); + f() + }).finally { + rt::rust_task_inhibit_kill(t); + } } /** @@ -640,27 +640,15 @@ pub unsafe fn rekillable<U>(f: &fn() -> U) -> U { * For use with exclusive ARCs, which use pthread mutexes directly. */ pub unsafe fn atomically<U>(f: &fn() -> U) -> U { - struct DeferInterrupts { - t: *rust_task, - drop { - unsafe { - rt::rust_task_allow_yield(self.t); - rt::rust_task_allow_kill(self.t); - } - } - } - - fn DeferInterrupts(t: *rust_task) -> DeferInterrupts { - DeferInterrupts { - t: t - } - } - let t = rt::rust_get_task(); - let _interrupts = DeferInterrupts(t); - rt::rust_task_inhibit_kill(t); - rt::rust_task_inhibit_yield(t); - f() + do (|| { + rt::rust_task_inhibit_kill(t); + rt::rust_task_inhibit_yield(t); + f() + }).finally { + rt::rust_task_allow_yield(t); + rt::rust_task_allow_kill(t); + } } #[test] #[should_fail] #[ignore(cfg(windows))] @@ -832,7 +820,7 @@ fn test_run_basic() { po.recv(); } -#[test] +#[cfg(test)] struct Wrapper { mut f: Option<Chan<()>> } @@ -1229,7 +1217,7 @@ fn test_spawn_thread_on_demand() { #[test] fn test_simple_newsched_spawn() { - use rt::run_in_newsched_task; + use rt::test::run_in_newsched_task; do run_in_newsched_task { spawn(||()) diff --git a/src/libcore/task/spawn.rs b/src/libcore/task/spawn.rs index 507643ea5ec..267250b3642 100644 --- a/src/libcore/task/spawn.rs +++ b/src/libcore/task/spawn.rs @@ -80,7 +80,7 @@ use prelude::*; use unstable; use ptr; use hashmap::HashSet; -use task::local_data_priv::{local_get, local_set}; +use task::local_data_priv::{local_get, local_set, OldHandle}; use task::rt::rust_task; use task::rt; use task::{Failure, ManualThreads, PlatformThread, SchedOpts, SingleThreaded}; @@ -451,7 +451,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) /*##################################################################* * Step 1. Get spawner's taskgroup info. *##################################################################*/ - let spawner_group = match local_get(spawner, taskgroup_key!()) { + let spawner_group = match local_get(OldHandle(spawner), taskgroup_key!()) { None => { // Main task, doing first spawn ever. Lazily initialise here. let mut members = new_taskset(); @@ -463,7 +463,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) // Main task/group has no ancestors, no notifier, etc. let group = @TCB(spawner, tasks, AncestorList(None), true, None); - local_set(spawner, taskgroup_key!(), group); + local_set(OldHandle(spawner), taskgroup_key!(), group); group } Some(group) => group @@ -627,7 +627,7 @@ fn spawn_raw_oldsched(opts: TaskOpts, f: ~fn()) { let group = @TCB(child, child_arc, ancestors, is_main, notifier); unsafe { - local_set(child, taskgroup_key!(), group); + local_set(OldHandle(child), taskgroup_key!(), group); } // Run the child's body. diff --git a/src/libcore/to_bytes.rs b/src/libcore/to_bytes.rs index 63dcf0f44dc..9e4da7ab488 100644 --- a/src/libcore/to_bytes.rs +++ b/src/libcore/to_bytes.rs @@ -419,8 +419,7 @@ impl<A> IterBytes for *const A { } } - -trait ToBytes { +pub trait ToBytes { fn to_bytes(&self, lsb0: bool) -> ~[u8]; } diff --git a/src/libcore/unicode.rs b/src/libcore/unicode.rs index a13d66c48ee..d6e2c5eee6a 100644 --- a/src/libcore/unicode.rs +++ b/src/libcore/unicode.rs @@ -10,6 +10,8 @@ #[doc(hidden)]; // FIXME #3538 +// The following code was generated by "src/etc/unicode.py" + pub mod general_category { fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { @@ -2640,4 +2642,3 @@ pub mod derived_property { bsearch_range_table(c, XID_Start_table) } } - diff --git a/src/libcore/unstable/exchange_alloc.rs b/src/libcore/unstable/exchange_alloc.rs index 8ca5486d929..57ed579e88d 100644 --- a/src/libcore/unstable/exchange_alloc.rs +++ b/src/libcore/unstable/exchange_alloc.rs @@ -81,4 +81,3 @@ extern { #[rust_stack] fn rust_get_exchange_count_ptr() -> *mut int; } - diff --git a/src/libcore/unstable/extfmt.rs b/src/libcore/unstable/extfmt.rs index e5d32c4bb32..258da9ff383 100644 --- a/src/libcore/unstable/extfmt.rs +++ b/src/libcore/unstable/extfmt.rs @@ -688,11 +688,3 @@ mod test { let _s = fmt!("%s", s); } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/unstable/intrinsics.rs b/src/libcore/unstable/intrinsics.rs index b58429a10aa..65cfc6ec1fe 100644 --- a/src/libcore/unstable/intrinsics.rs +++ b/src/libcore/unstable/intrinsics.rs @@ -46,10 +46,6 @@ pub extern "rust-intrinsic" { pub fn forget<T>(_: T) -> (); - // XXX: intrinsic uses legacy modes - #[cfg(stage0)] - fn reinterpret_cast<T,U>(&&src: T) -> U; - pub fn needs_drop<T>() -> bool; // XXX: intrinsic uses legacy modes and has reference to TyDesc diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index 6b61df31fdc..deff06d46f6 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -18,9 +18,11 @@ use str; use sys; use unstable::exchange_alloc; use cast::transmute; -use task::rt::rust_get_task; +use rt::{context, OldTaskContext}; +use rt::local_services::borrow_local_services; use option::{Option, Some, None}; use io; +use task::rt::rust_get_task; #[allow(non_camel_case_types)] pub type rust_task = c_void; @@ -249,21 +251,36 @@ pub unsafe fn exchange_free(ptr: *c_char) { } #[lang="malloc"] -#[inline(always)] pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { - let result = rustrt::rust_upcall_malloc_noswitch(td, size); - debug_mem("local_malloc: ", result); - return result; + match context() { + OldTaskContext => { + return rustrt::rust_upcall_malloc_noswitch(td, size); + } + _ => { + let mut alloc = ::ptr::null(); + do borrow_local_services |srv| { + alloc = srv.heap.alloc(td as *c_void, size as uint) as *c_char; + } + return alloc; + } + } } // NB: Calls to free CANNOT be allowed to fail, as throwing an exception from // inside a landing pad may corrupt the state of the exception handler. If a // problem occurs, call exit instead. #[lang="free"] -#[inline(always)] pub unsafe fn local_free(ptr: *c_char) { - debug_mem("local_free: ", ptr); - rustrt::rust_upcall_free_noswitch(ptr); + match context() { + OldTaskContext => { + rustrt::rust_upcall_free_noswitch(ptr); + } + _ => { + do borrow_local_services |srv| { + srv.heap.free(ptr as *c_void); + } + } + } } #[cfg(stage0)] @@ -444,11 +461,3 @@ pub fn start(main: *u8, argc: int, argv: **c_char, crate_map: *c_void) -> c_int; } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/unstable/weak_task.rs b/src/libcore/unstable/weak_task.rs index 7a30bb92111..6edbdcb51b0 100644 --- a/src/libcore/unstable/weak_task.rs +++ b/src/libcore/unstable/weak_task.rs @@ -205,4 +205,3 @@ fn test_select_stream_and_oneshot() { chan.send(()); waitport.recv(); } - diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 4c817da0819..ced3c300a35 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -134,9 +134,9 @@ pub fn uniq_len<T>(v: &const ~[T]) -> uint { } /** - * Creates and initializes an immutable vector. + * Creates and initializes an owned vector. * - * Creates an immutable vector of size `n_elts` and initializes the elements + * Creates an owned vector of size `n_elts` and initializes the elements * to the value returned by the function `op`. */ pub fn from_fn<T>(n_elts: uint, op: old_iter::InitOp<T>) -> ~[T] { @@ -156,9 +156,9 @@ pub fn from_fn<T>(n_elts: uint, op: old_iter::InitOp<T>) -> ~[T] { } /** - * Creates and initializes an immutable vector. + * Creates and initializes an owned vector. * - * Creates an immutable vector of size `n_elts` and initializes the elements + * Creates an owned vector of size `n_elts` and initializes the elements * to the value `t`. */ pub fn from_elem<T:Copy>(n_elts: uint, t: T) -> ~[T] { |
