diff options
100 files changed, 2730 insertions, 1412 deletions
diff --git a/Makefile.in b/Makefile.in index 7f1a6945d8a..aab1e2ff556 100644 --- a/Makefile.in +++ b/Makefile.in @@ -367,7 +367,7 @@ LLVM_COMPONENTS=x86 arm mips ipo bitreader bitwriter linker asmparser jit mcjit interpreter instrumentation # Only build these LLVM tools -LLVM_TOOLS=bugpoint llc llvm-ar llvm-as llvm-dis llvm-mc opt +LLVM_TOOLS=bugpoint llc llvm-ar llvm-as llvm-dis llvm-mc opt llvm-extract define DEF_LLVM_VARS # The configure script defines these variables with the target triples diff --git a/doc/guide-container.md b/doc/guide-container.md index 668e263697c..628e4f223b4 100644 --- a/doc/guide-container.md +++ b/doc/guide-container.md @@ -336,8 +336,8 @@ The `DoubleEndedIterator` trait represents an iterator able to yield elements from either end of a range. It inherits from the `Iterator` trait and extends it with the `next_back` function. -A `DoubleEndedIterator` can be flipped with the `invert` adaptor, returning -another `DoubleEndedIterator` with `next` and `next_back` exchanged. +A `DoubleEndedIterator` can have its direction changed with the `rev` adaptor, +returning another `DoubleEndedIterator` with `next` and `next_back` exchanged. ~~~ let xs = [1, 2, 3, 4, 5, 6]; @@ -347,7 +347,7 @@ println!("{:?}", it.next()); // prints `Some(&2)` println!("{:?}", it.next_back()); // prints `Some(&6)` // prints `5`, `4` and `3` -for &x in it.invert() { +for &x in it.rev() { println!("{}", x) } ~~~ @@ -366,7 +366,7 @@ let mut it = xs.iter().chain(ys.iter()).map(|&x| x * 2); println!("{:?}", it.next()); // prints `Some(2)` // prints `16`, `14`, `12`, `10`, `8`, `6`, `4` -for x in it.invert() { +for x in it.rev() { println!("{}", x); } ~~~ diff --git a/doc/guide-ffi.md b/doc/guide-ffi.md index 236da56588e..217eab52758 100644 --- a/doc/guide-ffi.md +++ b/doc/guide-ffi.md @@ -230,7 +230,7 @@ impl<T: Send> Drop for Unique<T> { // We need to move the object out of the box, so that // the destructor is called (at the end of this scope.) ptr::replace_ptr(self.ptr, x); - free(self.ptr as *c_void) + free(self.ptr as *mut c_void) } } } diff --git a/doc/tutorial.md b/doc/tutorial.md index 057944484ba..cc8dd6edd3f 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -3071,7 +3071,8 @@ The effect it has on your module hierarchy mirrors aspects of both `mod` and `us The linkage information the binary needs to use the library `foo`. - But like `use`, all `extern mod` statements that refer to the same library are interchangeable, - as each one really just presents an alias to an external module (the crate root of the library your linking against). + as each one really just presents an alias to an external module (the crate root of the library + you're linking against). Remember how `use`-statements have to go before local declarations because the latter shadows the former? Well, `extern mod` statements also have their own rules in that regard: diff --git a/man/rustc.1 b/man/rustc.1 index e4cfab7747f..6f84d0f8f71 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -122,8 +122,8 @@ To build an executable from a source file with a main function: To build a library from a source file: $ rustc --lib hello-lib.rs -To build either with a crate (.rc) file: - $ rustc hello.rc +To build either with a crate (.rs) file: + $ rustc hello.rs To build an executable with debug info (experimental): $ rustc -Z debug-info -o hello hello.rs diff --git a/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang b/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang index b8841ebe568..43700c02b75 100644 --- a/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang +++ b/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang @@ -5,7 +5,7 @@ <language id="rust" _name="Rust" version="2.0" _section="Sources"> <metadata> <property name="mimetypes">text/x-rust</property> - <property name="globs">*.rs;*.rc</property> + <property name="globs">*.rs</property> <property name="line-comment-start">//</property> <property name="block-comment-start">/*</property> <property name="block-comment-end">*/</property> diff --git a/src/etc/gedit/share/mime/packages/rust.xml b/src/etc/gedit/share/mime/packages/rust.xml index d75cffe9600..ede1c14907c 100644 --- a/src/etc/gedit/share/mime/packages/rust.xml +++ b/src/etc/gedit/share/mime/packages/rust.xml @@ -2,6 +2,5 @@ <mime-type type="text/x-rust"> <comment>Rust Source</comment> <glob pattern="*.rs"/> - <glob pattern="*.rc"/> </mime-type> </mime-info> diff --git a/src/etc/kate/rust.xml b/src/etc/kate/rust.xml index db479e468d5..c1c5215ac0f 100644 --- a/src/etc/kate/rust.xml +++ b/src/etc/kate/rust.xml @@ -7,7 +7,7 @@ <!ENTITY rustIdent "[a-zA-Z_][a-zA-Z_0-9]*"> <!ENTITY rustIntSuf "([iu](8|16|32|64)?)?"> ]> -<language name="Rust" version="0.10-pre" kateversion="2.4" section="Sources" extensions="*.rs;*.rc" mimetype="text/x-rust" priority="15"> +<language name="Rust" version="0.10-pre" kateversion="2.4" section="Sources" extensions="*.rs" mimetype="text/x-rust" priority="15"> <highlighting> <list name="fn"> <item> fn </item> diff --git a/src/etc/vim/ftdetect/rust.vim b/src/etc/vim/ftdetect/rust.vim index 10b616277c8..bf685d43243 100644 --- a/src/etc/vim/ftdetect/rust.vim +++ b/src/etc/vim/ftdetect/rust.vim @@ -1 +1 @@ -au BufRead,BufNewFile *.rs,*.rc set filetype=rust +au BufRead,BufNewFile *.rs set filetype=rust diff --git a/src/libextra/bitv.rs b/src/libextra/bitv.rs index 305c9702001..9df75ff044a 100644 --- a/src/libextra/bitv.rs +++ b/src/libextra/bitv.rs @@ -13,7 +13,7 @@ use std::cmp; use std::iter::RandomAccessIterator; -use std::iter::{Invert, Enumerate, Repeat, Map, Zip}; +use std::iter::{Rev, Enumerate, Repeat, Map, Zip}; use std::num; use std::ops; use std::uint; @@ -387,7 +387,7 @@ impl Bitv { } } - /// Invert all bits + /// Flip all bits #[inline] pub fn negate(&mut self) { match self.rep { @@ -428,8 +428,8 @@ impl Bitv { } #[inline] - pub fn rev_iter<'a>(&'a self) -> Invert<Bits<'a>> { - self.iter().invert() + pub fn rev_iter<'a>(&'a self) -> Rev<Bits<'a>> { + self.iter().rev() } /// Returns `true` if all bits are 0 diff --git a/src/libextra/c_vec.rs b/src/libextra/c_vec.rs index fc2caa13584..35a6ccaa708 100644 --- a/src/libextra/c_vec.rs +++ b/src/libextra/c_vec.rs @@ -172,7 +172,7 @@ mod tests { let mem = malloc_raw(n); CVec::new_with_dtor(mem as *mut u8, n, - proc() { libc::free(mem as *c_void); }) + proc() { libc::free(mem as *mut c_void); }) } } diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index 115700e7408..fa6e7c15ee0 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -25,7 +25,7 @@ use std::cast; use std::ptr; use std::util; -use std::iter::Invert; +use std::iter::Rev; use std::iter; use container::Deque; @@ -368,8 +368,8 @@ impl<T> DList<T> { /// Provide a reverse iterator #[inline] - pub fn rev_iter<'a>(&'a self) -> Invert<Items<'a, T>> { - self.iter().invert() + pub fn rev_iter<'a>(&'a self) -> Rev<Items<'a, T>> { + self.iter().rev() } /// Provide a forward iterator with mutable references @@ -388,8 +388,8 @@ impl<T> DList<T> { } /// Provide a reverse iterator with mutable references #[inline] - pub fn mut_rev_iter<'a>(&'a mut self) -> Invert<MutItems<'a, T>> { - self.mut_iter().invert() + pub fn mut_rev_iter<'a>(&'a mut self) -> Rev<MutItems<'a, T>> { + self.mut_iter().rev() } @@ -401,8 +401,8 @@ impl<T> DList<T> { /// Consume the list into an iterator yielding elements by value, in reverse #[inline] - pub fn move_rev_iter(self) -> Invert<MoveItems<T>> { - self.move_iter().invert() + pub fn move_rev_iter(self) -> Rev<MoveItems<T>> { + self.move_iter().rev() } } diff --git a/src/libextra/flate.rs b/src/libextra/flate.rs index 1153c3a6ef3..faceb17af47 100644 --- a/src/libextra/flate.rs +++ b/src/libextra/flate.rs @@ -53,7 +53,7 @@ fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] { assert!(res as int != 0); let out = vec::raw::from_buf_raw(res as *u8, outsz as uint); - libc::free(res); + libc::free(res as *mut c_void); out } } @@ -76,7 +76,7 @@ fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] { assert!(res as int != 0); let out = vec::raw::from_buf_raw(res as *u8, outsz as uint); - libc::free(res); + libc::free(res as *mut c_void); out } } diff --git a/src/libextra/ringbuf.rs b/src/libextra/ringbuf.rs index c5c8f69dc65..684aafd2500 100644 --- a/src/libextra/ringbuf.rs +++ b/src/libextra/ringbuf.rs @@ -15,7 +15,7 @@ use std::num; use std::vec; -use std::iter::{Invert, RandomAccessIterator}; +use std::iter::{Rev, RandomAccessIterator}; use container::Deque; @@ -192,8 +192,8 @@ impl<T> RingBuf<T> { } /// Back-to-front iterator. - pub fn rev_iter<'a>(&'a self) -> Invert<Items<'a, T>> { - self.iter().invert() + pub fn rev_iter<'a>(&'a self) -> Rev<Items<'a, T>> { + self.iter().rev() } /// Front-to-back iterator which returns mutable values. @@ -223,8 +223,8 @@ impl<T> RingBuf<T> { } /// Back-to-front iterator which returns mutable values. - pub fn mut_rev_iter<'a>(&'a mut self) -> Invert<MutItems<'a, T>> { - self.mut_iter().invert() + pub fn mut_rev_iter<'a>(&'a mut self) -> Rev<MutItems<'a, T>> { + self.mut_iter().rev() } } diff --git a/src/libextra/smallintmap.rs b/src/libextra/smallintmap.rs index 93d138a9d46..abbd987a9c4 100644 --- a/src/libextra/smallintmap.rs +++ b/src/libextra/smallintmap.rs @@ -15,7 +15,7 @@ #[allow(missing_doc)]; -use std::iter::{Enumerate, FilterMap, Invert}; +use std::iter::{Enumerate, FilterMap, Rev}; use std::util::replace; use std::vec; @@ -140,14 +140,14 @@ impl<V> SmallIntMap<V> { /// An iterator visiting all key-value pairs in descending order by the keys. /// Iterator element type is (uint, &'r V) pub fn rev_iter<'r>(&'r self) -> RevEntries<'r, V> { - self.iter().invert() + self.iter().rev() } /// An iterator visiting all key-value pairs in descending order by the keys, /// with mutable references to the values /// Iterator element type is (uint, &'r mut V) pub fn mut_rev_iter<'r>(&'r mut self) -> RevMutEntries <'r, V> { - self.mut_iter().invert() + self.mut_iter().rev() } /// Empties the hash map, moving all values into the specified closure @@ -241,7 +241,7 @@ pub struct Entries<'a, T> { iterator!(impl Entries -> (uint, &'a T), get_ref) double_ended_iterator!(impl Entries -> (uint, &'a T), get_ref) -pub type RevEntries<'a, T> = Invert<Entries<'a, T>>; +pub type RevEntries<'a, T> = Rev<Entries<'a, T>>; pub struct MutEntries<'a, T> { priv front: uint, @@ -251,7 +251,7 @@ pub struct MutEntries<'a, T> { iterator!(impl MutEntries -> (uint, &'a mut T), get_mut_ref) double_ended_iterator!(impl MutEntries -> (uint, &'a mut T), get_mut_ref) -pub type RevMutEntries<'a, T> = Invert<MutEntries<'a, T>>; +pub type RevMutEntries<'a, T> = Rev<MutEntries<'a, T>>; #[cfg(test)] mod test_map { diff --git a/src/libnative/bookkeeping.rs b/src/libnative/bookkeeping.rs index 6c5f555f401..b07e4271ee4 100644 --- a/src/libnative/bookkeeping.rs +++ b/src/libnative/bookkeeping.rs @@ -45,5 +45,6 @@ pub fn wait_for_other_tasks() { TASK_LOCK.wait(); } TASK_LOCK.unlock(); + TASK_LOCK.destroy(); } } diff --git a/src/libnative/io/file.rs b/src/libnative/io/file.rs index af6ed51729e..af06533d44b 100644 --- a/src/libnative/io/file.rs +++ b/src/libnative/io/file.rs @@ -548,13 +548,13 @@ pub fn readdir(p: &CString) -> IoResult<~[Path]> { let p = Path::new(p); let star = p.join("*"); as_utf16_p(star.as_str().unwrap(), |path_ptr| { - let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint) as *c_void; + let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint); let find_handle = FindFirstFileW(path_ptr, wfd_ptr as HANDLE); if find_handle as libc::c_int != INVALID_HANDLE_VALUE { let mut paths = ~[]; let mut more_files = 1 as libc::c_int; while more_files != 0 { - let fp_buf = rust_list_dir_wfd_fp_buf(wfd_ptr); + let fp_buf = rust_list_dir_wfd_fp_buf(wfd_ptr as *c_void); if fp_buf as uint == 0 { fail!("os::list_dir() failure: got null ptr from wfd"); } @@ -567,7 +567,7 @@ pub fn readdir(p: &CString) -> IoResult<~[Path]> { more_files = FindNextFileW(find_handle, wfd_ptr as HANDLE); } FindClose(find_handle); - free(wfd_ptr); + free(wfd_ptr as *mut c_void); Ok(paths) } else { Err(super::last_error()) diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index f1bec440547..f3aca7820a5 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -46,6 +46,22 @@ pub mod file; pub mod process; pub mod net; +#[cfg(target_os = "macos")] +#[cfg(target_os = "freebsd")] +#[path = "timer_other.rs"] +pub mod timer; + +#[cfg(target_os = "linux")] +#[cfg(target_os = "android")] +#[path = "timer_timerfd.rs"] +pub mod timer; + +#[cfg(target_os = "win32")] +#[path = "timer_win32.rs"] +pub mod timer; + +mod timer_helper; + type IoResult<T> = Result<T, IoError>; fn unimpl() -> IoError { @@ -249,7 +265,7 @@ impl rtio::IoFactory for IoFactory { // misc fn timer_init(&mut self) -> IoResult<~RtioTimer> { - Err(unimpl()) + timer::Timer::new().map(|t| ~t as ~RtioTimer) } fn spawn(&mut self, config: ProcessConfig) -> IoResult<(~RtioProcess, ~[Option<~RtioPipe>])> { diff --git a/src/libnative/io/process.rs b/src/libnative/io/process.rs index 0569c45f6de..ee4ee295055 100644 --- a/src/libnative/io/process.rs +++ b/src/libnative/io/process.rs @@ -460,7 +460,7 @@ fn spawn_process_os(prog: &str, args: &[~str], fail!("failure in dup3(err_fd, 2): {}", os::last_os_error()); } // close all other fds - for fd in range(3, getdtablesize()).invert() { + for fd in range(3, getdtablesize()).rev() { if fd != output.fd() { close(fd as c_int); } diff --git a/src/libnative/io/timer_helper.rs b/src/libnative/io/timer_helper.rs new file mode 100644 index 00000000000..3c20d073f29 --- /dev/null +++ b/src/libnative/io/timer_helper.rs @@ -0,0 +1,143 @@ +// 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. + +//! Implementation of the helper thread for the timer module +//! +//! This module contains the management necessary for the timer worker thread. +//! This thread is responsible for performing the send()s on channels for timers +//! that are using channels instead of a blocking call. +//! +//! The timer thread is lazily initialized, and it's shut down via the +//! `shutdown` function provided. It must be maintained as an invariant that +//! `shutdown` is only called when the entire program is finished. No new timers +//! can be created in the future and there must be no active timers at that +//! time. + +use std::cast; +use std::rt; +use std::unstable::mutex::{Once, ONCE_INIT}; + +use bookkeeping; +use io::timer::{Req, Shutdown}; +use task; + +// You'll note that these variables are *not* protected by a lock. These +// variables are initialized with a Once before any Timer is created and are +// only torn down after everything else has exited. This means that these +// variables are read-only during use (after initialization) and both of which +// are safe to use concurrently. +static mut HELPER_CHAN: *mut SharedChan<Req> = 0 as *mut SharedChan<Req>; +static mut HELPER_SIGNAL: imp::signal = 0 as imp::signal; + +pub fn boot(helper: fn(imp::signal, Port<Req>)) { + static mut INIT: Once = ONCE_INIT; + + unsafe { + INIT.doit(|| { + let (msgp, msgc) = SharedChan::new(); + HELPER_CHAN = cast::transmute(~msgc); + let (receive, send) = imp::new(); + HELPER_SIGNAL = send; + + do task::spawn { + bookkeeping::decrement(); + helper(receive, msgp); + } + + rt::at_exit(proc() { shutdown() }); + }) + } +} + +pub fn send(req: Req) { + unsafe { + assert!(!HELPER_CHAN.is_null()); + (*HELPER_CHAN).send(req); + imp::signal(HELPER_SIGNAL); + } +} + +fn shutdown() { + // We want to wait for the entire helper task to exit, and in doing so it + // will attempt to decrement the global task count. When the helper was + // created, it decremented the count so it wouldn't count towards preventing + // the program to exit, so here we pair that manual decrement with a manual + // increment. We will then wait for the helper thread to exit by calling + // wait_for_other_tasks. + bookkeeping::increment(); + + // Request a shutdown, and then wait for the task to exit + send(Shutdown); + bookkeeping::wait_for_other_tasks(); + + // Clean up after ther helper thread + unsafe { + imp::close(HELPER_SIGNAL); + let _chan: ~SharedChan<Req> = cast::transmute(HELPER_CHAN); + HELPER_CHAN = 0 as *mut SharedChan<Req>; + HELPER_SIGNAL = 0 as imp::signal; + } +} + +#[cfg(unix)] +mod imp { + use std::libc; + use std::os; + + use io::file::FileDesc; + + pub type signal = libc::c_int; + + pub fn new() -> (signal, signal) { + let pipe = os::pipe(); + (pipe.input, pipe.out) + } + + pub fn signal(fd: libc::c_int) { + FileDesc::new(fd, false).inner_write([0]); + } + + pub fn close(fd: libc::c_int) { + let _fd = FileDesc::new(fd, true); + } +} + +#[cfg(windows)] +mod imp { + use std::libc::{BOOL, LPCSTR, HANDLE, LPSECURITY_ATTRIBUTES, CloseHandle}; + use std::ptr; + use std::libc; + + pub type signal = HANDLE; + + pub fn new() -> (HANDLE, HANDLE) { + unsafe { + let handle = CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE, + ptr::null()); + (handle, handle) + } + } + + pub fn signal(handle: HANDLE) { + unsafe { SetEvent(handle); } + } + + pub fn close(handle: HANDLE) { + unsafe { CloseHandle(handle); } + } + + extern "system" { + fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + bManualReset: BOOL, + bInitialState: BOOL, + lpName: LPCSTR) -> HANDLE; + fn SetEvent(hEvent: HANDLE) -> BOOL; + } +} diff --git a/src/libnative/io/timer_other.rs b/src/libnative/io/timer_other.rs new file mode 100644 index 00000000000..24ffd7a4147 --- /dev/null +++ b/src/libnative/io/timer_other.rs @@ -0,0 +1,328 @@ +// 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. + +//! Timers for non-linux/non-windows OSes +//! +//! This module implements timers with a worker thread, select(), and a lot of +//! witchcraft that turns out to be horribly inaccurate timers. The unfortunate +//! part is that I'm at a loss of what else to do one these OSes. This is also +//! why linux has a specialized timerfd implementation and windows has its own +//! implementation (they're more accurate than this one). +//! +//! The basic idea is that there is a worker thread that's communicated to via a +//! channel and a pipe, the pipe is used by the worker thread in a select() +//! syscall with a timeout. The timeout is the "next timer timeout" while the +//! channel is used to send data over to the worker thread. +//! +//! Whenever the call to select() times out, then a channel receives a message. +//! Whenever the call returns that the file descriptor has information, then the +//! channel from timers is drained, enqueueing all incoming requests. +//! +//! The actual implementation of the helper thread is a sorted array of +//! timers in terms of target firing date. The target is the absolute time at +//! which the timer should fire. Timers are then re-enqueued after a firing if +//! the repeat boolean is set. +//! +//! Naturally, all this logic of adding times and keeping track of +//! relative/absolute time is a little lossy and not quite exact. I've done the +//! best I could to reduce the amount of calls to 'now()', but there's likely +//! still inaccuracies trickling in here and there. +//! +//! One of the tricky parts of this implementation is that whenever a timer is +//! acted upon, it must cancel whatever the previous action was (if one is +//! active) in order to act like the other implementations of this timer. In +//! order to do this, the timer's inner pointer is transferred to the worker +//! thread. Whenever the timer is modified, it first takes ownership back from +//! the worker thread in order to modify the same data structure. This has the +//! side effect of "cancelling" the previous requests while allowing a +//! re-enqueueing later on. +//! +//! Note that all time units in this file are in *milliseconds*. + +use std::comm::Data; +use std::hashmap::HashMap; +use std::libc; +use std::os; +use std::ptr; +use std::rt::rtio; +use std::sync::atomics; +use std::unstable::intrinsics; + +use io::file::FileDesc; +use io::IoResult; +use io::timer_helper; + +pub struct Timer { + priv id: uint, + priv inner: Option<~Inner>, +} + +struct Inner { + chan: Option<Chan<()>>, + interval: u64, + repeat: bool, + target: u64, + id: uint, +} + +pub enum Req { + // Add a new timer to the helper thread. + NewTimer(~Inner), + + // Remove a timer based on its id and then send it back on the channel + // provided + RemoveTimer(uint, Chan<~Inner>), + + // Shut down the loop and then ACK this channel once it's shut down + Shutdown, +} + +// returns the current time (in milliseconds) +fn now() -> u64 { + unsafe { + let mut now: libc::timeval = intrinsics::init(); + assert_eq!(imp::gettimeofday(&mut now, ptr::null()), 0); + return (now.tv_sec as u64) * 1000 + (now.tv_usec as u64) / 1000; + } +} + +fn helper(input: libc::c_int, messages: Port<Req>) { + let mut set: imp::fd_set = unsafe { intrinsics::init() }; + + let mut fd = FileDesc::new(input, true); + let mut timeout: libc::timeval = unsafe { intrinsics::init() }; + + // active timers are those which are able to be selected upon (and it's a + // sorted list, and dead timers are those which have expired, but ownership + // hasn't yet been transferred back to the timer itself. + let mut active: ~[~Inner] = ~[]; + let mut dead = HashMap::new(); + + // inserts a timer into an array of timers (sorted by firing time) + fn insert(t: ~Inner, active: &mut ~[~Inner]) { + match active.iter().position(|tm| tm.target > t.target) { + Some(pos) => { active.insert(pos, t); } + None => { active.push(t); } + } + } + + // signals the first requests in the queue, possible re-enqueueing it. + fn signal(active: &mut ~[~Inner], dead: &mut HashMap<uint, ~Inner>) { + let mut timer = match active.shift() { + Some(timer) => timer, None => return + }; + let chan = timer.chan.take_unwrap(); + if chan.try_send(()) && timer.repeat { + timer.chan = Some(chan); + timer.target += timer.interval; + insert(timer, active); + } else { + drop(chan); + dead.insert(timer.id, timer); + } + } + + 'outer: loop { + let timeout = match active { + // Empty array? no timeout (wait forever for the next request) + [] => ptr::null(), + + [~Inner { target, .. }, ..] => { + let now = now(); + // If this request has already expired, then signal it and go + // through another iteration + if target <= now { + signal(&mut active, &mut dead); + continue; + } + + // The actual timeout listed in the requests array is an + // absolute date, so here we translate the absolute time to a + // relative time. + let tm = target - now; + timeout.tv_sec = (tm / 1000) as libc::time_t; + timeout.tv_usec = ((tm % 1000) * 1000) as libc::suseconds_t; + &timeout as *libc::timeval + } + }; + + imp::fd_set(&mut set, input); + match unsafe { + imp::select(input + 1, &set, ptr::null(), ptr::null(), timeout) + } { + // timed out + 0 => signal(&mut active, &mut dead), + + // file descriptor write woke us up, we've got some new requests + 1 => { + loop { + match messages.try_recv() { + Data(Shutdown) => { + assert!(active.len() == 0); + break 'outer; + } + + Data(NewTimer(timer)) => insert(timer, &mut active), + + Data(RemoveTimer(id, ack)) => { + match dead.pop(&id) { + Some(i) => { ack.send(i); continue } + None => {} + } + let i = active.iter().position(|i| i.id == id); + let i = i.expect("no timer found"); + let t = active.remove(i).unwrap(); + ack.send(t); + } + _ => break + } + } + + // drain the file descriptor + let mut buf = [0]; + fd.inner_read(buf); + } + + -1 if os::errno() == libc::EINTR as int => {} + n => fail!("helper thread failed in select() with error: {} ({})", + n, os::last_os_error()) + } + } +} + +impl Timer { + pub fn new() -> IoResult<Timer> { + timer_helper::boot(helper); + + static mut ID: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT; + let id = unsafe { ID.fetch_add(1, atomics::Relaxed) }; + Ok(Timer { + id: id, + inner: Some(~Inner { + chan: None, + interval: 0, + target: 0, + repeat: false, + id: id, + }) + }) + } + + pub fn sleep(ms: u64) { + unsafe { libc::usleep((ms * 1000) as libc::c_uint); } + } + + fn inner(&mut self) -> ~Inner { + match self.inner.take() { + Some(i) => i, + None => { + let (p, c) = Chan::new(); + timer_helper::send(RemoveTimer(self.id, c)); + p.recv() + } + } + } +} + +impl rtio::RtioTimer for Timer { + fn sleep(&mut self, msecs: u64) { + let mut inner = self.inner(); + inner.chan = None; // cancel any previous request + self.inner = Some(inner); + + Timer::sleep(msecs); + } + + fn oneshot(&mut self, msecs: u64) -> Port<()> { + let now = now(); + let mut inner = self.inner(); + + let (p, c) = Chan::new(); + inner.repeat = false; + inner.chan = Some(c); + inner.interval = msecs; + inner.target = now + msecs; + + timer_helper::send(NewTimer(inner)); + return p; + } + + fn period(&mut self, msecs: u64) -> Port<()> { + let now = now(); + let mut inner = self.inner(); + + let (p, c) = Chan::new(); + inner.repeat = true; + inner.chan = Some(c); + inner.interval = msecs; + inner.target = now + msecs; + + timer_helper::send(NewTimer(inner)); + return p; + } +} + +impl Drop for Timer { + fn drop(&mut self) { + self.inner = Some(self.inner()); + } +} + +#[cfg(target_os = "macos")] +mod imp { + use std::libc; + + pub static FD_SETSIZE: uint = 1024; + + pub struct fd_set { + fds_bits: [i32, ..(FD_SETSIZE / 32)] + } + + pub fn fd_set(set: &mut fd_set, fd: i32) { + set.fds_bits[fd / 32] |= 1 << (fd % 32); + } + + extern { + pub fn select(nfds: libc::c_int, + readfds: *fd_set, + writefds: *fd_set, + errorfds: *fd_set, + timeout: *libc::timeval) -> libc::c_int; + + pub fn gettimeofday(timeval: *mut libc::timeval, + tzp: *libc::c_void) -> libc::c_int; + } +} + +#[cfg(target_os = "freebsd")] +mod imp { + use std::libc; + + pub static FD_SETSIZE: uint = 1024; + + pub struct fd_set { + fds_bits: [u64, ..(FD_SETSIZE / 64)] + } + + pub fn fd_set(set: &mut fd_set, fd: i32) { + set.fds_bits[fd / 64] |= (1 << (fd % 64)) as u64; + } + + extern { + pub fn select(nfds: libc::c_int, + readfds: *fd_set, + writefds: *fd_set, + errorfds: *fd_set, + timeout: *libc::timeval) -> libc::c_int; + + pub fn gettimeofday(timeval: *mut libc::timeval, + tzp: *libc::c_void) -> libc::c_int; + } +} diff --git a/src/libnative/io/timer_timerfd.rs b/src/libnative/io/timer_timerfd.rs new file mode 100644 index 00000000000..0556b0c2599 --- /dev/null +++ b/src/libnative/io/timer_timerfd.rs @@ -0,0 +1,304 @@ +// 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. + +//! Timers based on timerfd_create(2) +//! +//! On OSes which support timerfd_create, we can use these much more accurate +//! timers over select() + a timeout (see timer_other.rs). This strategy still +//! employs a worker thread which does the waiting on the timer fds (to send +//! messages away). +//! +//! The worker thread in this implementation uses epoll(7) to block. It +//! maintains a working set of *all* native timers in the process, along with a +//! pipe file descriptor used to communicate that there is data available on the +//! incoming channel to the worker thread. Timers send requests to update their +//! timerfd settings to the worker thread (see the comment above 'oneshot' for +//! why). +//! +//! As with timer_other, timers just using sleep() do not use the timerfd at +//! all. They remove the timerfd from the worker thread and then invoke usleep() +//! to block the calling thread. +//! +//! As with timer_other, all units in this file are in units of millseconds. + +use std::comm::Data; +use std::libc; +use std::ptr; +use std::os; +use std::rt::rtio; +use std::hashmap::HashMap; +use std::unstable::intrinsics; + +use io::file::FileDesc; +use io::IoResult; +use io::timer_helper; + +pub struct Timer { + priv fd: FileDesc, + priv on_worker: bool, +} + +pub enum Req { + NewTimer(libc::c_int, Chan<()>, bool, imp::itimerspec), + RemoveTimer(libc::c_int, Chan<()>), + Shutdown, +} + +fn helper(input: libc::c_int, messages: Port<Req>) { + let efd = unsafe { imp::epoll_create(10) }; + let _fd1 = FileDesc::new(input, true); + let _fd2 = FileDesc::new(efd, true); + + fn add(efd: libc::c_int, fd: libc::c_int) { + let event = imp::epoll_event { + events: imp::EPOLLIN as u32, + data: imp::epoll_data_t { fd: fd, pad: 0, } + }; + let ret = unsafe { + imp::epoll_ctl(efd, imp::EPOLL_CTL_ADD, fd, &event) + }; + assert_eq!(ret, 0); + } + fn del(efd: libc::c_int, fd: libc::c_int) { + let event = imp::epoll_event { + events: 0, data: imp::epoll_data_t { fd: 0, pad: 0, } + }; + let ret = unsafe { + imp::epoll_ctl(efd, imp::EPOLL_CTL_DEL, fd, &event) + }; + assert_eq!(ret, 0); + } + + add(efd, input); + let events: [imp::epoll_event, ..16] = unsafe { intrinsics::init() }; + let mut map: HashMap<libc::c_int, (Chan<()>, bool)> = HashMap::new(); + 'outer: loop { + let n = match unsafe { + imp::epoll_wait(efd, events.as_ptr(), + events.len() as libc::c_int, -1) + } { + 0 => fail!("epoll_wait returned immediately!"), + -1 if os::errno() == libc::EINTR as int => { continue } + -1 => fail!("epoll wait failed: {}", os::last_os_error()), + n => n + }; + + let mut incoming = false; + debug!("{} events to process", n); + for event in events.slice_to(n as uint).iter() { + let fd = event.data.fd; + debug!("data on fd {} (input = {})", fd, input); + if fd == input { + let mut buf = [0, ..1]; + // drain the input file descriptor of its input + FileDesc::new(fd, false).inner_read(buf); + incoming = true; + } else { + let mut bits = [0, ..8]; + // drain the timerfd of how many times its fired + // + // XXX: should this perform a send() this number of + // times? + FileDesc::new(fd, false).inner_read(bits); + let remove = { + match map.find(&fd).expect("fd unregistered") { + &(ref c, oneshot) => !c.try_send(()) || oneshot + } + }; + if remove { + map.remove(&fd); + del(efd, fd); + } + } + } + + while incoming { + match messages.try_recv() { + Data(NewTimer(fd, chan, one, timeval)) => { + // acknowledge we have the new channel, we will never send + // another message to the old channel + chan.send(()); + + // If we haven't previously seen the file descriptor, then + // we need to add it to the epoll set. + if map.insert(fd, (chan, one)) { + add(efd, fd); + } + + // Update the timerfd's time value now that we have control + // of the timerfd + let ret = unsafe { + imp::timerfd_settime(fd, 0, &timeval, ptr::null()) + }; + assert_eq!(ret, 0); + } + + Data(RemoveTimer(fd, chan)) => { + if map.remove(&fd) { + del(efd, fd); + } + chan.send(()); + } + + Data(Shutdown) => { + assert!(map.len() == 0); + break 'outer; + } + + _ => break, + } + } + } +} + +impl Timer { + pub fn new() -> IoResult<Timer> { + timer_helper::boot(helper); + match unsafe { imp::timerfd_create(imp::CLOCK_MONOTONIC, 0) } { + -1 => Err(super::last_error()), + n => Ok(Timer { fd: FileDesc::new(n, true), on_worker: false, }), + } + } + + pub fn sleep(ms: u64) { + unsafe { libc::usleep((ms * 1000) as libc::c_uint); } + } + + fn remove(&mut self) { + if !self.on_worker { return } + + let (p, c) = Chan::new(); + timer_helper::send(RemoveTimer(self.fd.fd(), c)); + p.recv(); + self.on_worker = false; + } +} + +impl rtio::RtioTimer for Timer { + fn sleep(&mut self, msecs: u64) { + self.remove(); + Timer::sleep(msecs); + } + + // Periodic and oneshot channels are updated by updating the settings on the + // corresopnding timerfd. The update is not performed on the thread calling + // oneshot or period, but rather the helper epoll thread. The reason for + // this is to avoid losing messages and avoid leaking messages across ports. + // + // By updating the timerfd on the helper thread, we're guaranteed that all + // messages for a particular setting of the timer will be received by the + // new channel/port pair rather than leaking old messages onto the new port + // or leaking new messages onto the old port. + // + // We also wait for the remote thread to actually receive the new settings + // before returning to guarantee the invariant that when oneshot() and + // period() return that the old port will never receive any more messages. + + fn oneshot(&mut self, msecs: u64) -> Port<()> { + let (p, c) = Chan::new(); + + let new_value = imp::itimerspec { + it_interval: imp::timespec { tv_sec: 0, tv_nsec: 0 }, + it_value: imp::timespec { + tv_sec: (msecs / 1000) as libc::time_t, + tv_nsec: ((msecs % 1000) * 1000000) as libc::c_long, + } + }; + timer_helper::send(NewTimer(self.fd.fd(), c, true, new_value)); + p.recv(); + self.on_worker = true; + + return p; + } + + fn period(&mut self, msecs: u64) -> Port<()> { + let (p, c) = Chan::new(); + + let spec = imp::timespec { + tv_sec: (msecs / 1000) as libc::time_t, + tv_nsec: ((msecs % 1000) * 1000000) as libc::c_long, + }; + let new_value = imp::itimerspec { it_interval: spec, it_value: spec, }; + timer_helper::send(NewTimer(self.fd.fd(), c, false, new_value)); + p.recv(); + self.on_worker = true; + + return p; + } +} + +impl Drop for Timer { + fn drop(&mut self) { + // When the timerfd file descriptor is closed, it will be automatically + // removed from the epoll set of the worker thread, but we want to make + // sure that the associated channel is also removed from the worker's + // hash map. + self.remove(); + } +} + +#[allow(dead_code)] +mod imp { + use std::libc; + + pub static CLOCK_MONOTONIC: libc::c_int = 1; + pub static EPOLL_CTL_ADD: libc::c_int = 1; + pub static EPOLL_CTL_DEL: libc::c_int = 2; + pub static EPOLL_CTL_MOD: libc::c_int = 3; + pub static EPOLLIN: libc::c_int = 0x001; + pub static EPOLLOUT: libc::c_int = 0x004; + pub static EPOLLPRI: libc::c_int = 0x002; + pub static EPOLLERR: libc::c_int = 0x008; + pub static EPOLLRDHUP: libc::c_int = 0x2000; + pub static EPOLLET: libc::c_int = 1 << 31; + pub static EPOLLHUP: libc::c_int = 0x010; + pub static EPOLLONESHOT: libc::c_int = 1 << 30; + + pub struct epoll_event { + events: u32, + data: epoll_data_t, + } + + pub struct epoll_data_t { + fd: i32, + pad: u32, + } + + pub struct timespec { + tv_sec: libc::time_t, + tv_nsec: libc::c_long, + } + + pub struct itimerspec { + it_interval: timespec, + it_value: timespec, + } + + extern { + pub fn timerfd_create(clockid: libc::c_int, + flags: libc::c_int) -> libc::c_int; + pub fn timerfd_settime(fd: libc::c_int, + flags: libc::c_int, + new_value: *itimerspec, + old_value: *itimerspec) -> libc::c_int; + pub fn timerfd_gettime(fd: libc::c_int, + curr_value: *itimerspec) -> libc::c_int; + + pub fn epoll_create(size: libc::c_int) -> libc::c_int; + pub fn epoll_ctl(epfd: libc::c_int, + op: libc::c_int, + fd: libc::c_int, + event: *epoll_event) -> libc::c_int; + pub fn epoll_wait(epfd: libc::c_int, + events: *epoll_event, + maxevents: libc::c_int, + timeout: libc::c_int) -> libc::c_int; + } +} diff --git a/src/libnative/io/timer_win32.rs b/src/libnative/io/timer_win32.rs new file mode 100644 index 00000000000..e359d99eedf --- /dev/null +++ b/src/libnative/io/timer_win32.rs @@ -0,0 +1,203 @@ +// 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. + +//! Timers based on win32 WaitableTimers +//! +//! This implementation is meant to be used solely on windows. As with other +//! implementations, there is a worker thread which is doing all the waiting on +//! a large number of timers for all active timers in the system. This worker +//! thread uses the select() equivalent, WaitForMultipleObjects. One of the +//! objects being waited on is a signal into the worker thread to notify that +//! the incoming channel should be looked at. +//! +//! Other than that, the implementation is pretty straightforward in terms of +//! the other two implementations of timers with nothing *that* new showing up. + +use std::comm::Data; +use std::libc; +use std::ptr; +use std::rt::rtio; + +use io::timer_helper; +use io::IoResult; + +pub struct Timer { + priv obj: libc::HANDLE, + priv on_worker: bool, +} + +pub enum Req { + NewTimer(libc::HANDLE, Chan<()>, bool), + RemoveTimer(libc::HANDLE, Chan<()>), + Shutdown, +} + +fn helper(input: libc::HANDLE, messages: Port<Req>) { + let mut objs = ~[input]; + let mut chans = ~[]; + + 'outer: loop { + let idx = unsafe { + imp::WaitForMultipleObjects(objs.len() as libc::DWORD, + objs.as_ptr(), + 0 as libc::BOOL, + libc::INFINITE) + }; + + if idx == 0 { + loop { + match messages.try_recv() { + Data(NewTimer(obj, c, one)) => { + objs.push(obj); + chans.push((c, one)); + } + Data(RemoveTimer(obj, c)) => { + c.send(()); + match objs.iter().position(|&o| o == obj) { + Some(i) => { + objs.remove(i); + chans.remove(i - 1); + } + None => {} + } + } + Data(Shutdown) => { + assert_eq!(objs.len(), 1); + assert_eq!(chans.len(), 0); + break 'outer; + } + _ => break + } + } + } else { + let remove = { + match &chans[idx - 1] { + &(ref c, oneshot) => !c.try_send(()) || oneshot + } + }; + if remove { + objs.remove(idx as uint); + chans.remove(idx as uint - 1); + } + } + } +} + +impl Timer { + pub fn new() -> IoResult<Timer> { + timer_helper::boot(helper); + + let obj = unsafe { + imp::CreateWaitableTimerA(ptr::mut_null(), 0, ptr::null()) + }; + if obj.is_null() { + Err(super::last_error()) + } else { + Ok(Timer { obj: obj, on_worker: false, }) + } + } + + pub fn sleep(ms: u64) { + use std::rt::rtio::RtioTimer; + let mut t = Timer::new().ok().expect("must allocate a timer!"); + t.sleep(ms); + } + + fn remove(&mut self) { + if !self.on_worker { return } + + let (p, c) = Chan::new(); + timer_helper::send(RemoveTimer(self.obj, c)); + p.recv(); + + self.on_worker = false; + } +} + +impl rtio::RtioTimer for Timer { + fn sleep(&mut self, msecs: u64) { + self.remove(); + + // there are 10^6 nanoseconds in a millisecond, and the parameter is in + // 100ns intervals, so we multiply by 10^4. + let due = -(msecs * 10000) as libc::LARGE_INTEGER; + assert_eq!(unsafe { + imp::SetWaitableTimer(self.obj, &due, 0, ptr::null(), + ptr::mut_null(), 0) + }, 1); + + unsafe { imp::WaitForSingleObject(self.obj, libc::INFINITE); } + } + + fn oneshot(&mut self, msecs: u64) -> Port<()> { + self.remove(); + let (p, c) = Chan::new(); + + // see above for the calculation + let due = -(msecs * 10000) as libc::LARGE_INTEGER; + assert_eq!(unsafe { + imp::SetWaitableTimer(self.obj, &due, 0, ptr::null(), + ptr::mut_null(), 0) + }, 1); + + timer_helper::send(NewTimer(self.obj, c, true)); + self.on_worker = true; + return p; + } + + fn period(&mut self, msecs: u64) -> Port<()> { + self.remove(); + let (p, c) = Chan::new(); + + // see above for the calculation + let due = -(msecs * 10000) as libc::LARGE_INTEGER; + assert_eq!(unsafe { + imp::SetWaitableTimer(self.obj, &due, msecs as libc::LONG, + ptr::null(), ptr::mut_null(), 0) + }, 1); + + timer_helper::send(NewTimer(self.obj, c, false)); + self.on_worker = true; + + return p; + } +} + +impl Drop for Timer { + fn drop(&mut self) { + self.remove(); + unsafe { libc::CloseHandle(self.obj); } + } +} + +mod imp { + use std::libc::{LPSECURITY_ATTRIBUTES, BOOL, LPCSTR, HANDLE, LARGE_INTEGER, + LONG, LPVOID, DWORD, c_void}; + + pub type PTIMERAPCROUTINE = *c_void; + + extern "system" { + pub fn CreateWaitableTimerA(lpTimerAttributes: LPSECURITY_ATTRIBUTES, + bManualReset: BOOL, + lpTimerName: LPCSTR) -> HANDLE; + pub fn SetWaitableTimer(hTimer: HANDLE, + pDueTime: *LARGE_INTEGER, + lPeriod: LONG, + pfnCompletionRoutine: PTIMERAPCROUTINE, + lpArgToCompletionRoutine: LPVOID, + fResume: BOOL) -> BOOL; + pub fn WaitForMultipleObjects(nCount: DWORD, + lpHandles: *HANDLE, + bWaitAll: BOOL, + dwMilliseconds: DWORD) -> DWORD; + pub fn WaitForSingleObject(hHandle: HANDLE, + dwMilliseconds: DWORD) -> DWORD; + } +} diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 9cc12caa478..301a49d8aec 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -1134,7 +1134,7 @@ pub fn build_output_filenames(input: &Input, pub fn early_error(emitter: &diagnostic::Emitter, msg: &str) -> ! { emitter.emit(None, msg, diagnostic::Fatal); - fail!(); + fail!(diagnostic::FatalError); } pub fn list_metadata(sess: Session, path: &Path, out: &mut io::Writer) { diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 75094bc8084..42b716e8cdf 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -250,6 +250,9 @@ impl Session_ { pub fn span_note(&self, sp: Span, msg: &str) { self.span_diagnostic.span_note(sp, msg) } + pub fn span_end_note(&self, sp: Span, msg: &str) { + self.span_diagnostic.span_end_note(sp, msg) + } pub fn note(&self, msg: &str) { self.span_diagnostic.handler().note(msg) } diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index c259fa6a618..3693b00951b 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -1836,7 +1836,7 @@ impl TypeNames { unsafe { let s = llvm::LLVMTypeToString(ty.to_ref()); let ret = from_c_str(s); - free(s as *c_void); + free(s as *mut c_void); ret } } @@ -1850,7 +1850,7 @@ impl TypeNames { unsafe { let s = llvm::LLVMValueToString(val); let ret = from_c_str(s); - free(s as *c_void); + free(s as *mut c_void); ret } } diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 3985527232c..8d5be0cfb82 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -211,17 +211,14 @@ pub fn get_field_type(tcx: ty::ctxt, class_id: ast::DefId, let cstore = tcx.cstore; let cdata = cstore.get_crate_data(class_id.crate); let all_items = reader::get_doc(reader::Doc(cdata.data()), tag_items); - debug!("Looking up {:?}", class_id); let class_doc = expect(tcx.diag, decoder::maybe_find_item(class_id.node, all_items), || format!("get_field_type: class ID {:?} not found", class_id) ); - debug!("looking up {:?} : {:?}", def, class_doc); let the_field = expect(tcx.diag, decoder::maybe_find_item(def.node, class_doc), || format!("get_field_type: in class {:?}, field ID {:?} not found", class_id, def) ); - debug!("got field data {:?}", the_field); let ty = decoder::item_type(def, the_field, tcx, cdata); ty::ty_param_bounds_and_ty { generics: ty::Generics {type_param_defs: @~[], diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index fe9371af1fe..0fd92079489 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -231,34 +231,47 @@ impl<'a> CheckLoanCtxt<'a> { if restr.loan_path != loan2.loan_path { continue; } match (new_loan.mutbl, old_loan.mutbl) { - (MutableMutability, MutableMutability) => { + (_, MutableMutability) => { + let var = self.bccx.loan_path_to_str(new_loan.loan_path); self.bccx.span_err( new_loan.span, - format!("cannot borrow `{}` as mutable \ - more than once at a time", - self.bccx.loan_path_to_str(new_loan.loan_path))); + format!("cannot borrow `{}` because it is already \ + borrowed as mutable", var)); self.bccx.span_note( old_loan.span, - format!("previous borrow of `{}` as mutable occurs here", - self.bccx.loan_path_to_str(new_loan.loan_path))); - return false; + format!("previous borrow of `{0}` as mutable occurs \ + here; the mutable borrow prevents subsequent \ + moves, borrows, or modification of `{0}` \ + until the borrow ends", var)); } - _ => { + (_, mutability) => { self.bccx.span_err( new_loan.span, format!("cannot borrow `{}` as {} because \ - it is also borrowed as {}", + it is already borrowed as {}", self.bccx.loan_path_to_str(new_loan.loan_path), self.bccx.mut_to_str(new_loan.mutbl), self.bccx.mut_to_str(old_loan.mutbl))); - self.bccx.span_note( - old_loan.span, - format!("previous borrow of `{}` occurs here", - self.bccx.loan_path_to_str(new_loan.loan_path))); - return false; + + let var = self.bccx.loan_path_to_str(new_loan.loan_path); + let mut note = format!("previous borrow of `{}` occurs \ + here", var); + if mutability == ImmutableMutability { + note.push_str(format!("; the immutable borrow prevents \ + subsequent moves or mutable + borrows of `{}` until the + borrow ends", var)); + } + self.bccx.span_note(old_loan.span, note); } } + + let old_loan_span = ast_map::node_span(self.tcx().items, + old_loan.kill_scope); + self.bccx.span_end_note(old_loan_span, + "previous borrow ends here"); + return false; } true diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 74845878907..f1cccab1239 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -631,6 +631,10 @@ impl BorrowckCtxt { self.tcx.sess.span_note(s, m); } + pub fn span_end_note(&self, s: Span, m: &str) { + self.tcx.sess.span_end_note(s, m); + } + pub fn bckerr_to_str(&self, err: BckError) -> ~str { match err.code { err_mutbl(lk) => { diff --git a/src/librustc/middle/trans/cleanup.rs b/src/librustc/middle/trans/cleanup.rs index 1f0e99de264..020b840e5b2 100644 --- a/src/librustc/middle/trans/cleanup.rs +++ b/src/librustc/middle/trans/cleanup.rs @@ -203,7 +203,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> { */ let scopes = self.scopes.borrow(); - for scope in scopes.get().iter().invert() { + for scope in scopes.get().iter().rev() { match scope.kind { LoopScopeKind(id, _) => { return id; @@ -325,7 +325,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> { cleanup_scope); let mut scopes = self.scopes.borrow_mut(); - for scope in scopes.get().mut_iter().invert() { + for scope in scopes.get().mut_iter().rev() { if scope.kind.is_ast_with_id(cleanup_scope) { scope.cleanups.push(cleanup); scope.clear_cached_exits(); @@ -368,7 +368,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> { */ let scopes = self.scopes.borrow(); - scopes.get().iter().invert().any(|s| s.needs_invoke()) + scopes.get().iter().rev().any(|s| s.needs_invoke()) } fn get_landing_pad(&self) -> BasicBlockRef { @@ -415,7 +415,7 @@ impl<'a> CleanupHelperMethods<'a> for FunctionContext<'a> { * Returns the id of the current top-most AST scope, if any. */ let scopes = self.scopes.borrow(); - for scope in scopes.get().iter().invert() { + for scope in scopes.get().iter().rev() { match scope.kind { CustomScopeKind | LoopScopeKind(..) => {} AstScopeKind(i) => { @@ -428,7 +428,7 @@ impl<'a> CleanupHelperMethods<'a> for FunctionContext<'a> { fn top_nonempty_cleanup_scope(&self) -> Option<uint> { let scopes = self.scopes.borrow(); - scopes.get().iter().invert().position(|s| !s.cleanups.is_empty()) + scopes.get().iter().rev().position(|s| !s.cleanups.is_empty()) } fn is_valid_to_pop_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool { @@ -450,7 +450,7 @@ impl<'a> CleanupHelperMethods<'a> for FunctionContext<'a> { let mut bcx = bcx; if !bcx.unreachable.get() { - for cleanup in scope.cleanups.iter().invert() { + for cleanup in scope.cleanups.iter().rev() { bcx = cleanup.trans(bcx); } } @@ -619,7 +619,7 @@ impl<'a> CleanupHelperMethods<'a> for FunctionContext<'a> { debug!("generating cleanups for {}", name); let bcx_in = self.new_block(label.is_unwind(), name, None); let mut bcx_out = bcx_in; - for cleanup in scope.cleanups.iter().invert() { + for cleanup in scope.cleanups.iter().rev() { if cleanup_is_suitable_for(*cleanup, label) { bcx_out = cleanup.trans(bcx_out); } diff --git a/src/librustpkg/api.rs b/src/librustpkg/api.rs index 19586ac48b0..13d5a117704 100644 --- a/src/librustpkg/api.rs +++ b/src/librustpkg/api.rs @@ -11,11 +11,9 @@ use CtxMethods; use context::*; use crate::*; -use crate_id::*; use package_source::*; use path_util::{platform_library_name, target_build_dir}; use target::*; -use version::Version; use workspace::pkg_parent_workspaces; use workcache_support::*; pub use path_util::default_workspace; @@ -27,6 +25,7 @@ use extra::arc::{Arc,RWArc}; use extra::workcache; use extra::workcache::{Database, FreshnessMap}; use extra::treemap::TreeMap; +use syntax::crateid::CrateId; // A little sad -- duplicated from rustc::back::* #[cfg(target_arch = "arm")] @@ -79,20 +78,19 @@ pub fn new_workcache_context(p: &Path) -> workcache::Context { workcache::Context::new_with_freshness(db, cfg, Arc::new(freshness)) } -pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version, - lib: Path) { - build_lib_with_cfgs(sysroot, root, name, version, lib, ~[]) +pub fn build_lib(sysroot: Path, root: Path, name: ~str, lib: Path) { + build_lib_with_cfgs(sysroot, root, name, lib, ~[]) } -pub fn build_lib_with_cfgs(sysroot: Path, root: Path, name: ~str, - version: Version, lib: Path, cfgs: ~[~str]) { +pub fn build_lib_with_cfgs(sysroot: Path, root: Path, name: ~str, lib: Path, cfgs: ~[~str]) { let cx = default_context(sysroot, root.clone()); + let crate_id: CrateId = from_str(name).expect("valid crate id"); let pkg_src = PkgSrc { source_workspace: root.clone(), build_in_destination: false, destination_workspace: root.clone(), start_dir: root.join_many(["src", name.as_slice()]), - id: CrateId{ version: version, ..CrateId::new(name)}, + id: crate_id, // n.b. This assumes the package only has one crate libs: ~[mk_crate(lib)], mains: ~[], @@ -102,20 +100,19 @@ pub fn build_lib_with_cfgs(sysroot: Path, root: Path, name: ~str, pkg_src.build(&cx, cfgs, []); } -pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version, - main: Path) { - build_exe_with_cfgs(sysroot, root, name, version, main, ~[]) +pub fn build_exe(sysroot: Path, root: Path, name: ~str, main: Path) { + build_exe_with_cfgs(sysroot, root, name, main, ~[]) } -pub fn build_exe_with_cfgs(sysroot: Path, root: Path, name: ~str, - version: Version, main: Path, cfgs: ~[~str]) { +pub fn build_exe_with_cfgs(sysroot: Path, root: Path, name: ~str, main: Path, cfgs: ~[~str]) { let cx = default_context(sysroot, root.clone()); + let crate_id: CrateId = from_str(name).expect("valid crate id"); let pkg_src = PkgSrc { source_workspace: root.clone(), build_in_destination: false, destination_workspace: root.clone(), start_dir: root.join_many(["src", name.as_slice()]), - id: CrateId{ version: version, ..CrateId::new(name)}, + id: crate_id, libs: ~[], // n.b. This assumes the package only has one crate mains: ~[mk_crate(main)], @@ -129,11 +126,10 @@ pub fn build_exe_with_cfgs(sysroot: Path, root: Path, name: ~str, pub fn install_pkg(cx: &BuildContext, workspace: Path, name: ~str, - version: Version, // For now, these inputs are assumed to be inputs to each of the crates more_inputs: ~[(~str, Path)]) { // pairs of Kind and Path - let crateid = CrateId{ version: version, ..CrateId::new(name)}; - cx.install(PkgSrc::new(workspace.clone(), workspace, false, crateid), + let crate_id: CrateId = from_str(name).expect("valid crate id"); + cx.install(PkgSrc::new(workspace.clone(), workspace, false, crate_id), &WhatToBuild{ build_type: Inferred, inputs_to_discover: more_inputs, sources: Everything }); @@ -157,10 +153,10 @@ pub fn build_library_in_workspace(exec: &mut workcache::Exec, let out_name = workspace_build_dir.join_many([package_name.to_str(), platform_library_name(output)]); // make paths absolute - let crateid = CrateId::new(package_name); + let crateid: CrateId = from_str(package_name).expect("valid crate id"); let absolute_paths = paths.map(|s| { let whatever = workspace.join_many([~"src", - crateid.to_str(), + crateid.short_name_with_version(), s.to_owned()]); whatever.as_str().unwrap().to_owned() }); @@ -190,7 +186,7 @@ pub fn my_workspace(context: &Context, package_name: &str) -> Path { use bad_pkg_id = conditions::bad_pkg_id::cond; // (this assumes no particular version is requested) - let crateid = CrateId::new(package_name); + let crateid = from_str(package_name).expect("valid crate id"); let workspaces = pkg_parent_workspaces(context, &crateid); if workspaces.is_empty() { bad_pkg_id.raise((Path::new(package_name), package_name.to_owned())); diff --git a/src/librustpkg/conditions.rs b/src/librustpkg/conditions.rs index 6c38d63a518..d18161d7c4a 100644 --- a/src/librustpkg/conditions.rs +++ b/src/librustpkg/conditions.rs @@ -10,7 +10,7 @@ // Useful conditions -pub use crate_id::CrateId; +pub use syntax::crateid::CrateId; pub use std::io::FileStat; pub use std::io::process::ProcessExit; pub use std::path::Path; diff --git a/src/librustpkg/crate_id.rs b/src/librustpkg/crate_id.rs deleted file mode 100644 index 239abbe546f..00000000000 --- a/src/librustpkg/crate_id.rs +++ /dev/null @@ -1,150 +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 version::{try_getting_version, try_getting_local_version, - Version, NoVersion, ExactRevision}; -use std::hash::Streaming; -use std::hash; -use syntax::crateid; - -/// Path-fragment identifier of a package such as -/// 'github.com/graydon/test'; path must be a relative -/// path with >=1 component. -#[deriving(Clone)] -pub struct CrateId { - /// This is a path, on the local filesystem, referring to where the - /// files for this package live. For example: - /// github.com/mozilla/quux-whatever (it's assumed that if we're - /// working with a package ID of this form, rustpkg has already cloned - /// the sources into a local directory in the RUST_PATH). - path: Path, - /// Short name. This is the path's filestem, but we store it - /// redundantly so as to not call get() everywhere (filestem() returns an - /// option) - /// The short name does not need to be a valid Rust identifier. - /// Users can write: `extern mod foo = "...";` to get around the issue - /// of package IDs whose short names aren't valid Rust identifiers. - short_name: ~str, - /// The requested package version. - version: Version -} - -impl Eq for CrateId { - fn eq(&self, other: &CrateId) -> bool { - self.path == other.path && self.version == other.version - } -} - -impl CrateId { - pub fn new(s: &str) -> CrateId { - use conditions::bad_pkg_id::cond; - - let raw_crateid: Option<crateid::CrateId> = from_str(s); - if raw_crateid.is_none() { - return cond.raise((Path::new(s), ~"bad crateid")) - } - let raw_crateid = raw_crateid.unwrap(); - let crateid::CrateId { path, name, version } = raw_crateid; - let path = Path::new(path); - let given_version = version.map(|v| ExactRevision(v)); - - let version = match given_version { - Some(v) => v, - None => match try_getting_local_version(&path) { - Some(v) => v, - None => match try_getting_version(&path) { - Some(v) => v, - None => NoVersion - } - } - }; - - CrateId { - path: path, - short_name: name, - version: version - } - } - - pub fn hash(&self) -> ~str { - // FIXME (#9639): hash should take a &[u8] so we can hash the real path - self.path.display().with_str(|s| { - let vers = self.version.to_str(); - format!("{}-{}-{}", s, hash(s + vers), vers) - }) - } - - pub fn short_name_with_version(&self) -> ~str { - format!("{}{}", self.short_name, self.version.to_str()) - } - - /// True if the ID has multiple components - pub fn is_complex(&self) -> bool { - self.short_name.as_bytes() != self.path.as_vec() - } - - pub fn prefixes(&self) -> Prefixes { - prefixes(&self.path) - } - - // This is the workcache function name for the *installed* - // binaries for this package (as opposed to the built ones, - // which are per-crate). - pub fn install_tag(&self) -> ~str { - format!("install({})", self.to_str()) - } -} - -pub fn prefixes(p: &Path) -> Prefixes { - Prefixes { - components: p.str_components().map(|x|x.unwrap().to_owned()).to_owned_vec(), - remaining: ~[] - } -} - -struct Prefixes { - priv components: ~[~str], - priv remaining: ~[~str] -} - -impl Iterator<(Path, Path)> for Prefixes { - #[inline] - fn next(&mut self) -> Option<(Path, Path)> { - if self.components.len() <= 1 { - None - } - else { - let last = self.components.pop().unwrap(); - self.remaining.unshift(last); - // converting to str and then back is a little unfortunate - Some((Path::new(self.components.connect("/")), - Path::new(self.remaining.connect("/")))) - } - } -} - -impl ToStr for CrateId { - fn to_str(&self) -> ~str { - // should probably use the filestem and not the whole path - format!("{}-{}", self.path.as_str().unwrap(), self.version.to_str()) - } -} - - -pub fn write<W: Writer>(writer: &mut W, string: &str) { - writer.write(string.as_bytes()); -} - -pub fn hash(data: ~str) -> ~str { - let hasher = &mut hash::default_state(); - write(hasher, data); - hasher.result_str() -} - diff --git a/src/librustpkg/installed_packages.rs b/src/librustpkg/installed_packages.rs index 67ba5d2b8e8..c7900181a77 100644 --- a/src/librustpkg/installed_packages.rs +++ b/src/librustpkg/installed_packages.rs @@ -11,10 +11,10 @@ // Listing installed packages use rustc::metadata::filesearch::rust_path; -use path_util::*; use std::os; use std::io; use std::io::fs; +use syntax::crateid::CrateId; pub fn list_installed_packages(f: |&CrateId| -> bool) -> bool { let workspaces = rust_path(); @@ -28,7 +28,8 @@ pub fn list_installed_packages(f: |&CrateId| -> bool) -> bool { match exec.filestem_str() { None => (), Some(exec_path) => { - if !f(&CrateId::new(exec_path)) { + let crate_id = from_str(exec_path).expect("valid crate id"); + if !f(&crate_id) { return false; } } @@ -50,7 +51,8 @@ pub fn list_installed_packages(f: |&CrateId| -> bool) -> bool { let rel_path = rel_p.join(basename); rel_path.display().with_str(|s| { debug!("Rel name: {}", s); - f(&CrateId::new(s)); + let crate_id = from_str(s).expect("valid crate id"); + f(&crate_id); }); } None => () diff --git a/src/librustpkg/lib.rs b/src/librustpkg/lib.rs index c9db8af0b8a..e5e494e9b5f 100644 --- a/src/librustpkg/lib.rs +++ b/src/librustpkg/lib.rs @@ -33,6 +33,7 @@ use rustc::metadata::filesearch; use rustc::metadata::filesearch::rust_path; use rustc::util::sha2; use syntax::{ast, diagnostic}; +use syntax::crateid::CrateId; use messages::{error, warn, note}; use parse_args::{ParseResult, parse_args}; use path_util::{build_pkg_id_in_workspace, built_test_in_workspace}; @@ -46,7 +47,6 @@ use context::{BuildContext, Trans, Nothing, Pretty, Analysis, LLVMAssemble, LLVMCompileBitcode}; use context::{Command, BuildCmd, CleanCmd, DoCmd, HelpCmd, InfoCmd, InstallCmd, ListCmd, PreferCmd, TestCmd, InitCmd, UninstallCmd, UnpreferCmd}; -use crate_id::CrateId; use package_source::PkgSrc; use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench}; use target::{Main, Tests, MaybeCustom, Inferred, JustOne}; @@ -60,7 +60,6 @@ mod crate; pub mod exit_codes; mod installed_packages; mod messages; -pub mod crate_id; pub mod package_source; mod parse_args; mod path_util; @@ -103,7 +102,7 @@ impl<'a> PkgScript<'a> { workspace: &Path, id: &'a CrateId) -> PkgScript<'a> { // Get the executable name that was invoked - let binary = os::args()[0].to_owned(); + let binary = os::args()[0]; // Build the rustc session data structures to pass // to the compiler debug!("pkgscript parse: {}", sysroot.display()); @@ -163,7 +162,6 @@ impl<'a> PkgScript<'a> { exe.as_str().unwrap().to_owned() } - /// Run the contents of this package script, where <what> /// is the command to pass to it (e.g., "build", "clean", "install") /// Returns a pair of an exit code and list of configs (obtained by @@ -243,9 +241,9 @@ impl CtxMethods for BuildContext { if args.len() < 1 { match cwd_to_workspace() { - None if dir_has_crate_file(&cwd) => { + None if dir_has_crate_file(&cwd) => { // FIXME (#9639): This needs to handle non-utf8 paths - let crateid = CrateId::new(cwd.filename_str().unwrap()); + let crateid = from_str(cwd.filename_str().unwrap()).expect("valid crate id"); let mut pkg_src = PkgSrc::new(cwd, default_workspace(), true, crateid); self.build(&mut pkg_src, what); match pkg_src { @@ -270,7 +268,7 @@ impl CtxMethods for BuildContext { } else { // The package id is presumed to be the first command-line // argument - let crateid = CrateId::new(args[0].clone()); + let crateid = from_str(args[0]).expect("valid crate id"); let mut dest_ws = default_workspace(); each_pkg_parent_workspace(&self.context, &crateid, |workspace| { debug!("found pkg {} in workspace {}, trying to build", @@ -289,6 +287,7 @@ impl CtxMethods for BuildContext { Some((crateid, dest_ws)) } } + fn run(&self, cmd: Command, args: ~[~str]) { let cwd = os::getcwd(); match cmd { @@ -308,7 +307,7 @@ impl CtxMethods for BuildContext { else { // The package id is presumed to be the first command-line // argument - let crateid = CrateId::new(args[0].clone()); + let crateid = from_str(args[0]).expect("valid crate id"); self.clean(&cwd, &crateid); // tjc: should use workspace, not cwd } } @@ -341,7 +340,7 @@ impl CtxMethods for BuildContext { // FIXME (#9639): This needs to handle non-utf8 paths let inferred_crateid = - CrateId::new(cwd.filename_str().unwrap()); + from_str(cwd.filename_str().unwrap()).expect("valid crate id"); self.install(PkgSrc::new(cwd, default_workspace(), true, inferred_crateid), &WhatToBuild::new(MaybeCustom, Everything)); @@ -357,7 +356,7 @@ impl CtxMethods for BuildContext { else { // The package id is presumed to be the first command-line // argument - let crateid = CrateId::new(args[0]); + let crateid = from_str(args[0]).expect("valid crate id"); let workspaces = pkg_parent_workspaces(&self.context, &crateid); debug!("package ID = {}, found it in {:?} workspaces", crateid.to_str(), workspaces.len()); @@ -383,7 +382,7 @@ impl CtxMethods for BuildContext { ListCmd => { println!("Installed packages:"); installed_packages::list_installed_packages(|pkg_id| { - pkg_id.path.display().with_str(|s| println!("{}", s)); + println!("{}", pkg_id.path); true }); } @@ -420,7 +419,7 @@ impl CtxMethods for BuildContext { return usage::uninstall(); } - let crateid = CrateId::new(args[0]); + let crateid = from_str(args[0]).expect("valid crate id"); if !installed_packages::package_is_installed(&crateid) { warn(format!("Package {} doesn't seem to be installed! \ Doing nothing.", args[0])); @@ -458,24 +457,24 @@ impl CtxMethods for BuildContext { let workspace = pkg_src.source_workspace.clone(); let crateid = pkg_src.id.clone(); + let path = crateid.path.as_slice(); debug!("build: workspace = {} (in Rust path? {:?} is git dir? {:?} \ crateid = {} pkgsrc start_dir = {}", workspace.display(), - in_rust_path(&workspace), is_git_dir(&workspace.join(&crateid.path)), + in_rust_path(&workspace), is_git_dir(&workspace.join(path)), crateid.to_str(), pkg_src.start_dir.display()); debug!("build: what to build = {:?}", what_to_build); // If workspace isn't in the RUST_PATH, and it's a git repo, // then clone it into the first entry in RUST_PATH, and repeat - if !in_rust_path(&workspace) && is_git_dir(&workspace.join(&crateid.path)) { + if !in_rust_path(&workspace) && is_git_dir(&workspace.join(path)) { let mut out_dir = default_workspace().join("src"); - out_dir.push(&crateid.path); - let git_result = source_control::safe_git_clone(&workspace.join(&crateid.path), + out_dir.push(path); + let git_result = source_control::safe_git_clone(&workspace.join(path), &crateid.version, &out_dir); match git_result { CheckedOutSources => make_read_only(&out_dir), - // FIXME (#9639): This needs to handle non-utf8 paths - _ => cond.raise((crateid.path.as_str().unwrap().to_owned(), out_dir.clone())) + _ => cond.raise((path.to_owned(), out_dir.clone())) }; let default_ws = default_workspace(); debug!("Calling build recursively with {:?} and {:?}", default_ws.display(), @@ -652,7 +651,8 @@ impl CtxMethods for BuildContext { target_exec.display(), target_lib, maybe_executable, maybe_library); - self.workcache_context.with_prep(id.install_tag(), |prep| { + let install_tag = format!("install({}-{})", id.path, id.version_or_default()); + self.workcache_context.with_prep(install_tag, |prep| { for ee in maybe_executable.iter() { // FIXME (#9639): This needs to handle non-utf8 paths prep.declare_input("binary", diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs index 651d64aa9d3..5ac62c5284e 100644 --- a/src/librustpkg/package_source.rs +++ b/src/librustpkg/package_source.rs @@ -11,7 +11,6 @@ extern mod extra; use target::*; -use crate_id::CrateId; use std::io; use std::io::fs; use std::os; @@ -27,7 +26,7 @@ use workcache_support; use workcache_support::{digest_only_date, digest_file_with_date, crate_tag}; use extra::workcache; use extra::treemap::TreeMap; - +use syntax::crateid::CrateId; use rustc::driver::session; // An enumeration of the unpacked source of a package workspace. @@ -68,12 +67,38 @@ impl ToStr for PkgSrc { } } condition! { - // #6009: should this be pub or not, when #8215 is fixed? build_err: (~str) -> ~str; } -impl PkgSrc { +fn prefixes(p: &Path) -> Prefixes { + Prefixes { + components: p.str_components().map(|x|x.unwrap().to_owned()).to_owned_vec(), + remaining: ~[] + } +} + +struct Prefixes { + priv components: ~[~str], + priv remaining: ~[~str] +} + +impl Iterator<(Path, Path)> for Prefixes { + #[inline] + fn next(&mut self) -> Option<(Path, Path)> { + if self.components.len() <= 1 { + None + } + else { + let last = self.components.pop().unwrap(); + self.remaining.unshift(last); + // converting to str and then back is a little unfortunate + Some((Path::new(self.components.connect("/")), + Path::new(self.remaining.connect("/")))) + } + } +} +impl PkgSrc { pub fn new(mut source_workspace: Path, destination_workspace: Path, use_rust_path_hack: bool, @@ -98,21 +123,22 @@ impl PkgSrc { } else { // We search for sources under both src/ and build/ , because build/ is where // automatically-checked-out sources go. + let path = Path::new(id.path.as_slice()); let mut result = source_workspace.join("src"); - result.push(&id.path.dir_path()); - result.push(format!("{}-{}", id.short_name, id.version.to_str())); + result.push(&path.dir_path()); + result.push(id.short_name_with_version()); to_try.push(result); let mut result = source_workspace.join("src"); - result.push(&id.path); + result.push(&path); to_try.push(result); let mut result = build_dir.join("src"); - result.push(&id.path.dir_path()); - result.push(format!("{}-{}", id.short_name, id.version.to_str())); + result.push(&path.dir_path()); + result.push(id.short_name_with_version()); to_try.push(result.clone()); output_names.push(result); let mut other_result = build_dir.join("src"); - other_result.push(&id.path); + other_result.push(&path); to_try.push(other_result.clone()); output_names.push(other_result); @@ -132,9 +158,10 @@ impl PkgSrc { None => { // See if any of the prefixes of this package ID form a valid package ID // That is, is this a package ID that points into the middle of a workspace? - for (prefix, suffix) in id.prefixes() { - let crate_id = CrateId::new(prefix.as_str().unwrap()); - let path = build_dir.join(&crate_id.path); + for (prefix, suffix) in prefixes(&Path::new(id.path.as_slice())) { + let crate_id: Option<CrateId> = from_str(prefix.as_str().unwrap()); + let crate_id = crate_id.expect("valid crate id"); + let path = build_dir.join(crate_id.path.as_slice()); debug!("in loop: checking if {} is a directory", path.display()); if path.is_dir() { let ps = PkgSrc::new(source_workspace, @@ -163,7 +190,7 @@ impl PkgSrc { } } - }; + } } // Ok, no prefixes work, so try fetching from git @@ -179,11 +206,12 @@ impl PkgSrc { } match ok_d { Some(ref d) => { - if d.is_ancestor_of(&id.path) - || d.is_ancestor_of(&versionize(&id.path, &id.version)) { + let path = Path::new(id.path.as_slice()); + if d.is_ancestor_of(&path) + || d.is_ancestor_of(&versionize(id.path, &id.version)) { // Strip off the package ID source_workspace = d.clone(); - for _ in id.path.components() { + for _ in path.components() { source_workspace.pop(); } // Strip off the src/ part @@ -226,8 +254,7 @@ impl PkgSrc { exist, and couldn't interpret it as a URL fragment")) } } - } - else { + } else { cond.raise((id.clone(), ~"supplied path for package dir does not \ exist, and couldn't interpret it as a URL fragment")) @@ -268,26 +295,27 @@ impl PkgSrc { use conditions::git_checkout_failed::cond; let cwd = os::getcwd(); + let path = Path::new(crateid.path.as_slice()); debug!("Checking whether {} (path = {}) exists locally. Cwd = {}, does it? {:?}", - crateid.to_str(), crateid.path.display(), + crateid.to_str(), crateid.path, cwd.display(), - crateid.path.exists()); + path.exists()); - match safe_git_clone(&crateid.path, &crateid.version, local) { + match safe_git_clone(&path, &crateid.version, local) { CheckedOutSources => { make_read_only(local); Some(local.clone()) } DirToUse(clone_target) => { - if crateid.path.components().nth(1).is_none() { + if path.components().nth(1).is_none() { // If a non-URL, don't bother trying to fetch return None; } // FIXME (#9639): This needs to handle non-utf8 paths - let url = format!("https://{}", crateid.path.as_str().unwrap()); + let url = format!("https://{}", path.as_str().unwrap()); debug!("Fetching package: git clone {} {} [version={}]", - url, clone_target.display(), crateid.version.to_str()); + url, clone_target.display(), crateid.version_or_default()); let mut failed = false; @@ -345,7 +373,7 @@ impl PkgSrc { use conditions::missing_pkg_files::cond; let prefix = self.start_dir.components().len(); - debug!("Matching against {}", self.id.short_name); + debug!("Matching against {}", self.id.name); for pth in fs::walk_dir(&self.start_dir) { let maybe_known_crate_set = match pth.filename_str() { Some(filename) if filter(filename) => match filename { diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index 3c91e660784..a0d49e7565f 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -12,19 +12,20 @@ #[allow(dead_code)]; -pub use crate_id::CrateId; pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install}; -pub use version::{Version, ExactRevision, NoVersion, split_version, split_version_general, - try_parsing_version}; +pub use version::{Version, split_version_general}; pub use rustc::metadata::filesearch::rust_path; -use rustc::metadata::filesearch::{libdir, relative_target_lib_path}; -use rustc::driver::driver::host_triple; use std::libc; use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use std::os; use std::io; use std::io::fs; +use extra::hex::ToHex; +use syntax::crateid::CrateId; +use rustc::util::sha2::{Digest, Sha256}; +use rustc::metadata::filesearch::{libdir, relative_target_lib_path}; +use rustc::driver::driver::host_triple; use messages::*; pub fn default_workspace() -> Path { @@ -78,14 +79,14 @@ pub fn workspace_contains_crate_id_(crateid: &CrateId, workspace: &Path, let mut found = None; for p in fs::walk_dir(&src_dir) { if p.is_dir() { - if p == src_dir.join(&crateid.path) || { + if p == src_dir.join(crateid.path.as_slice()) || { let pf = p.filename_str(); pf.iter().any(|&g| { match split_version_general(g, '-') { None => false, Some((ref might_match, ref vers)) => { - *might_match == crateid.short_name - && (crateid.version == *vers || crateid.version == NoVersion) + *might_match == crateid.name + && (crateid.version == *vers || crateid.version == None) } } }) @@ -173,151 +174,63 @@ fn output_in_workspace(crateid: &CrateId, workspace: &Path, what: OutputType) -> /// Figure out what the library name for <crateid> in <workspace>'s build /// directory is, and if the file exists, return it. pub fn built_library_in_workspace(crateid: &CrateId, workspace: &Path) -> Option<Path> { - library_in_workspace(&crateid.path, crateid.short_name, Build, workspace, "build", - &crateid.version) + library_in_workspace(crateid, Build, workspace) } /// Does the actual searching stuff -pub fn installed_library_in_workspace(pkg_path: &Path, workspace: &Path) -> Option<Path> { +pub fn installed_library_in_workspace(crate_id: &CrateId, workspace: &Path) -> Option<Path> { // This could break once we're handling multiple versions better -- I should add a test for it - // FIXME (#9639): This needs to handle non-utf8 paths - match pkg_path.filename_str() { + let path = Path::new(crate_id.path.as_slice()); + match path.filename_str() { None => None, - Some(short_name) => library_in_workspace(pkg_path, - short_name, - Install, - workspace, - libdir(), - &NoVersion) + Some(_short_name) => library_in_workspace(crate_id, Install, workspace) } } /// `workspace` is used to figure out the directory to search. -/// `short_name` is taken as the link name of the library. -pub fn library_in_workspace(path: &Path, short_name: &str, where: Target, - workspace: &Path, prefix: &str, version: &Version) -> Option<Path> { +/// `name` is taken as the link name of the library. +pub fn library_in_workspace(crate_id: &CrateId, where: Target, workspace: &Path) -> Option<Path> { debug!("library_in_workspace: checking whether a library named {} exists", - short_name); - - // We don't know what the hash is, so we have to search through the directory - // contents - - debug!("short_name = {} where = {:?} workspace = {} \ - prefix = {}", short_name, where, workspace.display(), prefix); + crate_id.name); let dir_to_search = match where { - Build => target_build_dir(workspace).join(path), + Build => target_build_dir(workspace).join(crate_id.path.as_slice()), Install => target_lib_dir(workspace) }; - library_in(short_name, version, &dir_to_search) + library_in(crate_id, &dir_to_search) } -pub fn system_library(sysroot: &Path, crate_id: &str) -> Option<Path> { - let (lib_name, version) = split_crate_id(crate_id); - library_in(lib_name, &version, &sysroot.join(relative_target_lib_path(host_triple()))) +pub fn system_library(sysroot: &Path, crate_id: &CrateId) -> Option<Path> { + library_in(crate_id, &sysroot.join(relative_target_lib_path(host_triple()))) } -fn library_in(short_name: &str, version: &Version, dir_to_search: &Path) -> Option<Path> { - debug!("Listing directory {}", dir_to_search.display()); - let dir_contents = { - let _guard = io::ignore_io_error(); - fs::readdir(dir_to_search) - }; - debug!("dir has {:?} entries", dir_contents.len()); - - let dll_prefix = format!("{}{}", os::consts::DLL_PREFIX, short_name); - let dll_filetype = os::consts::DLL_EXTENSION; - let rlib_prefix = format!("{}{}", "lib", short_name); - let rlib_filetype = "rlib"; - - debug!("dll_prefix = {} and dll_filetype = {}", dll_prefix, dll_filetype); - debug!("rlib_prefix = {} and rlib_filetype = {}", rlib_prefix, rlib_filetype); - - // Find a filename that matches the pattern: - // (lib_prefix)-hash-(version)(lib_suffix) - let mut libraries = dir_contents.iter().filter(|p| { - let extension = p.extension_str(); - debug!("p = {}, p's extension is {:?}", p.display(), extension); - match extension { - None => false, - Some(ref s) => dll_filetype == *s || rlib_filetype == *s, - } - }); - - let mut result_filename = None; - for p_path in libraries { - // Find a filename that matches the pattern: (lib_prefix)-hash-(version)(lib_suffix) - // and remember what the hash was - let mut f_name = match p_path.filestem_str() { - Some(s) => s, None => continue - }; - // Already checked the filetype above - - // This is complicated because library names and versions can both contain dashes - loop { - if f_name.is_empty() { break; } - match f_name.rfind('-') { - Some(i) => { - debug!("Maybe {} is a version", f_name.slice(i + 1, f_name.len())); - match try_parsing_version(f_name.slice(i + 1, f_name.len())) { - Some(ref found_vers) if version == found_vers => { - match f_name.slice(0, i).rfind('-') { - Some(j) => { - let lib_prefix = match p_path.extension_str() { - Some(ref s) if dll_filetype == *s => &dll_prefix, - _ => &rlib_prefix, - }; - debug!("Maybe {} equals {}", f_name.slice(0, j), *lib_prefix); - if f_name.slice(0, j) == *lib_prefix { - result_filename = Some(p_path.clone()); - } - break; - } - None => break - } - - } - _ => { f_name = f_name.slice(0, i); } - } - } - None => break - } // match - } // loop - } // for - - if result_filename.is_none() { - debug!("warning: library_in_workspace didn't find a library in {} for {}", - dir_to_search.display(), short_name); - } +fn library_in(crate_id: &CrateId, dir_to_search: &Path) -> Option<Path> { + let mut hasher = Sha256::new(); + hasher.reset(); + hasher.input_str(crate_id.to_str()); + let hash = hasher.result_bytes().to_hex(); + let hash = hash.slice_chars(0, 8); + + let lib_name = format!("{}-{}-{}", crate_id.name, hash, crate_id.version_or_default()); + let filenames = [ + format!("{}{}.{}", "lib", lib_name, "rlib"), + format!("{}{}{}", os::consts::DLL_PREFIX, lib_name, os::consts::DLL_SUFFIX), + ]; - // Return the filename that matches, which we now know exists - // (if result_filename != None) - let abs_path = result_filename.map(|result_filename| { - let absolute_path = dir_to_search.join(&result_filename); - debug!("result_filename = {}", absolute_path.display()); - absolute_path - }); - - abs_path -} - -fn split_crate_id<'a>(crate_id: &'a str) -> (&'a str, Version) { - match split_version(crate_id) { - Some((name, vers)) => - match vers { - ExactRevision(ref v) => match v.find('-') { - Some(pos) => (name, ExactRevision(v.slice(0, pos).to_owned())), - None => (name, ExactRevision(v.to_owned())) - }, - _ => (name, vers) - }, - None => (crate_id, NoVersion) + for filename in filenames.iter() { + debug!("filename = {}", filename.as_slice()); + let path = dir_to_search.join(filename.as_slice()); + if path.exists() { + debug!("found: {}", path.display()); + return Some(path); + } } + debug!("warning: library_in_workspace didn't find a library in {} for {}", + dir_to_search.display(), crate_id.to_str()); + return None; } - - /// Returns the executable that would be installed for <crateid> /// in <workspace> /// As a side effect, creates the bin-dir if it doesn't exist @@ -366,7 +279,7 @@ fn target_file_in_workspace(crateid: &CrateId, workspace: &Path, // Artifacts in the build directory live in a package-ID-specific subdirectory, // but installed ones don't. let result = match (where, what) { - (Build, _) => target_build_dir(workspace).join(&crateid.path), + (Build, _) => target_build_dir(workspace).join(crateid.path.as_slice()), (Install, Lib) => target_lib_dir(workspace), (Install, _) => target_bin_dir(workspace) }; @@ -382,7 +295,7 @@ fn target_file_in_workspace(crateid: &CrateId, workspace: &Path, /// Creates it if it doesn't exist. pub fn build_pkg_id_in_workspace(crateid: &CrateId, workspace: &Path) -> Path { let mut result = target_build_dir(workspace); - result.push(&crateid.path); + result.push(crateid.path.as_slice()); debug!("Creating build dir {} for package id {}", result.display(), crateid.to_str()); fs::mkdir_recursive(&result, io::UserRWX); @@ -392,25 +305,24 @@ pub fn build_pkg_id_in_workspace(crateid: &CrateId, workspace: &Path) -> Path { /// Return the output file for a given directory name, /// given whether we're building a library and whether we're building tests pub fn mk_output_path(what: OutputType, where: Target, - pkg_id: &CrateId, workspace: Path) -> Path { - let short_name_with_version = format!("{}-{}", pkg_id.short_name, - pkg_id.version.to_str()); + crate_id: &CrateId, workspace: Path) -> Path { + let short_name_with_version = crate_id.short_name_with_version(); // Not local_path.dir_path()! For package foo/bar/blat/, we want // the executable blat-0.5 to live under blat/ let dir = match where { // If we're installing, it just goes under <workspace>... Install => workspace, // and if we're just building, it goes in a package-specific subdir - Build => workspace.join(&pkg_id.path) + Build => workspace.join(crate_id.path.as_slice()) }; - debug!("[{:?}:{:?}] mk_output_path: short_name = {}, path = {}", what, where, - if what == Lib { short_name_with_version.clone() } else { pkg_id.short_name.clone() }, + debug!("[{:?}:{:?}] mk_output_path: name = {}, path = {}", what, where, + if what == Lib { short_name_with_version.clone() } else { crate_id.name.clone() }, dir.display()); let mut output_path = match what { // this code is duplicated from elsewhere; fix this Lib => dir.join(os::dll_filename(short_name_with_version)), // executable names *aren't* versioned - _ => dir.join(format!("{}{}{}", pkg_id.short_name, + _ => dir.join(format!("{}{}{}", crate_id.name, match what { Test => "test", Bench => "bench", @@ -457,11 +369,12 @@ fn dir_has_file(dir: &Path, file: &str) -> bool { pub fn find_dir_using_rust_path_hack(p: &CrateId) -> Option<Path> { let rp = rust_path(); + let path = Path::new(p.path.as_slice()); for dir in rp.iter() { // Require that the parent directory match the package ID // Note that this only matches if the package ID being searched for // has a name that's a single component - if dir.ends_with_path(&p.path) || dir.ends_with_path(&versionize(&p.path, &p.version)) { + if dir.ends_with_path(&path) || dir.ends_with_path(&versionize(p.path, &p.version)) { debug!("In find_dir_using_rust_path_hack: checking dir {}", dir.display()); if dir_has_crate_file(dir) { debug!("Did find id {} in dir {}", p.to_str(), dir.display()); @@ -483,11 +396,12 @@ pub fn user_set_rust_path() -> bool { } /// Append the version string onto the end of the path's filename -pub fn versionize(p: &Path, v: &Version) -> Path { +pub fn versionize(p: &str, v: &Version) -> Path { + let p = Path::new(p); let q = p.filename().expect("path is a directory"); let mut q = q.to_owned(); q.push('-' as u8); - let vs = v.to_str(); + let vs = match v { &Some(ref s) => s.to_owned(), &None => ~"0.0" }; q.push_all(vs.as_bytes()); p.with_filename(q) } diff --git a/src/librustpkg/source_control.rs b/src/librustpkg/source_control.rs index 4b7aaf7e340..2346749feb5 100644 --- a/src/librustpkg/source_control.rs +++ b/src/librustpkg/source_control.rs @@ -14,7 +14,6 @@ use std::{run, str}; use std::run::{ProcessOutput, ProcessOptions, Process}; use std::io::fs; use extra::tempfile::TempDir; -use version::*; use path_util::chmod_read_only; /// Attempts to clone `source`, a local git repository, into `target`, a local @@ -22,7 +21,7 @@ use path_util::chmod_read_only; /// Returns `DirToUse(p)` if the clone fails, where `p` is a newly created temporary /// directory (that the callee may use, for example, to check out remote sources into). /// Returns `CheckedOutSources` if the clone succeeded. -pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult { +pub fn safe_git_clone(source: &Path, v: &Option<~str>, target: &Path) -> CloneResult { if source.exists() { debug!("{} exists locally! Cloning it into {}", source.display(), target.display()); @@ -44,7 +43,7 @@ pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult } else { match v { - &ExactRevision(ref s) => { + &Some(ref s) => { let git_dir = target.join(".git"); debug!("`Running: git --work-tree={} --git-dir={} checkout {}", *s, target.display(), git_dir.display()); @@ -65,7 +64,7 @@ pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult } else { // Check that no version was specified. There's no reason to not handle the // case where a version was requested, but I haven't implemented it. - assert!(*v == NoVersion); + assert!(*v == None); let git_dir = target.join(".git"); debug!("Running: git --work-tree={} --git-dir={} pull --no-edit {}", target.display(), git_dir.display(), source.display()); @@ -106,7 +105,7 @@ pub fn make_read_only(target: &Path) { } /// Source can be either a URL or a local file path. -pub fn git_clone_url(source: &str, target: &Path, v: &Version) { +pub fn git_clone_url(source: &str, target: &Path, v: &Option<~str>) { use conditions::git_checkout_failed::cond; // FIXME (#9639): This needs to handle non-utf8 paths @@ -120,7 +119,7 @@ pub fn git_clone_url(source: &str, target: &Path, v: &Version) { } else { match v { - &ExactRevision(ref s) | &Tagged(ref s) => { + &Some(ref s) => { let opt_outp = process_output_in_cwd("git", [~"checkout", s.to_owned()], target); let outp = opt_outp.expect("Failed to exec `git`"); diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index c0b4a246d35..bf8ec1e738c 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -20,13 +20,12 @@ use extra::arc::Arc; use extra::arc::RWArc; use extra::tempfile::TempDir; use extra::workcache; -use extra::workcache::{Database}; +use extra::workcache::Database; use extra::treemap::TreeMap; use extra::getopts::groups::getopts; use std::run::ProcessOutput; use installed_packages::list_installed_packages; -use crate_id::{CrateId}; -use version::{ExactRevision, NoVersion, Version}; +use syntax::crateid::CrateId; use path_util::{target_executable_in_workspace, target_test_in_workspace, target_bench_in_workspace, make_dir_rwx, library_in_workspace, installed_library_in_workspace, @@ -59,19 +58,18 @@ fn fake_ctxt(sysroot: Path, workspace: &Path) -> BuildContext { } fn fake_pkg() -> CrateId { - let sn = ~"bogus"; CrateId { - path: Path::new(sn.as_slice()), - short_name: sn, - version: NoVersion + path: ~"bogus", + name: ~"bogus", + version: None } } fn git_repo_pkg() -> CrateId { CrateId { - path: Path::new("mockgithub.com/catamorphism/test-pkg"), - short_name: ~"test-pkg", - version: NoVersion + path: ~"mockgithub.com/catamorphism/test-pkg", + name: ~"test-pkg", + version: None } } @@ -88,28 +86,24 @@ fn mk_emptier_workspace(tag: &str) -> TempDir { workspace } -fn mk_empty_workspace(short_name: &Path, version: &Version, tag: &str) -> TempDir { +fn mk_empty_workspace(crate_id: &CrateId, tag: &str) -> TempDir { let workspace_dir = TempDir::new(tag).expect("couldn't create temp dir"); - mk_workspace(workspace_dir.path(), short_name, version); + mk_workspace(workspace_dir.path(), crate_id); workspace_dir } -fn mk_workspace(workspace: &Path, short_name: &Path, version: &Version) -> Path { +fn mk_workspace(workspace: &Path, crate_id: &CrateId) -> Path { // include version number in directory name // FIXME (#9639): This needs to handle non-utf8 paths - let package_dir = workspace.join_many([~"src", format!("{}-{}", - short_name.as_str().unwrap(), version.to_str())]); + let package_dir = workspace.join_many([~"src", crate_id.short_name_with_version()]); fs::mkdir_recursive(&package_dir, io::UserRWX); package_dir } -fn mk_temp_workspace(short_name: &Path, version: &Version) -> (TempDir, Path) { - let workspace_dir = mk_empty_workspace(short_name, version, "temp_workspace"); +fn mk_temp_workspace(crate_id: &CrateId) -> (TempDir, Path) { + let workspace_dir = mk_empty_workspace(crate_id, "temp_workspace"); // FIXME (#9639): This needs to handle non-utf8 paths - let package_dir = workspace_dir.path().join_many([~"src", - format!("{}-{}", - short_name.as_str().unwrap(), - version.to_str())]); + let package_dir = workspace_dir.path().join_many([~"src", crate_id.short_name_with_version()]); debug!("Created {} and does it exist? {:?}", package_dir.display(), package_dir.is_dir()); @@ -278,14 +272,11 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s err_fd: None }).expect(format!("failed to exec `{}`", cmd)); let output = prog.finish_with_output(); - debug!("Output from command {} with args {:?} was {} \\{{}\\}[{:?}]", + debug!("Output from command {} with args {:?} was --- {} \\{{}\\} --- [{:?}]", cmd, args, str::from_utf8(output.output).unwrap(), str::from_utf8(output.error).unwrap(), output.status); if !output.status.success() { - debug!("Command {} {:?} failed with exit code {:?}; its output was --- {} {} ---", - cmd, args, output.status, - str::from_utf8(output.output).unwrap(), str::from_utf8(output.error).unwrap()); Fail(output) } else { @@ -294,7 +285,7 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s } fn create_local_package(crateid: &CrateId) -> TempDir { - let (workspace, parent_dir) = mk_temp_workspace(&crateid.path, &crateid.version); + let (workspace, parent_dir) = mk_temp_workspace(crateid); debug!("Created empty package dir for {}, returning {}", crateid.to_str(), parent_dir.display()); workspace @@ -302,7 +293,7 @@ fn create_local_package(crateid: &CrateId) -> TempDir { fn create_local_package_in(crateid: &CrateId, pkgdir: &Path) -> Path { - let package_dir = pkgdir.join_many([~"src", crateid.to_str()]); + let package_dir = pkgdir.join_many([~"src", crateid.short_name_with_version()]); // Create main, lib, test, and bench files fs::mkdir_recursive(&package_dir, io::UserRWX); @@ -330,11 +321,15 @@ fn create_local_package_with_dep(crateid: &CrateId, subord_crateid: &CrateId) -> let package_dir = create_local_package(crateid); create_local_package_in(subord_crateid, package_dir.path()); // Write a main.rs file into crateid that references subord_crateid - writeFile(&package_dir.path().join_many([~"src", crateid.to_str(), ~"main.rs"]), + writeFile(&package_dir.path().join_many([~"src", + crateid.short_name_with_version(), + ~"main.rs"]), format!("extern mod {};\nfn main() \\{\\}", - subord_crateid.short_name)); + subord_crateid.name)); // Write a lib.rs file into subord_crateid that has something in it - writeFile(&package_dir.path().join_many([~"src", subord_crateid.to_str(), ~"lib.rs"]), + writeFile(&package_dir.path().join_many([~"src", + subord_crateid.short_name_with_version(), + ~"lib.rs"]), "pub fn f() {}"); package_dir } @@ -348,13 +343,13 @@ fn create_local_package_with_custom_build_hook(crateid: &CrateId, } -fn assert_lib_exists(repo: &Path, pkg_path: &Path, v: Version) { - assert!(lib_exists(repo, pkg_path, v)); +fn assert_lib_exists(repo: &Path, crate_id: &CrateId) { + assert!(lib_exists(repo, crate_id)); } -fn lib_exists(repo: &Path, pkg_path: &Path, _v: Version) -> bool { // ??? version? - debug!("assert_lib_exists: repo = {}, pkg_path = {}", repo.display(), pkg_path.display()); - let lib = installed_library_in_workspace(pkg_path, repo); +fn lib_exists(repo: &Path, crate_id: &CrateId) -> bool { + debug!("assert_lib_exists: repo = {}, crate_id = {}", repo.display(), crate_id.to_str()); + let lib = installed_library_in_workspace(crate_id, repo); debug!("assert_lib_exists: checking whether {:?} exists", lib); lib.is_some() && { let libname = lib.get_ref(); @@ -367,19 +362,21 @@ fn assert_executable_exists(repo: &Path, short_name: &str) { } fn executable_exists(repo: &Path, short_name: &str) -> bool { + let crate_id = from_str(short_name).expect("valid crate id"); debug!("executable_exists: repo = {}, short_name = {}", repo.display(), short_name); - let exec = target_executable_in_workspace(&CrateId::new(short_name), repo); + let exec = target_executable_in_workspace(&crate_id, repo); exec.exists() && is_rwx(&exec) } fn test_executable_exists(repo: &Path, short_name: &str) -> bool { + let crate_id = from_str(short_name).expect("valid crate id"); debug!("test_executable_exists: repo = {}, short_name = {}", repo.display(), short_name); - let exec = built_test_in_workspace(&CrateId::new(short_name), repo); + let exec = built_test_in_workspace(&crate_id, repo); exec.map_or(false, |exec| exec.exists() && is_rwx(&exec)) } fn remove_executable_file(p: &CrateId, workspace: &Path) { - let exec = target_executable_in_workspace(&CrateId::new(p.short_name), workspace); + let exec = target_executable_in_workspace(p, workspace); if exec.exists() { fs::unlink(&exec); } @@ -392,7 +389,8 @@ fn assert_built_executable_exists(repo: &Path, short_name: &str) { fn built_executable_exists(repo: &Path, short_name: &str) -> bool { debug!("assert_built_executable_exists: repo = {}, short_name = {}", repo.display(), short_name); - let exec = built_executable_in_workspace(&CrateId::new(short_name), repo); + let crate_id = from_str(short_name).expect("valid crate id"); + let exec = built_executable_in_workspace(&crate_id, repo); exec.is_some() && { let execname = exec.get_ref(); execname.exists() && is_rwx(execname) @@ -400,7 +398,7 @@ fn built_executable_exists(repo: &Path, short_name: &str) -> bool { } fn remove_built_executable_file(p: &CrateId, workspace: &Path) { - let exec = built_executable_in_workspace(&CrateId::new(p.short_name), workspace); + let exec = built_executable_in_workspace(p, workspace); match exec { Some(r) => fs::unlink(&r), None => () @@ -435,7 +433,8 @@ fn assert_built_library_exists(repo: &Path, short_name: &str) { fn built_library_exists(repo: &Path, short_name: &str) -> bool { debug!("assert_built_library_exists: repo = {}, short_name = {}", repo.display(), short_name); - let lib = built_library_in_workspace(&CrateId::new(short_name), repo); + let crate_id = from_str(short_name).expect("valid crate id"); + let lib = built_library_in_workspace(&crate_id, repo); lib.is_some() && { let libname = lib.get_ref(); libname.exists() && is_rwx(libname) @@ -470,18 +469,16 @@ fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~ fn lib_output_file_name(workspace: &Path, short_name: &str) -> Path { debug!("lib_output_file_name: given {} and short name {}", workspace.display(), short_name); - library_in_workspace(&Path::new(short_name), - short_name, + let crate_id = from_str(short_name).expect("valid crate id"); + library_in_workspace(&crate_id, Build, - workspace, - "build", - &NoVersion).expect("lib_output_file_name") + workspace).expect("lib_output_file_name") } #[cfg(target_os = "linux")] fn touch_source_file(workspace: &Path, crateid: &CrateId) { use conditions::bad_path::cond; - let pkg_src_dir = workspace.join_many([~"src", crateid.to_str()]); + let pkg_src_dir = workspace.join_many([~"src", crateid.short_name_with_version()]); let contents = fs::readdir(&pkg_src_dir); for p in contents.iter() { if p.extension_str() == Some("rs") { @@ -501,7 +498,7 @@ fn touch_source_file(workspace: &Path, crateid: &CrateId) { #[cfg(not(target_os = "linux"))] fn touch_source_file(workspace: &Path, crateid: &CrateId) { use conditions::bad_path::cond; - let pkg_src_dir = workspace.join_many([~"src", crateid.to_str()]); + let pkg_src_dir = workspace.join_many([~"src", crateid.short_name_with_version()]); let contents = fs::readdir(&pkg_src_dir); for p in contents.iter() { if p.extension_str() == Some("rs") { @@ -520,7 +517,7 @@ fn touch_source_file(workspace: &Path, crateid: &CrateId) { /// Add a comment at the end fn frob_source_file(workspace: &Path, crateid: &CrateId, filename: &str) { use conditions::bad_path::cond; - let pkg_src_dir = workspace.join_many([~"src", crateid.to_str()]); + let pkg_src_dir = workspace.join_many([~"src", crateid.short_name_with_version()]); let mut maybe_p = None; let maybe_file = pkg_src_dir.join(filename); debug!("Trying to frob {} -- {}", pkg_src_dir.display(), filename); @@ -567,7 +564,7 @@ fn test_install_valid() { let sysroot = test_sysroot(); debug!("sysroot = {}", sysroot.display()); let temp_pkg_id = fake_pkg(); - let (temp_workspace, _pkg_dir) = mk_temp_workspace(&temp_pkg_id.path, &NoVersion); + let (temp_workspace, _pkg_dir) = mk_temp_workspace(&temp_pkg_id); let temp_workspace = temp_workspace.path(); let ctxt = fake_ctxt(sysroot, temp_workspace); debug!("temp_workspace = {}", temp_workspace.display()); @@ -583,7 +580,7 @@ fn test_install_valid() { assert!(exec.exists()); assert!(is_rwx(&exec)); - let lib = installed_library_in_workspace(&temp_pkg_id.path, temp_workspace); + let lib = installed_library_in_workspace(&temp_pkg_id, temp_workspace); debug!("lib = {:?}", lib); assert!(lib.as_ref().map_or(false, |l| l.exists())); assert!(lib.as_ref().map_or(false, |l| is_rwx(l))); @@ -623,9 +620,8 @@ fn test_install_invalid() { #[test] fn test_install_valid_external() { - let temp_pkg_id = CrateId::new("foo"); - let (tempdir, _) = mk_temp_workspace(&temp_pkg_id.path, - &temp_pkg_id.version); + let temp_pkg_id: CrateId = from_str("foo").unwrap(); + let (tempdir, _) = mk_temp_workspace(&temp_pkg_id); let temp_workspace = tempdir.path(); command_line_test([~"install", ~"foo"], temp_workspace); @@ -635,7 +631,7 @@ fn test_install_valid_external() { assert!(exec.exists()); assert!(is_rwx(&exec)); - let lib = installed_library_in_workspace(&temp_pkg_id.path, temp_workspace); + let lib = installed_library_in_workspace(&temp_pkg_id, temp_workspace); debug!("lib = {:?}", lib); assert!(lib.as_ref().map_or(false, |l| l.exists())); assert!(lib.as_ref().map_or(false, |l| is_rwx(l))); @@ -662,7 +658,8 @@ fn test_install_invalid_external() { #[test] fn test_install_git() { let temp_pkg_id = git_repo_pkg(); - let repo = init_git_repo(&temp_pkg_id.path); + let path = Path::new(temp_pkg_id.path.as_slice()); + let repo = init_git_repo(&path); let repo = repo.path(); debug!("repo = {}", repo.display()); let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg"]); @@ -679,10 +676,9 @@ fn test_install_git() { add_git_tag(&repo_subdir, ~"0.1"); // this has the effect of committing the files debug!("test_install_git: calling rustpkg install {} in {}", - temp_pkg_id.path.display(), repo.display()); + temp_pkg_id.path, repo.display()); // should have test, bench, lib, and main - // FIXME (#9639): This needs to handle non-utf8 paths - command_line_test([~"install", temp_pkg_id.path.as_str().unwrap().to_owned()], repo); + command_line_test([~"install", temp_pkg_id.path.to_owned()], repo); let ws = repo.join(".rust"); // Check that all files exist debug!("Checking for files in {}", ws.display()); @@ -693,7 +689,7 @@ fn test_install_git() { let _built_lib = built_library_in_workspace(&temp_pkg_id, &ws).expect("test_install_git: built lib should exist"); - assert_lib_exists(&ws, &temp_pkg_id.path, temp_pkg_id.version.clone()); + assert_lib_exists(&ws, &temp_pkg_id); let built_test = built_test_in_workspace(&temp_pkg_id, &ws).expect("test_install_git: built test should exist"); assert!(built_test.exists()); @@ -711,8 +707,6 @@ fn test_install_git() { #[test] fn test_crate_ids_must_be_relative_path_like() { - use conditions::bad_pkg_id::cond; - /* Okay: - One identifier, with no slashes @@ -724,72 +718,16 @@ fn test_crate_ids_must_be_relative_path_like() { */ - let whatever = CrateId::new("foo"); + let foo: CrateId = from_str("foo").unwrap(); + assert_eq!(~"foo#0.0", foo.to_str()); + let test_pkg: CrateId = from_str("github.com/catamorphism/test-pkg").unwrap(); + assert_eq!(~"github.com/catamorphism/test-pkg#0.0", test_pkg.to_str()); - assert_eq!(~"foo-0.0", whatever.to_str()); - assert!("github.com/catamorphism/test-pkg-0.0" == - CrateId::new("github.com/catamorphism/test-pkg").to_str()); - - cond.trap(|(p, e)| { - assert!(p.filename().is_none()); - assert!("bad crateid" == e); - whatever.clone() - }).inside(|| { - let x = CrateId::new(""); - assert_eq!(~"foo-0.0", x.to_str()); - }); + let x: Option<CrateId> = from_str(""); + assert_eq!(x, None); - cond.trap(|(p, e)| { - let abs = os::make_absolute(&Path::new("foo/bar/quux")); - assert_eq!(p, abs); - assert!("bad crateid" == e); - whatever.clone() - }).inside(|| { - let zp = os::make_absolute(&Path::new("foo/bar/quux")); - // FIXME (#9639): This needs to handle non-utf8 paths - let z = CrateId::new(zp.as_str().unwrap()); - assert_eq!(~"foo-0.0", z.to_str()); - }) -} - -#[test] -fn test_package_version() { - let local_path = "mockgithub.com/catamorphism/test_pkg_version"; - let repo = init_git_repo(&Path::new(local_path)); - let repo = repo.path(); - let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test_pkg_version"]); - debug!("Writing files in: {}", repo_subdir.display()); - fs::mkdir_recursive(&repo_subdir, io::UserRWX); - writeFile(&repo_subdir.join("main.rs"), - "fn main() { let _x = (); }"); - writeFile(&repo_subdir.join("lib.rs"), - "pub fn f() { let _x = (); }"); - writeFile(&repo_subdir.join("test.rs"), - "#[test] pub fn f() { (); }"); - writeFile(&repo_subdir.join("bench.rs"), - "#[bench] pub fn f() { (); }"); - add_git_tag(&repo_subdir, ~"0.4"); - - // It won't pick up the 0.4 version because the dir isn't in the RUST_PATH, but... - let temp_pkg_id = CrateId::new("mockgithub.com/catamorphism/test_pkg_version"); - // This should look at the prefix, clone into a workspace, then build. - command_line_test([~"install", ~"mockgithub.com/catamorphism/test_pkg_version"], - repo); - let ws = repo.join(".rust"); - // we can still match on the filename to make sure it contains the 0.4 version - assert!(match built_library_in_workspace(&temp_pkg_id, - &ws) { - Some(p) => { - let suffix = format!("0.4{}", os::consts::DLL_SUFFIX); - p.as_vec().ends_with(suffix.as_bytes()) - } - None => false - }); - assert!(built_executable_in_workspace(&temp_pkg_id, &ws) - == Some(target_build_dir(&ws).join_many(["mockgithub.com", - "catamorphism", - "test_pkg_version", - "test_pkg_version"]))); + let z: Option<CrateId> = from_str("/foo/bar/quux"); + assert_eq!(z, None); } #[test] @@ -814,7 +752,8 @@ fn test_package_request_version() { command_line_test([~"install", format!("{}\\#0.3", local_path)], repo); - assert!(match installed_library_in_workspace(&Path::new("test_pkg_version"), + let crate_id = from_str(format!("{}\\#0.3", local_path)).unwrap(); + assert!(match installed_library_in_workspace(&crate_id, &repo.join(".rust")) { Some(p) => { debug!("installed: {}", p.display()); @@ -823,7 +762,7 @@ fn test_package_request_version() { } None => false }); - let temp_pkg_id = CrateId::new("mockgithub.com/catamorphism/test_pkg_version#0.3"); + let temp_pkg_id = from_str("mockgithub.com/catamorphism/test_pkg_version#0.3").unwrap(); assert!(target_executable_in_workspace(&temp_pkg_id, &repo.join(".rust")) == repo.join_many([".rust", "bin", "test_pkg_version"])); @@ -858,15 +797,17 @@ fn rustpkg_library_target() { "#[test] pub fn f() { (); }"); writeFile(&package_dir.join("bench.rs"), "#[bench] pub fn f() { (); }"); + add_git_tag(&package_dir, ~"0.0"); - add_git_tag(&package_dir, ~"1.0"); command_line_test([~"install", ~"foo"], foo_repo); - assert_lib_exists(&foo_repo.join(".rust"), &Path::new("foo"), ExactRevision(~"1.0")); + let crate_id: CrateId = from_str("foo").unwrap(); + assert_lib_exists(&foo_repo.join(".rust"), &crate_id); } #[test] fn rustpkg_local_pkg() { - let dir = create_local_package(&CrateId::new("foo")); + let crate_id: CrateId = from_str("foo").unwrap(); + let dir = create_local_package(&crate_id); command_line_test([~"install", ~"foo"], dir.path()); assert_executable_exists(dir.path(), "foo"); } @@ -874,7 +815,8 @@ fn rustpkg_local_pkg() { #[test] #[ignore(reason="busted")] fn package_script_with_default_build() { - let dir = create_local_package(&CrateId::new("fancy-lib")); + let crate_id: CrateId = from_str("fancy-lib").unwrap(); + let dir = create_local_package(&crate_id); let dir = dir.path(); debug!("dir = {}", dir.display()); let mut source = test_sysroot().dir_path(); @@ -884,7 +826,7 @@ fn package_script_with_default_build() { debug!("package_script_with_default_build: {}", source.display()); fs::copy(&source, &dir.join_many(["src", "fancy-lib-0.0", "pkg.rs"])); command_line_test([~"install", ~"fancy-lib"], dir); - assert_lib_exists(dir, &Path::new("fancy-lib"), NoVersion); + assert_lib_exists(dir, &crate_id); assert!(target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"]).exists()); let generated_path = target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"]); debug!("generated path = {}", generated_path.display()); @@ -915,7 +857,8 @@ fn rustpkg_install_no_arg() { "fn main() { let _x = (); }"); debug!("install_no_arg: dir = {}", package_dir.display()); command_line_test([~"install"], &package_dir); - assert_lib_exists(&tmp, &Path::new("foo"), NoVersion); + let crate_id: CrateId = from_str("foo").unwrap(); + assert_lib_exists(&tmp, &crate_id); } #[test] @@ -931,14 +874,16 @@ fn rustpkg_clean_no_arg() { command_line_test([~"build"], &package_dir); assert_built_executable_exists(&tmp, "foo"); command_line_test([~"clean"], &package_dir); - let res = built_executable_in_workspace(&CrateId::new("foo"), &tmp); + let crate_id: CrateId = from_str("foo").unwrap(); + let res = built_executable_in_workspace(&crate_id, &tmp); assert!(!res.as_ref().map_or(false, |m| m.exists())); } #[test] fn rust_path_test() { let dir_for_path = TempDir::new("more_rust").expect("rust_path_test failed"); - let dir = mk_workspace(dir_for_path.path(), &Path::new("foo"), &NoVersion); + let crate_id: CrateId = from_str("foo").unwrap(); + let dir = mk_workspace(dir_for_path.path(), &crate_id); debug!("dir = {}", dir.display()); writeFile(&dir.join("main.rs"), "fn main() { let _x = (); }"); @@ -989,11 +934,11 @@ fn rust_path_parse() { fn test_list() { let dir = TempDir::new("test_list").expect("test_list failed"); let dir = dir.path(); - let foo = CrateId::new("foo"); + let foo: CrateId = from_str("foo").unwrap(); create_local_package_in(&foo, dir); - let bar = CrateId::new("bar"); + let bar: CrateId = from_str("bar").unwrap(); create_local_package_in(&bar, dir); - let quux = CrateId::new("quux"); + let quux: CrateId = from_str("quux").unwrap(); create_local_package_in(&quux, dir); // list doesn't output very much right now... @@ -1019,9 +964,9 @@ fn test_list() { fn install_remove() { let dir = TempDir::new("install_remove").expect("install_remove"); let dir = dir.path(); - let foo = CrateId::new("foo"); - let bar = CrateId::new("bar"); - let quux = CrateId::new("quux"); + let foo: CrateId = from_str("foo").unwrap(); + let bar: CrateId = from_str("bar").unwrap(); + let quux: CrateId = from_str("quux").unwrap(); create_local_package_in(&foo, dir); create_local_package_in(&bar, dir); create_local_package_in(&quux, dir); @@ -1048,7 +993,7 @@ fn install_check_duplicates() { // check invariant that there are no dups in the pkg database let dir = TempDir::new("install_remove").expect("install_remove"); let dir = dir.path(); - let foo = CrateId::new("foo"); + let foo: CrateId = from_str("foo").unwrap(); create_local_package_in(&foo, dir); command_line_test([~"install", ~"foo"], dir); @@ -1056,7 +1001,7 @@ fn install_check_duplicates() { let mut contents = ~[]; let check_dups = |p: &CrateId| { if contents.contains(p) { - fail!("package {} appears in `list` output more than once", p.path.display()); + fail!("package {} appears in `list` output more than once", p.path); } else { contents.push((*p).clone()); @@ -1068,7 +1013,7 @@ fn install_check_duplicates() { #[test] fn no_rebuilding() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); command_line_test([~"build", ~"foo"], workspace); @@ -1089,11 +1034,11 @@ fn no_rebuilding() { #[test] #[ignore] fn no_recopying() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); command_line_test([~"install", ~"foo"], workspace); - let foo_lib = installed_library_in_workspace(&p_id.path, workspace); + let foo_lib = installed_library_in_workspace(&p_id, workspace); assert!(foo_lib.is_some()); // Now make `foo` read-only so that subsequent attempts to copy to it will fail assert!(chmod_read_only(&foo_lib.unwrap())); @@ -1108,8 +1053,8 @@ fn no_recopying() { #[test] fn no_rebuilding_dep() { - let p_id = CrateId::new("foo"); - let dep_id = CrateId::new("bar"); + let p_id: CrateId = from_str("foo").unwrap(); + let dep_id: CrateId = from_str("bar").unwrap(); let workspace = create_local_package_with_dep(&p_id, &dep_id); let workspace = workspace.path(); command_line_test([~"build", ~"foo"], workspace); @@ -1127,8 +1072,8 @@ fn no_rebuilding_dep() { #[test] fn do_rebuild_dep_dates_change() { - let p_id = CrateId::new("foo"); - let dep_id = CrateId::new("bar"); + let p_id: CrateId = from_str("foo").unwrap(); + let dep_id: CrateId = from_str("bar").unwrap(); let workspace = create_local_package_with_dep(&p_id, &dep_id); let workspace = workspace.path(); command_line_test([~"build", ~"foo"], workspace); @@ -1147,8 +1092,8 @@ fn do_rebuild_dep_dates_change() { #[test] fn do_rebuild_dep_only_contents_change() { - let p_id = CrateId::new("foo"); - let dep_id = CrateId::new("bar"); + let p_id: CrateId = from_str("foo").unwrap(); + let dep_id: CrateId = from_str("bar").unwrap(); let workspace = create_local_package_with_dep(&p_id, &dep_id); let workspace = workspace.path(); command_line_test([~"build", ~"foo"], workspace); @@ -1168,8 +1113,10 @@ fn do_rebuild_dep_only_contents_change() { #[test] fn test_versions() { - let workspace = create_local_package(&CrateId::new("foo#0.1")); - let _other_workspace = create_local_package(&CrateId::new("foo#0.2")); + let foo_01: CrateId = from_str("foo#0.1").unwrap(); + let foo_02: CrateId = from_str("foo#0.2").unwrap(); + let workspace = create_local_package(&foo_01); + let _other_workspace = create_local_package(&foo_02); command_line_test([~"install", ~"foo#0.1"], workspace.path()); let output = command_line_test_output([~"list"]); // make sure output includes versions @@ -1179,7 +1126,8 @@ fn test_versions() { #[test] #[ignore(reason = "do not yet implemented")] fn test_build_hooks() { - let workspace = create_local_package_with_custom_build_hook(&CrateId::new("foo"), + let crate_id: CrateId = from_str("foo").unwrap(); + let workspace = create_local_package_with_custom_build_hook(&crate_id, "frob"); command_line_test([~"do", ~"foo", ~"frob"], workspace.path()); } @@ -1189,14 +1137,16 @@ fn test_build_hooks() { #[ignore(reason = "info not yet implemented")] fn test_info() { let expected_info = ~"package foo"; // fill in - let workspace = create_local_package(&CrateId::new("foo")); + let crate_id: CrateId = from_str("foo").unwrap(); + let workspace = create_local_package(&crate_id); let output = command_line_test([~"info", ~"foo"], workspace.path()); assert_eq!(str::from_utf8_owned(output.output).unwrap(), expected_info); } #[test] fn test_uninstall() { - let workspace = create_local_package(&CrateId::new("foo")); + let crate_id: CrateId = from_str("foo").unwrap(); + let workspace = create_local_package(&crate_id); command_line_test([~"uninstall", ~"foo"], workspace.path()); let output = command_line_test([~"list"], workspace.path()); assert!(!str::from_utf8(output.output).unwrap().contains("foo")); @@ -1205,7 +1155,7 @@ fn test_uninstall() { #[test] fn test_non_numeric_tag() { let temp_pkg_id = git_repo_pkg(); - let repo = init_git_repo(&temp_pkg_id.path); + let repo = init_git_repo(&Path::new(temp_pkg_id.path.as_slice())); let repo = repo.path(); let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg"]); writeFile(&repo_subdir.join("foo"), "foo"); @@ -1217,9 +1167,7 @@ fn test_non_numeric_tag() { writeFile(&repo_subdir.join("not_on_testbranch_only"), "bye bye"); add_all_and_commit(&repo_subdir); - // FIXME (#9639): This needs to handle non-utf8 paths - command_line_test([~"install", format!("{}\\#testbranch", - temp_pkg_id.path.as_str().unwrap())], repo); + command_line_test([~"install", format!("{}\\#testbranch", temp_pkg_id.path)], repo); let file1 = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg", "testbranch_only"]); let file2 = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg", "master_only"]); assert!(file1.exists()); @@ -1332,7 +1280,7 @@ fn test_extern_mod_simpler() { #[test] fn test_import_rustpkg() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); writeFile(&workspace.join_many(["src", "foo-0.0", "pkg.rs"]), @@ -1345,7 +1293,7 @@ fn test_import_rustpkg() { #[test] fn test_macro_pkg_script() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); writeFile(&workspace.join_many(["src", "foo-0.0", "pkg.rs"]), @@ -1362,8 +1310,10 @@ fn multiple_workspaces() { // Copy the exact same package into directory B and install it // Set the RUST_PATH to A:B // Make a third package that uses foo, make sure we can build/install it - let (a_loc, _pkg_dir) = mk_temp_workspace(&Path::new("foo"), &NoVersion); - let (b_loc, _pkg_dir) = mk_temp_workspace(&Path::new("foo"), &NoVersion); + let p_id: CrateId = from_str("foo").unwrap(); + let bar_p_id: CrateId = from_str("bar").unwrap(); + let (a_loc, _pkg_dir) = mk_temp_workspace(&p_id); + let (b_loc, _pkg_dir) = mk_temp_workspace(&p_id); let (a_loc, b_loc) = (a_loc.path(), b_loc.path()); debug!("Trying to install foo in {}", a_loc.display()); command_line_test([~"install", ~"foo"], a_loc); @@ -1372,7 +1322,7 @@ fn multiple_workspaces() { // FIXME (#9639): This needs to handle non-utf8 paths let env = Some(~[(~"RUST_PATH", format!("{}:{}", a_loc.as_str().unwrap(), b_loc.as_str().unwrap()))]); - let c_loc = create_local_package_with_dep(&CrateId::new("bar"), &CrateId::new("foo")); + let c_loc = create_local_package_with_dep(&bar_p_id, &p_id); command_line_test_with_env([~"install", ~"bar"], c_loc.path(), env); } @@ -1385,26 +1335,28 @@ fn rust_path_hack_test(hack_flag: bool) { make sure built files for foo are in B make sure nothing gets built into A or A/../build[lib,bin] */ - let p_id = CrateId::new("foo"); - let workspace = create_local_package(&p_id); - let workspace = workspace.path(); - let dest_workspace = mk_empty_workspace(&Path::new("bar"), &NoVersion, "dest_workspace"); - let dest_workspace = dest_workspace.path(); - let foo_path = workspace.join_many(["src", "foo-0.0"]); - let rust_path = Some(~[(~"RUST_PATH", - format!("{}:{}", - dest_workspace.as_str().unwrap(), - foo_path.as_str().unwrap()))]); - command_line_test_with_env(~[~"install"] + if hack_flag { ~[~"--rust-path-hack"] } else { ~[] } + - ~[~"foo"], dest_workspace, rust_path); - assert_lib_exists(dest_workspace, &Path::new("foo"), NoVersion); - assert_executable_exists(dest_workspace, "foo"); - assert_built_library_exists(dest_workspace, "foo"); - assert_built_executable_exists(dest_workspace, "foo"); - assert!(!lib_exists(workspace, &Path::new("foo"), NoVersion)); - assert!(!executable_exists(workspace, "foo")); - assert!(!built_library_exists(workspace, "foo")); - assert!(!built_executable_exists(workspace, "foo")); + let p_id: CrateId = from_str("foo").unwrap(); + let bar_p_id: CrateId = from_str("bar").unwrap(); + let workspace = create_local_package(&p_id); + let workspace = workspace.path(); + let dest_workspace = mk_empty_workspace(&bar_p_id, "dest_workspace"); + let dest_workspace = dest_workspace.path(); + let foo_path = workspace.join_many(["src", "foo-0.0"]); + let rust_path = Some(~[(~"RUST_PATH", + format!("{}:{}", + dest_workspace.as_str().unwrap(), + foo_path.as_str().unwrap()))]); + command_line_test_with_env(~[~"install"] + + if hack_flag { ~[~"--rust-path-hack"] } else { ~[] } + ~[~"foo"], + dest_workspace, rust_path); + assert_lib_exists(dest_workspace, &p_id); + assert_executable_exists(dest_workspace, "foo"); + assert_built_library_exists(dest_workspace, "foo"); + assert_built_executable_exists(dest_workspace, "foo"); + assert!(!lib_exists(workspace, &p_id)); + assert!(!executable_exists(workspace, "foo")); + assert!(!built_library_exists(workspace, "foo")); + assert!(!built_executable_exists(workspace, "foo")); } // Notice that this is the only test case where the --rust-path-hack @@ -1430,88 +1382,95 @@ fn test_rust_path_can_contain_package_dirs_without_flag() { #[test] fn rust_path_hack_cwd() { - // Same as rust_path_hack_test, but the CWD is the dir to build out of - let cwd = TempDir::new("foo").expect("rust_path_hack_cwd"); - let cwd = cwd.path().join("foo"); - fs::mkdir_recursive(&cwd, io::UserRWX); - writeFile(&cwd.join("lib.rs"), "pub fn f() { }"); - - let dest_workspace = mk_empty_workspace(&Path::new("bar"), &NoVersion, "dest_workspace"); - let dest_workspace = dest_workspace.path(); - // FIXME (#9639): This needs to handle non-utf8 paths - let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]); - command_line_test_with_env([~"install", ~"--rust-path-hack", ~"foo"], &cwd, rust_path); - debug!("Checking that foo exists in {}", dest_workspace.display()); - assert_lib_exists(dest_workspace, &Path::new("foo"), NoVersion); - assert_built_library_exists(dest_workspace, "foo"); - assert!(!lib_exists(&cwd, &Path::new("foo"), NoVersion)); - assert!(!built_library_exists(&cwd, "foo")); + // Same as rust_path_hack_test, but the CWD is the dir to build out of + let cwd = TempDir::new("foo").expect("rust_path_hack_cwd"); + let cwd = cwd.path().join("foo"); + fs::mkdir_recursive(&cwd, io::UserRWX); + writeFile(&cwd.join("lib.rs"), "pub fn f() { }"); + let foo_id: CrateId = from_str("foo").unwrap(); + let bar_id: CrateId = from_str("bar").unwrap(); + + let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace"); + let dest_workspace = dest_workspace.path(); + // FIXME (#9639): This needs to handle non-utf8 paths + let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]); + command_line_test_with_env([~"install", ~"--rust-path-hack", ~"foo"], &cwd, rust_path); + debug!("Checking that foo exists in {}", dest_workspace.display()); + assert_lib_exists(dest_workspace, &foo_id); + assert_built_library_exists(dest_workspace, "foo"); + assert!(!lib_exists(&cwd, &foo_id)); + assert!(!built_library_exists(&cwd, "foo")); } #[test] fn rust_path_hack_multi_path() { - // Same as rust_path_hack_test, but with a more complex package ID - let cwd = TempDir::new("pkg_files").expect("rust_path_hack_cwd"); - let subdir = cwd.path().join_many(["foo", "bar", "quux"]); - fs::mkdir_recursive(&subdir, io::UserRWX); - writeFile(&subdir.join("lib.rs"), "pub fn f() { }"); - let name = ~"foo/bar/quux"; - - let dest_workspace = mk_empty_workspace(&Path::new("bar"), &NoVersion, "dest_workspace"); - let dest_workspace = dest_workspace.path(); - // FIXME (#9639): This needs to handle non-utf8 paths - let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]); - command_line_test_with_env([~"install", ~"--rust-path-hack", name.clone()], &subdir, rust_path); - debug!("Checking that {} exists in {}", name, dest_workspace.display()); - assert_lib_exists(dest_workspace, &Path::new("quux"), NoVersion); - assert_built_library_exists(dest_workspace, name); - assert!(!lib_exists(&subdir, &Path::new("quux"), NoVersion)); - assert!(!built_library_exists(&subdir, name)); + // Same as rust_path_hack_test, but with a more complex package ID + let cwd = TempDir::new("pkg_files").expect("rust_path_hack_cwd"); + let subdir = cwd.path().join_many(["foo", "bar", "quux"]); + fs::mkdir_recursive(&subdir, io::UserRWX); + writeFile(&subdir.join("lib.rs"), "pub fn f() { }"); + let name = ~"foo/bar/quux"; + let foo_id: CrateId = from_str("foo/bar/quux").unwrap(); + let bar_id: CrateId = from_str("bar").unwrap(); + + let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace"); + let dest_workspace = dest_workspace.path(); + // FIXME (#9639): This needs to handle non-utf8 paths + let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]); + command_line_test_with_env([~"install", ~"--rust-path-hack", name.clone()], &subdir, rust_path); + debug!("Checking that {} exists in {}", name, dest_workspace.display()); + assert_lib_exists(dest_workspace, &foo_id); + assert_built_library_exists(dest_workspace, name); + assert!(!lib_exists(&subdir, &foo_id)); + assert!(!built_library_exists(&subdir, name)); } #[test] fn rust_path_hack_install_no_arg() { - // Same as rust_path_hack_cwd, but making rustpkg infer the pkg id - let cwd = TempDir::new("pkg_files").expect("rust_path_hack_install_no_arg"); - let cwd = cwd.path(); - let source_dir = cwd.join("foo"); - assert!(make_dir_rwx(&source_dir)); - writeFile(&source_dir.join("lib.rs"), "pub fn f() { }"); - - let dest_workspace = mk_empty_workspace(&Path::new("bar"), &NoVersion, "dest_workspace"); - let dest_workspace = dest_workspace.path(); - // FIXME (#9639): This needs to handle non-utf8 paths - let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]); - command_line_test_with_env([~"install", ~"--rust-path-hack"], &source_dir, rust_path); - debug!("Checking that foo exists in {}", dest_workspace.display()); - assert_lib_exists(dest_workspace, &Path::new("foo"), NoVersion); - assert_built_library_exists(dest_workspace, "foo"); - assert!(!lib_exists(&source_dir, &Path::new("foo"), NoVersion)); - assert!(!built_library_exists(cwd, "foo")); + // Same as rust_path_hack_cwd, but making rustpkg infer the pkg id + let cwd = TempDir::new("pkg_files").expect("rust_path_hack_install_no_arg"); + let cwd = cwd.path(); + let source_dir = cwd.join("foo"); + assert!(make_dir_rwx(&source_dir)); + writeFile(&source_dir.join("lib.rs"), "pub fn f() { }"); + + let foo_id: CrateId = from_str("foo").unwrap(); + let bar_id: CrateId = from_str("bar").unwrap(); + let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace"); + let dest_workspace = dest_workspace.path(); + // FIXME (#9639): This needs to handle non-utf8 paths + let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]); + command_line_test_with_env([~"install", ~"--rust-path-hack"], &source_dir, rust_path); + debug!("Checking that foo exists in {}", dest_workspace.display()); + assert_lib_exists(dest_workspace, &foo_id); + assert_built_library_exists(dest_workspace, "foo"); + assert!(!lib_exists(&source_dir, &foo_id)); + assert!(!built_library_exists(cwd, "foo")); } #[test] fn rust_path_hack_build_no_arg() { - // Same as rust_path_hack_install_no_arg, but building instead of installing - let cwd = TempDir::new("pkg_files").expect("rust_path_hack_build_no_arg"); - let source_dir = cwd.path().join("foo"); - assert!(make_dir_rwx(&source_dir)); - writeFile(&source_dir.join("lib.rs"), "pub fn f() { }"); - - let dest_workspace = mk_empty_workspace(&Path::new("bar"), &NoVersion, "dest_workspace"); - let dest_workspace = dest_workspace.path(); - // FIXME (#9639): This needs to handle non-utf8 paths - let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]); - command_line_test_with_env([~"build", ~"--rust-path-hack"], &source_dir, rust_path); - debug!("Checking that foo exists in {}", dest_workspace.display()); - assert_built_library_exists(dest_workspace, "foo"); - assert!(!built_library_exists(&source_dir, "foo")); + // Same as rust_path_hack_install_no_arg, but building instead of installing + let cwd = TempDir::new("pkg_files").expect("rust_path_hack_build_no_arg"); + let source_dir = cwd.path().join("foo"); + assert!(make_dir_rwx(&source_dir)); + writeFile(&source_dir.join("lib.rs"), "pub fn f() { }"); + + let bar_id: CrateId = from_str("bar").unwrap(); + let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace"); + let dest_workspace = dest_workspace.path(); + // FIXME (#9639): This needs to handle non-utf8 paths + let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]); + command_line_test_with_env([~"build", ~"--rust-path-hack"], &source_dir, rust_path); + debug!("Checking that foo exists in {}", dest_workspace.display()); + assert_built_library_exists(dest_workspace, "foo"); + assert!(!built_library_exists(&source_dir, "foo")); } #[test] fn rust_path_hack_build_with_dependency() { - let foo_id = CrateId::new("foo"); - let dep_id = CrateId::new("dep"); + let foo_id: CrateId = from_str("foo").unwrap(); + let dep_id: CrateId = from_str("dep").unwrap(); // Tests that when --rust-path-hack is in effect, dependencies get built // into the destination workspace and not the source directory let work_dir = create_local_package(&foo_id); @@ -1536,7 +1495,8 @@ fn rust_path_hack_build_with_dependency() { fn rust_path_install_target() { let dir_for_path = TempDir::new( "source_workspace").expect("rust_path_install_target failed"); - let mut dir = mk_workspace(dir_for_path.path(), &Path::new("foo"), &NoVersion); + let foo_id: CrateId = from_str("foo").unwrap(); + let mut dir = mk_workspace(dir_for_path.path(), &foo_id); debug!("dir = {}", dir.display()); writeFile(&dir.join("main.rs"), "fn main() { let _x = (); }"); let dir_to_install_to = TempDir::new( @@ -1559,7 +1519,7 @@ fn rust_path_install_target() { #[test] fn sysroot_flag() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); // no-op sysroot setting; I'm not sure how else to test this @@ -1575,7 +1535,7 @@ fn sysroot_flag() { #[test] fn compile_flag_build() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); let test_sys = test_sysroot(); @@ -1592,7 +1552,7 @@ fn compile_flag_build() { #[test] fn compile_flag_fail() { // --no-link shouldn't be accepted for install - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); let test_sys = test_sysroot(); @@ -1608,7 +1568,7 @@ fn compile_flag_fail() { #[test] fn notrans_flag_build() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); let flags_to_test = [~"--no-trans", ~"--parse-only", @@ -1633,7 +1593,7 @@ fn notrans_flag_build() { #[test] fn notrans_flag_fail() { // --no-trans shouldn't be accepted for install - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); let flags_to_test = [~"--no-trans", ~"--parse-only", @@ -1648,13 +1608,13 @@ fn notrans_flag_fail() { workspace, None, BAD_FLAG_CODE); assert!(!built_executable_exists(workspace, "foo")); assert!(!object_file_exists(workspace, "foo")); - assert!(!lib_exists(workspace, &Path::new("foo"), NoVersion)); + assert!(!lib_exists(workspace, &p_id)); } } #[test] fn dash_S() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); let test_sys = test_sysroot(); @@ -1671,7 +1631,7 @@ fn dash_S() { #[test] fn dash_S_fail() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); let test_sys = test_sysroot(); @@ -1688,7 +1648,7 @@ fn dash_S_fail() { #[test] fn test_cfg_build() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); // If the cfg flag gets messed up, this won't compile @@ -1707,7 +1667,7 @@ fn test_cfg_build() { #[test] fn test_cfg_fail() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); writeFile(&workspace.join_many(["src", "foo-0.0", "main.rs"]), @@ -1726,7 +1686,7 @@ fn test_cfg_fail() { #[test] fn test_emit_llvm_S_build() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); let test_sys = test_sysroot(); @@ -1744,7 +1704,7 @@ fn test_emit_llvm_S_build() { #[test] fn test_emit_llvm_S_fail() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); let test_sys = test_sysroot(); @@ -1764,7 +1724,7 @@ fn test_emit_llvm_S_fail() { #[test] fn test_emit_llvm_build() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); let test_sys = test_sysroot(); @@ -1783,7 +1743,7 @@ fn test_emit_llvm_build() { #[test] fn test_emit_llvm_fail() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); let test_sys = test_sysroot(); @@ -1804,7 +1764,7 @@ fn test_emit_llvm_fail() { #[test] fn test_linker_build() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); let matches = getopts([], optgroups()); @@ -1849,7 +1809,7 @@ fn test_build_install_flags_fail() { #[test] fn test_optimized_build() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); let test_sys = test_sysroot(); @@ -1879,10 +1839,10 @@ fn crateid_pointing_to_subdir() { fs::mkdir_recursive(&foo_dir, io::UserRWX); fs::mkdir_recursive(&bar_dir, io::UserRWX); writeFile(&foo_dir.join("lib.rs"), - "#[crate_id=\"mockgithub.com/mozilla/some_repo/extras/rust-foo#foo:0.0\"];" + + "#[crate_id=\"mockgithub.com/mozilla/some_repo/extras/foo\"];" + "pub fn f() {}"); writeFile(&bar_dir.join("lib.rs"), - "#[crate_id=\"mockgithub.com/mozilla/some_repo/extras/rust-bar#bar:0.0\"];" + + "#[crate_id=\"mockgithub.com/mozilla/some_repo/extras/bar\"];" + "pub fn g() {}"); debug!("Creating a file in {}", workspace.display()); @@ -1890,8 +1850,8 @@ fn crateid_pointing_to_subdir() { fs::mkdir_recursive(&testpkg_dir, io::UserRWX); writeFile(&testpkg_dir.join("main.rs"), - "extern mod foo = \"mockgithub.com/mozilla/some_repo/extras/foo\";\n - extern mod bar = \"mockgithub.com/mozilla/some_repo/extras/bar\";\n + "extern mod foo = \"mockgithub.com/mozilla/some_repo/extras/foo#foo:0.0\";\n + extern mod bar = \"mockgithub.com/mozilla/some_repo/extras/bar#bar:0.0\";\n use foo::f; use bar::g; \n fn main() { f(); g(); }"); @@ -1901,9 +1861,9 @@ fn crateid_pointing_to_subdir() { #[test] fn test_recursive_deps() { - let a_id = CrateId::new("a"); - let b_id = CrateId::new("b"); - let c_id = CrateId::new("c"); + let a_id: CrateId = from_str("a").unwrap(); + let b_id: CrateId = from_str("b").unwrap(); + let c_id: CrateId = from_str("c").unwrap(); let b_workspace = create_local_package_with_dep(&b_id, &c_id); let b_workspace = b_workspace.path(); writeFile(&b_workspace.join_many(["src", "c-0.0", "lib.rs"]), @@ -1920,17 +1880,18 @@ fn test_recursive_deps() { command_line_test_with_env([~"install", ~"a"], a_workspace, environment); - assert_lib_exists(a_workspace, &Path::new("a"), NoVersion); - assert_lib_exists(b_workspace, &Path::new("b"), NoVersion); - assert_lib_exists(b_workspace, &Path::new("c"), NoVersion); + assert_lib_exists(a_workspace, &a_id); + assert_lib_exists(b_workspace, &b_id); + assert_lib_exists(b_workspace, &c_id); } #[test] fn test_install_to_rust_path() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let second_workspace = create_local_package(&p_id); let second_workspace = second_workspace.path(); - let first_workspace = mk_empty_workspace(&Path::new("p"), &NoVersion, "dest"); + let none_id: CrateId = from_str("p").unwrap(); + let first_workspace = mk_empty_workspace(&none_id, "dest"); let first_workspace = first_workspace.path(); // FIXME (#9639): This needs to handle non-utf8 paths let rust_path = Some(~[(~"RUST_PATH", @@ -1951,7 +1912,7 @@ fn test_install_to_rust_path() { #[test] fn test_target_specific_build_dir() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); let test_sys = test_sysroot(); @@ -1967,7 +1928,7 @@ fn test_target_specific_build_dir() { #[test] fn test_target_specific_install_dir() { - let p_id = CrateId::new("foo"); + let p_id: CrateId = from_str("foo").unwrap(); let workspace = create_local_package(&p_id); let workspace = workspace.path(); let test_sys = test_sysroot(); @@ -1977,7 +1938,7 @@ fn test_target_specific_install_dir() { ~"foo"], workspace); assert!(workspace.join_many([~"lib", host_triple()]).is_dir()); - assert_lib_exists(workspace, &Path::new("foo"), NoVersion); + assert_lib_exists(workspace, &p_id); assert!(fs::readdir(&workspace.join("lib")).len() == 1); assert!(workspace.join("bin").is_dir()); assert_executable_exists(workspace, "foo"); @@ -1986,7 +1947,7 @@ fn test_target_specific_install_dir() { #[test] #[ignore(reason = "See #7240")] fn test_dependencies_terminate() { - let b_id = CrateId::new("b"); + let b_id: CrateId = from_str("b").unwrap(); let workspace = create_local_package(&b_id); let workspace = workspace.path(); let b_dir = workspace.join_many(["src", "b-0.0"]); @@ -1999,42 +1960,42 @@ fn test_dependencies_terminate() { #[test] fn install_after_build() { - let b_id = CrateId::new("b"); + let b_id: CrateId = from_str("b").unwrap(); let workspace = create_local_package(&b_id); let workspace = workspace.path(); command_line_test([~"build", ~"b"], workspace); command_line_test([~"install", ~"b"], workspace); - assert_executable_exists(workspace, b_id.short_name); - assert_lib_exists(workspace, &b_id.path, NoVersion); + assert_executable_exists(workspace, b_id.name); + assert_lib_exists(workspace, &b_id); } #[test] fn reinstall() { - let b = CrateId::new("b"); + let b: CrateId = from_str("b").unwrap(); let workspace = create_local_package(&b); let workspace = workspace.path(); // 1. Install, then remove executable file, then install again, // and make sure executable was re-installed command_line_test([~"install", ~"b"], workspace); - assert_executable_exists(workspace, b.short_name); - assert_lib_exists(workspace, &b.path, NoVersion); + assert_executable_exists(workspace, b.name); + assert_lib_exists(workspace, &b); remove_executable_file(&b, workspace); command_line_test([~"install", ~"b"], workspace); - assert_executable_exists(workspace, b.short_name); + assert_executable_exists(workspace, b.name); // 2. Build, then remove build executable file, then build again, // and make sure executable was re-built. command_line_test([~"build", ~"b"], workspace); remove_built_executable_file(&b, workspace); command_line_test([~"build", ~"b"], workspace); - assert_built_executable_exists(workspace, b.short_name); + assert_built_executable_exists(workspace, b.name); // 3. Install, then remove both executable and built executable, // then install again, make sure both were recreated command_line_test([~"install", ~"b"], workspace); remove_executable_file(&b, workspace); remove_built_executable_file(&b, workspace); command_line_test([~"install", ~"b"], workspace); - assert_executable_exists(workspace, b.short_name); - assert_built_executable_exists(workspace, b.short_name); + assert_executable_exists(workspace, b.name); + assert_built_executable_exists(workspace, b.name); } #[test] @@ -2049,11 +2010,11 @@ fn correct_package_name_with_rust_path_hack() { */ // Set RUST_PATH to something containing only the sources for foo - let foo_id = CrateId::new("foo"); - let bar_id = CrateId::new("bar"); + let foo_id: CrateId = from_str("foo").unwrap(); + let bar_id: CrateId = from_str("bar").unwrap(); let foo_workspace = create_local_package(&foo_id); let foo_workspace = foo_workspace.path(); - let dest_workspace = mk_empty_workspace(&Path::new("bar"), &NoVersion, "dest_workspace"); + let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace"); let dest_workspace = dest_workspace.path(); writeFile(&dest_workspace.join_many(["src", "bar-0.0", "main.rs"]), @@ -2068,18 +2029,18 @@ fn correct_package_name_with_rust_path_hack() { // FIXME #3408: Should be NONEXISTENT_PACKAGE_CODE dest_workspace, rust_path, COPY_FAILED_CODE); assert!(!executable_exists(dest_workspace, "bar")); - assert!(!lib_exists(dest_workspace, &bar_id.path.clone(), bar_id.version.clone())); + assert!(!lib_exists(dest_workspace, &bar_id)); assert!(!executable_exists(dest_workspace, "foo")); - assert!(!lib_exists(dest_workspace, &foo_id.path.clone(), foo_id.version.clone())); + assert!(!lib_exists(dest_workspace, &foo_id)); assert!(!executable_exists(foo_workspace, "bar")); - assert!(!lib_exists(foo_workspace, &bar_id.path.clone(), bar_id.version.clone())); + assert!(!lib_exists(foo_workspace, &bar_id)); assert!(!executable_exists(foo_workspace, "foo")); - assert!(!lib_exists(foo_workspace, &foo_id.path.clone(), foo_id.version.clone())); + assert!(!lib_exists(foo_workspace, &foo_id)); } #[test] fn test_rustpkg_test_creates_exec() { - let foo_id = CrateId::new("foo"); + let foo_id: CrateId = from_str("foo").unwrap(); let foo_workspace = create_local_package(&foo_id); let foo_workspace = foo_workspace.path(); writeFile(&foo_workspace.join_many(["src", "foo-0.0", "test.rs"]), @@ -2090,7 +2051,8 @@ fn test_rustpkg_test_creates_exec() { #[test] fn test_rustpkg_test_output() { - let workspace = create_local_package_with_test(&CrateId::new("foo")); + let foo_id: CrateId = from_str("foo").unwrap(); + let workspace = create_local_package_with_test(&foo_id); let output = command_line_test([~"test", ~"foo"], workspace.path()); let output_str = str::from_utf8(output.output).unwrap(); // The first two assertions are separate because test output may @@ -2102,7 +2064,7 @@ fn test_rustpkg_test_output() { #[test] fn test_rustpkg_test_failure_exit_status() { - let foo_id = CrateId::new("foo"); + let foo_id: CrateId = from_str("foo").unwrap(); let foo_workspace = create_local_package(&foo_id); let foo_workspace = foo_workspace.path(); writeFile(&foo_workspace.join_many(["src", "foo-0.0", "test.rs"]), @@ -2116,7 +2078,7 @@ fn test_rustpkg_test_failure_exit_status() { #[test] fn test_rustpkg_test_cfg() { - let foo_id = CrateId::new("foo"); + let foo_id: CrateId = from_str("foo").unwrap(); let foo_workspace = create_local_package(&foo_id); let foo_workspace = foo_workspace.path(); writeFile(&foo_workspace.join_many(["src", "foo-0.0", "test.rs"]), @@ -2129,7 +2091,7 @@ fn test_rustpkg_test_cfg() { #[test] fn test_rebuild_when_needed() { - let foo_id = CrateId::new("foo"); + let foo_id: CrateId = from_str("foo").unwrap(); let foo_workspace = create_local_package(&foo_id); let foo_workspace = foo_workspace.path(); let test_crate = foo_workspace.join_many(["src", "foo-0.0", "test.rs"]); @@ -2150,7 +2112,7 @@ fn test_rebuild_when_needed() { #[test] #[ignore] // FIXME (#10257): This doesn't work as is since a read only file can't execute fn test_no_rebuilding() { - let foo_id = CrateId::new("foo"); + let foo_id: CrateId = from_str("foo").unwrap(); let foo_workspace = create_local_package(&foo_id); let foo_workspace = foo_workspace.path(); let test_crate = foo_workspace.join_many(["src", "foo-0.0", "test.rs"]); @@ -2172,8 +2134,9 @@ fn test_no_rebuilding() { fn test_installed_read_only() { // Install sources from a "remote" (actually a local github repo) // Check that afterward, sources are read-only and installed under build/ - let mut temp_pkg_id = git_repo_pkg(); - let repo = init_git_repo(&temp_pkg_id.path); + let temp_pkg_id = git_repo_pkg(); + let path = Path::new(temp_pkg_id.path.as_slice()); + let repo = init_git_repo(&path); let repo = repo.path(); debug!("repo = {}", repo.display()); let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg"]); @@ -2183,12 +2146,11 @@ fn test_installed_read_only() { "fn main() { let _x = (); }"); writeFile(&repo_subdir.join("lib.rs"), "pub fn f() { let _x = (); }"); - add_git_tag(&repo_subdir, ~"0.1"); // this has the effect of committing the files + add_git_tag(&repo_subdir, ~"0.0"); // this has the effect of committing the files // update crateid to what will be auto-detected - temp_pkg_id.version = ExactRevision(~"0.1"); // FIXME (#9639): This needs to handle non-utf8 paths - command_line_test([~"install", temp_pkg_id.path.as_str().unwrap().to_owned()], repo); + command_line_test([~"install", temp_pkg_id.to_str()], repo); let ws = repo.join(".rust"); // Check that all files exist @@ -2204,8 +2166,10 @@ fn test_installed_read_only() { assert!(is_rwx(&built_lib)); // Make sure sources are (a) under "build" and (b) read-only - let src1 = target_build_dir(&ws).join_many([~"src", temp_pkg_id.to_str(), ~"main.rs"]); - let src2 = target_build_dir(&ws).join_many([~"src", temp_pkg_id.to_str(), ~"lib.rs"]); + let temp_dir = format!("{}-{}", temp_pkg_id.path, temp_pkg_id.version_or_default()); + let src1 = target_build_dir(&ws).join_many([~"src", temp_dir.clone(), ~"main.rs"]); + let src2 = target_build_dir(&ws).join_many([~"src", temp_dir.clone(), ~"lib.rs"]); + debug!("src1: {}", src1.display()); assert!(src1.exists()); assert!(src2.exists()); assert!(is_read_only(&src1)); @@ -2215,7 +2179,7 @@ fn test_installed_read_only() { #[test] fn test_installed_local_changes() { let temp_pkg_id = git_repo_pkg(); - let repo = init_git_repo(&temp_pkg_id.path); + let repo = init_git_repo(&Path::new(temp_pkg_id.path.as_slice())); let repo = repo.path(); debug!("repo = {}", repo.display()); let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg"]); @@ -2228,9 +2192,7 @@ fn test_installed_local_changes() { "pub fn f() { let _x = (); }"); add_git_tag(&repo_subdir, ~"0.1"); // this has the effect of committing the files - // FIXME (#9639): This needs to handle non-utf8 paths - command_line_test([~"install", temp_pkg_id.path.as_str().unwrap().to_owned()], repo); - + command_line_test([~"install", temp_pkg_id.path.to_owned()], repo); // We installed the dependency. // Now start a new workspace and clone it into it @@ -2242,7 +2204,7 @@ fn test_installed_local_changes() { "test-pkg-0.0"]); debug!("---- git clone {} {}", repo_subdir.display(), target_dir.display()); - let c_res = safe_git_clone(&repo_subdir, &NoVersion, &target_dir); + let c_res = safe_git_clone(&repo_subdir, &None, &target_dir); match c_res { DirToUse(_) => fail!("test_installed_local_changes failed"), @@ -2262,14 +2224,13 @@ fn test_installed_local_changes() { fn main() { g(); }"); // And make sure we can build it - // FIXME (#9639): This needs to handle non-utf8 paths - command_line_test([~"build", importer_pkg_id.path.as_str().unwrap().to_owned()], - hacking_workspace); + command_line_test([~"build", importer_pkg_id.path.to_owned()], hacking_workspace); } #[test] fn test_7402() { - let dir = create_local_package(&CrateId::new("foo")); + let foo_id: CrateId = from_str("foo").unwrap(); + let dir = create_local_package(&foo_id); let dest_workspace = TempDir::new("more_rust").expect("test_7402"); let dest_workspace = dest_workspace.path(); // FIXME (#9639): This needs to handle non-utf8 paths @@ -2283,7 +2244,7 @@ fn test_7402() { #[test] fn test_compile_error() { - let foo_id = CrateId::new("foo"); + let foo_id: CrateId = from_str("foo").unwrap(); let foo_workspace = create_local_package(&foo_id); let foo_workspace = foo_workspace.path(); let main_crate = foo_workspace.join_many(["src", "foo-0.0", "main.rs"]); @@ -2317,7 +2278,8 @@ fn test_c_dependency_ok() { // registers a hook to build it if it's not fresh // After running `build`, test that the C library built - let dir = create_local_package(&CrateId::new("cdep")); + let cdep_id: CrateId = from_str("cdep").unwrap(); + let dir = create_local_package(&cdep_id); let dir = dir.path(); writeFile(&dir.join_many(["src", "cdep-0.0", "main.rs"]), "#[link_args = \"-lfoo\"]\nextern { fn f(); } \ @@ -2340,7 +2302,8 @@ fn test_c_dependency_ok() { #[test] #[ignore(reason="busted")] fn test_c_dependency_no_rebuilding() { - let dir = create_local_package(&CrateId::new("cdep")); + let cdep_id: CrateId = from_str("cdep").unwrap(); + let dir = create_local_package(&cdep_id); let dir = dir.path(); writeFile(&dir.join_many(["src", "cdep-0.0", "main.rs"]), "#[link_args = \"-lfoo\"]\nextern { fn f(); } \ @@ -2374,7 +2337,8 @@ fn test_c_dependency_no_rebuilding() { #[test] #[ignore(reason="busted")] fn test_c_dependency_yes_rebuilding() { - let dir = create_local_package(&CrateId::new("cdep")); + let cdep_id: CrateId = from_str("cdep").unwrap(); + let dir = create_local_package(&cdep_id); let dir = dir.path(); writeFile(&dir.join_many(["src", "cdep-0.0", "main.rs"]), "#[link_args = \"-lfoo\"]\nextern { fn f(); } \ @@ -2395,7 +2359,7 @@ fn test_c_dependency_yes_rebuilding() { assert!(c_library_path.exists()); // Now, make the Rust library read-only so rebuilding will fail - match built_library_in_workspace(&CrateId::new("cdep"), dir) { + match built_library_in_workspace(&cdep_id, dir) { Some(ref pth) => assert!(chmod_read_only(pth)), None => assert_built_library_exists(dir, "cdep") } @@ -2413,7 +2377,8 @@ fn test_c_dependency_yes_rebuilding() { fn correct_error_dependency() { // Supposing a package we're trying to install via a dependency doesn't // exist, we should throw a condition, and not ICE - let workspace_dir = create_local_package(&CrateId::new("badpkg")); + let crate_id: CrateId = from_str("badpkg").unwrap(); + let workspace_dir = create_local_package(&crate_id); let dir = workspace_dir.path(); let main_rs = dir.join_many(["src", "badpkg-0.0", "main.rs"]); diff --git a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs index b6c5e15c09a..b6dba40ebd4 100644 --- a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs +++ b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs @@ -13,7 +13,7 @@ extern mod rustc; use std::{os, task}; use rustpkg::api; -use rustpkg::version::NoVersion; +use rustpkg::version::None; use rustpkg::workcache_support::digest_file_with_date; use rustpkg::exit_codes::COPY_FAILED_CODE; @@ -73,7 +73,7 @@ pub fn main() { api::install_pkg(&mut cc, os::getcwd(), ~"cdep", - NoVersion, + None, ~[(~"binary", out_lib_path.clone()), (~"file", foo_c_name.clone())]); }; diff --git a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs index 4a107de55a5..7b1291025e4 100644 --- a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs +++ b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs @@ -14,7 +14,7 @@ extern mod rustc; use std::os; use std::io::File; use rustpkg::api; -use rustpkg::version::NoVersion; +use rustpkg::version::None; pub fn main() { let args = os::args(); @@ -48,5 +48,5 @@ pub fn main() { for _ in xs.iter() { assert!(true); } }".as_bytes()); let context = api::default_context(sysroot, api::default_workspace()); - api::install_pkg(&context, os::getcwd(), ~"fancy-lib", NoVersion, ~[]); + api::install_pkg(&context, os::getcwd(), ~"fancy-lib", None, ~[]); } diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 628c0b937af..57fcf564c5d 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -10,6 +10,10 @@ #[allow(dead_code)]; +pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename}; +pub use target::{Target, Build, Install}; +pub use target::{lib_name_of, lib_crate_filename, WhatToBuild, MaybeCustom, Inferred}; + use std::cell::RefCell; use std::libc; use std::os; @@ -17,7 +21,7 @@ use std::io; use std::io::fs; use extra::workcache; use rustc::metadata::creader::Loader; -use rustc::driver::{driver, session}; +use extra::treemap::TreeMap; use extra::getopts::groups::getopts; use syntax; use syntax::codemap::{DUMMY_SP, Spanned}; @@ -28,19 +32,16 @@ use syntax::attr::AttrMetaMethods; use syntax::fold::Folder; use syntax::visit::Visitor; use syntax::util::small_vector::SmallVector; +use syntax::crateid::CrateId; use rustc::back::link::OutputTypeExe; use rustc::back::link; +use rustc::driver::{driver, session}; use CtxMethods; use context::{in_target, StopBefore, Link, Assemble, BuildContext}; -use crate_id::CrateId; use package_source::PkgSrc; use workspace::pkg_parent_workspaces; use path_util::{system_library, target_build_dir}; use path_util::{default_workspace, built_library_in_workspace}; -pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename}; -pub use target::{Target, Build, Install}; -use extra::treemap::TreeMap; -pub use target::{lib_name_of, lib_crate_filename, WhatToBuild, MaybeCustom, Inferred}; use workcache_support::{digest_file_with_date, digest_only_date}; use messages::error; @@ -135,7 +136,7 @@ struct CrateSetup<'a> { ctx: &'a mut ReadyCtx<'a>, } -impl<'a> fold::Folder for CrateSetup<'a> { +impl<'a> Folder for CrateSetup<'a> { fn fold_item(&mut self, item: @ast::Item) -> SmallVector<@ast::Item> { fold_item(item, self) } @@ -162,7 +163,7 @@ pub fn ready_crate(sess: session::Session, pub fn compile_input(context: &BuildContext, exec: &mut workcache::Exec, - pkg_id: &CrateId, + crate_id: &CrateId, in_file: &Path, workspace: &Path, deps: &mut DepMap, @@ -177,11 +178,11 @@ pub fn compile_input(context: &BuildContext, // not sure if we should support anything else let mut out_dir = target_build_dir(workspace); - out_dir.push(&pkg_id.path); + out_dir.push(crate_id.path.as_slice()); // Make the output directory if it doesn't exist already fs::mkdir_recursive(&out_dir, io::UserRWX); - let binary = os::args()[0].to_owned(); + let binary = os::args()[0]; debug!("flags: {}", flags.connect(" ")); debug!("cfgs: {}", cfgs.connect(" ")); @@ -276,7 +277,7 @@ pub fn compile_input(context: &BuildContext, let (mut crate, ast_map) = { let installer = CrateInstaller { context: context, - parent: pkg_id, + parent: crate_id, parent_crate: in_file, sess: sess, exec: exec, @@ -312,10 +313,7 @@ pub fn compile_input(context: &BuildContext, if !attr::contains_name(crate.attrs, "crate_id") { // FIXME (#9639): This needs to handle non-utf8 paths let crateid_attr = - attr::mk_name_value_item_str(@"crate_id", - format!("{}\\#{}", - pkg_id.path.as_str().unwrap(), - pkg_id.version.to_str()).to_managed()); + attr::mk_name_value_item_str(@"crate_id", crate_id.to_str().to_managed()); debug!("crateid attr: {:?}", crateid_attr); crate.attrs.push(attr::mk_attr(crateid_attr)); @@ -333,7 +331,7 @@ pub fn compile_input(context: &BuildContext, what); // Discover the output let discovered_output = if what == Lib { - built_library_in_workspace(pkg_id, workspace) // Huh??? + built_library_in_workspace(crate_id, workspace) // Huh??? } else { result @@ -435,7 +433,7 @@ pub fn exe_suffix() -> ~str { ~"" } // Called by build_crates pub fn compile_crate(ctxt: &BuildContext, exec: &mut workcache::Exec, - pkg_id: &CrateId, + crate_id: &CrateId, crate: &Path, workspace: &Path, deps: &mut DepMap, @@ -444,11 +442,11 @@ pub fn compile_crate(ctxt: &BuildContext, opt: session::OptLevel, what: OutputType) -> Option<Path> { debug!("compile_crate: crate={}, workspace={}", crate.display(), workspace.display()); - debug!("compile_crate: short_name = {}, flags =...", pkg_id.to_str()); + debug!("compile_crate: name = {}, flags =...", crate_id.to_str()); for fl in flags.iter() { debug!("+++ {}", *fl); } - compile_input(ctxt, exec, pkg_id, crate, workspace, deps, flags, cfgs, opt, what) + compile_input(ctxt, exec, crate_id, crate, workspace, deps, flags, cfgs, opt, what) } struct CrateInstaller<'a> { @@ -473,8 +471,9 @@ impl<'a> CrateInstaller<'a> { None => self.sess.str_of(lib_ident) }; debug!("Finding and installing... {}", lib_name); + let crate_id: CrateId = from_str(lib_name).expect("valid crate id"); // Check standard Rust library path first - let whatever = system_library(&self.context.sysroot_to_use(), lib_name); + let whatever = system_library(&self.context.sysroot_to_use(), &crate_id); debug!("system library returned {:?}", whatever); match whatever { Some(ref installed_path) => { @@ -494,13 +493,11 @@ impl<'a> CrateInstaller<'a> { } None => { // FIXME #8711: need to parse version out of path_opt - debug!("Trying to install library {}, rebuilding it", - lib_name.to_str()); + debug!("Trying to install library {}, rebuilding it", crate_id.to_str()); // Try to install it - let pkg_id = CrateId::new(lib_name); // Find all the workspaces in the RUST_PATH that contain this package. let workspaces = pkg_parent_workspaces(&self.context.context, - &pkg_id); + &crate_id); // Three cases: // (a) `workspaces` is empty. That means there's no local source // for this package. In that case, we pass the default workspace @@ -529,8 +526,8 @@ impl<'a> CrateInstaller<'a> { // Nonexistent package? Then print a better error error(format!("Package {} depends on {}, but I don't know \ how to find it", - self.parent.path.display(), - pkg_id.path.display())); + self.parent.path, + crate_id.path)); fail!() }).inside(|| { PkgSrc::new(source_workspace.clone(), @@ -538,7 +535,7 @@ impl<'a> CrateInstaller<'a> { // Use the rust_path_hack to search for dependencies iff // we were already using it self.context.context.use_rust_path_hack, - pkg_id.clone()) + crate_id.clone()) }); let (outputs_disc, inputs_disc) = self.context.install( diff --git a/src/librustpkg/version.rs b/src/librustpkg/version.rs index 77dbb335518..93e7a052efa 100644 --- a/src/librustpkg/version.rs +++ b/src/librustpkg/version.rs @@ -13,170 +13,9 @@ extern mod std; -use extra::semver; -use std::{char, result, run, str}; -use extra::tempfile::TempDir; -use path_util::rust_path; +use std::char; -#[deriving(Clone)] -pub enum Version { - ExactRevision(~str), // Should look like a m.n.(...).x - SemanticVersion(semver::Version), - Tagged(~str), // String that can't be parsed as a version. - // Requirements get interpreted exactly - NoVersion // user didn't specify a version -- prints as 0.0 -} - -// Equality on versions is non-symmetric: if self is NoVersion, it's equal to -// anything; but if self is a precise version, it's not equal to NoVersion. -// We should probably make equality symmetric, and use less-than and greater-than -// where we currently use eq -impl Eq for Version { - fn eq(&self, other: &Version) -> bool { - match (self, other) { - (&ExactRevision(ref s1), &ExactRevision(ref s2)) => *s1 == *s2, - (&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => *v1 == *v2, - (&NoVersion, _) => true, - _ => false - } - } -} - -impl Ord for Version { - fn lt(&self, other: &Version) -> bool { - match (self, other) { - (&NoVersion, _) => true, - (&ExactRevision(ref f1), &ExactRevision(ref f2)) => f1 < f2, - (&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => v1 < v2, - _ => false // incomparable, really - } - } - fn le(&self, other: &Version) -> bool { - match (self, other) { - (&NoVersion, _) => true, - (&ExactRevision(ref f1), &ExactRevision(ref f2)) => f1 <= f2, - (&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => v1 <= v2, - _ => false // incomparable, really - } - } - fn ge(&self, other: &Version) -> bool { - match (self, other) { - (&ExactRevision(ref f1), &ExactRevision(ref f2)) => f1 > f2, - (&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => v1 > v2, - _ => false // incomparable, really - } - } - fn gt(&self, other: &Version) -> bool { - match (self, other) { - (&ExactRevision(ref f1), &ExactRevision(ref f2)) => f1 >= f2, - (&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => v1 >= v2, - _ => false // incomparable, really - } - } - -} - -impl ToStr for Version { - fn to_str(&self) -> ~str { - match *self { - ExactRevision(ref n) | Tagged(ref n) => format!("{}", n.to_str()), - SemanticVersion(ref v) => format!("{}", v.to_str()), - NoVersion => ~"0.0" - } - } -} - -pub fn parse_vers(vers: ~str) -> result::Result<semver::Version, ~str> { - match semver::parse(vers) { - Some(vers) => result::Ok(vers), - None => result::Err(~"could not parse version: invalid") - } -} - -/// If `local_path` is a git repo in the RUST_PATH, and the most recent tag -/// in that repo denotes a version, return it; otherwise, `None` -pub fn try_getting_local_version(local_path: &Path) -> Option<Version> { - let rustpath = rust_path(); - for rp in rustpath.iter() { - let local_path = rp.join(local_path); - let git_dir = local_path.join(".git"); - if !git_dir.is_dir() { - continue; - } - // FIXME (#9639): This needs to handle non-utf8 paths - let opt_outp = run::process_output("git", - ["--git-dir=" + git_dir.as_str().unwrap(), ~"tag", ~"-l"]); - let outp = opt_outp.expect("Failed to exec `git`"); - - debug!("git --git-dir={} tag -l ~~~> {:?}", git_dir.display(), outp.status); - - if !outp.status.success() { - continue; - } - - let mut output = None; - let output_text = str::from_utf8(outp.output).unwrap(); - for l in output_text.lines() { - if !l.is_whitespace() { - output = Some(l); - } - match output.and_then(try_parsing_version) { - Some(v) => return Some(v), - None => () - } - } - } - None -} - -/// If `remote_path` refers to a git repo that can be downloaded, -/// and the most recent tag in that repo denotes a version, return it; -/// otherwise, `None` -pub fn try_getting_version(remote_path: &Path) -> Option<Version> { - if is_url_like(remote_path) { - let tmp_dir = TempDir::new("test"); - let tmp_dir = tmp_dir.expect("try_getting_version: couldn't create temp dir"); - let tmp_dir = tmp_dir.path(); - debug!("(to get version) executing \\{git clone https://{} {}\\}", - remote_path.display(), - tmp_dir.display()); - // FIXME (#9639): This needs to handle non-utf8 paths - let opt_outp = run::process_output("git", [~"clone", format!("https://{}", - remote_path.as_str().unwrap()), - tmp_dir.as_str().unwrap().to_owned()]); - let outp = opt_outp.expect("Failed to exec `git`"); - if outp.status.success() { - debug!("Cloned it... ( {}, {} )", - str::from_utf8(outp.output).unwrap(), - str::from_utf8(outp.error).unwrap()); - let mut output = None; - let git_dir = tmp_dir.join(".git"); - debug!("(getting version, now getting tags) executing \\{git --git-dir={} tag -l\\}", - git_dir.display()); - // FIXME (#9639): This needs to handle non-utf8 paths - let opt_outp = run::process_output("git", - ["--git-dir=" + git_dir.as_str().unwrap(), - ~"tag", ~"-l"]); - let outp = opt_outp.expect("Failed to exec `git`"); - let output_text = str::from_utf8(outp.output).unwrap(); - debug!("Full output: ( {} ) [{:?}]", output_text, outp.status); - for l in output_text.lines() { - debug!("A line of output: {}", l); - if !l.is_whitespace() { - output = Some(l); - } - } - - output.and_then(try_parsing_version) - } - else { - None - } - } - else { - None - } -} +pub type Version = Option<~str>; // Being lazy since we don't have a regexp library now #[deriving(Eq)] @@ -186,7 +25,7 @@ enum ParseState { SawDot } -pub fn try_parsing_version(s: &str) -> Option<Version> { +pub fn try_parsing_version(s: &str) -> Option<~str> { let s = s.trim(); debug!("Attempting to parse: {}", s); let mut parse_state = Start; @@ -202,17 +41,11 @@ pub fn try_parsing_version(s: &str) -> Option<Version> { } } match parse_state { - SawDigit => Some(ExactRevision(s.to_owned())), + SawDigit => Some(s.to_owned()), _ => None } } -/// Just an approximation -fn is_url_like(p: &Path) -> bool { - // check if there are more than 2 /-separated components - p.as_vec().split(|b| *b == '/' as u8).nth(2).is_some() -} - /// If s is of the form foo#bar, where bar is a valid version /// number, return the prefix before the # and the version. /// Otherwise, return None. @@ -229,7 +62,7 @@ pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Vers Some(i) => { let path = s.slice(0, i); // n.b. for now, assuming an exact revision is intended, not a SemVer - Some((path, ExactRevision(s.slice(i + 1, s.len()).to_owned()))) + Some((path, Some(s.slice(i + 1, s.len()).to_owned()))) } None => { None @@ -239,11 +72,11 @@ pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Vers #[test] fn test_parse_version() { - assert!(try_parsing_version("1.2") == Some(ExactRevision(~"1.2"))); - assert!(try_parsing_version("1.0.17") == Some(ExactRevision(~"1.0.17"))); + assert!(try_parsing_version("1.2") == Some(~"1.2")); + assert!(try_parsing_version("1.0.17") == Some(~"1.0.17")); assert!(try_parsing_version("you're_a_kitty") == None); assert!(try_parsing_version("42..1") == None); - assert!(try_parsing_version("17") == Some(ExactRevision(~"17"))); + assert!(try_parsing_version("17") == Some(~"17")); assert!(try_parsing_version(".1.2.3") == None); assert!(try_parsing_version("2.3.") == None); } @@ -252,9 +85,9 @@ fn test_parse_version() { fn test_split_version() { let s = "a/b/c#0.1"; debug!("== {:?} ==", split_version(s)); - assert!(split_version(s) == Some((s.slice(0, 5), ExactRevision(~"0.1")))); + assert!(split_version(s) == Some((s.slice(0, 5), Some(~"0.1")))); assert!(split_version("a/b/c") == None); let s = "a#1.2"; - assert!(split_version(s) == Some((s.slice(0, 1), ExactRevision(~"1.2")))); + assert!(split_version(s) == Some((s.slice(0, 1), Some(~"1.2")))); assert!(split_version("a#a#3.4") == None); } diff --git a/src/librustpkg/workspace.rs b/src/librustpkg/workspace.rs index d6e617d2d50..e19a19dc8ab 100644 --- a/src/librustpkg/workspace.rs +++ b/src/librustpkg/workspace.rs @@ -11,12 +11,11 @@ // rustpkg utilities having to do with workspaces use std::os; -use std::path::Path; use context::Context; use path_util::{workspace_contains_crate_id, find_dir_using_rust_path_hack, default_workspace}; use path_util::rust_path; use util::option_to_vec; -use crate_id::CrateId; +use syntax::crateid::CrateId; pub fn each_pkg_parent_workspace(cx: &Context, crateid: &CrateId, @@ -29,7 +28,7 @@ pub fn each_pkg_parent_workspace(cx: &Context, // tjc: make this a condition fail!("Package {} not found in any of \ the following workspaces: {}", - crateid.path.display(), + crateid.path, rust_path().map(|p| p.display().to_str()).to_str()); } for ws in workspaces.iter() { @@ -64,7 +63,8 @@ pub fn cwd_to_workspace() -> Option<(Path, CrateId)> { let rel = cwd.path_relative_from(&srcpath); let rel_s = rel.as_ref().and_then(|p|p.as_str()); if rel_s.is_some() { - return Some((path, CrateId::new(rel_s.unwrap()))); + let crate_id = from_str(rel_s.unwrap()).expect("valid crate id"); + return Some((path, crate_id)); } } } diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs index 189a820cd3e..0a6e23e9956 100644 --- a/src/librustuv/uvll.rs +++ b/src/librustuv/uvll.rs @@ -373,7 +373,7 @@ pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void { } pub unsafe fn free_handle(v: *c_void) { - free(v) + free(v as *mut c_void) } pub unsafe fn malloc_req(req: uv_req_type) -> *c_void { @@ -383,7 +383,7 @@ pub unsafe fn malloc_req(req: uv_req_type) -> *c_void { } pub unsafe fn free_req(v: *c_void) { - free(v) + free(v as *mut c_void) } #[test] diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs index c735e325068..22e93e58194 100644 --- a/src/libstd/c_str.rs +++ b/src/libstd/c_str.rs @@ -183,7 +183,7 @@ impl Drop for CString { fn drop(&mut self) { if self.owns_buffer_ { unsafe { - libc::free(self.buf as *libc::c_void) + libc::free(self.buf as *mut libc::c_void) } } } @@ -459,7 +459,7 @@ mod tests { #[test] fn test_unwrap() { let c_str = "hello".to_c_str(); - unsafe { libc::free(c_str.unwrap() as *libc::c_void) } + unsafe { libc::free(c_str.unwrap() as *mut libc::c_void) } } #[test] diff --git a/src/libstd/cleanup.rs b/src/libstd/cleanup.rs index ab374ebccfe..40c4ad842ff 100644 --- a/src/libstd/cleanup.rs +++ b/src/libstd/cleanup.rs @@ -10,12 +10,11 @@ #[doc(hidden)]; -use libc::c_void; use ptr; use unstable::intrinsics::TyDesc; use unstable::raw; -type DropGlue<'a> = 'a |**TyDesc, *c_void|; +type DropGlue<'a> = 'a |**TyDesc, *u8|; static RC_IMMORTAL : uint = 0x77777777; @@ -107,7 +106,7 @@ pub unsafe fn annihilate() { stats.n_bytes_freed += (*((*alloc).type_desc)).size + mem::size_of::<raw::Box<()>>(); - local_free(alloc as *i8); + local_free(alloc as *u8); true }); diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs index 411f9f25459..5b2a792a05b 100644 --- a/src/libstd/fmt/mod.rs +++ b/src/libstd/fmt/mod.rs @@ -147,6 +147,8 @@ The current mapping of types to traits is: * `p` ⇒ `Pointer` * `t` ⇒ `Binary` * `f` ⇒ `Float` +* `e` ⇒ `LowerExp` +* `E` ⇒ `UpperExp` * *nothing* ⇒ `Default` What this means is that any type of argument which implements the @@ -578,6 +580,12 @@ pub trait Pointer { fn fmt(&Self, &mut Formatter); } /// Format trait for the `f` character #[allow(missing_doc)] pub trait Float { fn fmt(&Self, &mut Formatter); } +/// Format trait for the `e` character +#[allow(missing_doc)] +pub trait LowerExp { fn fmt(&Self, &mut Formatter); } +/// Format trait for the `E` character +#[allow(missing_doc)] +pub trait UpperExp { fn fmt(&Self, &mut Formatter); } /// The `write` function takes an output stream, a precompiled format string, /// and a list of arguments. The arguments will be formatted according to the @@ -1085,6 +1093,28 @@ macro_rules! floating(($ty:ident) => { fmt.pad_integral(s.as_bytes(), "", *f >= 0.0); } } + + impl LowerExp for $ty { + fn fmt(f: &$ty, fmt: &mut Formatter) { + // XXX: this shouldn't perform an allocation + let s = match fmt.precision { + Some(i) => ::$ty::to_str_exp_exact(f.abs(), i, false), + None => ::$ty::to_str_exp_digits(f.abs(), 6, false) + }; + fmt.pad_integral(s.as_bytes(), "", *f >= 0.0); + } + } + + impl UpperExp for $ty { + fn fmt(f: &$ty, fmt: &mut Formatter) { + // XXX: this shouldn't perform an allocation + let s = match fmt.precision { + Some(i) => ::$ty::to_str_exp_exact(f.abs(), i, true), + None => ::$ty::to_str_exp_digits(f.abs(), 6, true) + }; + fmt.pad_integral(s.as_bytes(), "", *f >= 0.0); + } + } }) floating!(f32) floating!(f64) diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index 7f19105cdc8..13a03d32525 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -66,8 +66,9 @@ use rand::Rng; use rand; use uint; use util::replace; -use vec::{ImmutableVector, MutableVector, OwnedVector}; -use vec; +use vec::{ImmutableVector, MutableVector, OwnedVector, Items, MutItems}; +use vec_ng; +use vec_ng::Vec; static INITIAL_CAPACITY: uint = 32u; // 2^5 @@ -90,7 +91,7 @@ pub struct HashMap<K,V> { priv k1: u64, priv resize_at: uint, priv size: uint, - priv buckets: ~[Option<Bucket<K, V>>], + priv buckets: Vec<Option<Bucket<K, V>>> } // We could rewrite FoundEntry to have type Option<&Bucket<K, V>> @@ -151,7 +152,7 @@ impl<K:Hash + Eq,V> HashMap<K, V> { -> SearchResult { let mut ret = TableFull; self.bucket_sequence(hash, |i| { - match self.buckets[i] { + match self.buckets.as_slice()[i] { Some(ref bkt) if bkt.hash == hash && *k == bkt.key => { ret = FoundEntry(i); false }, @@ -169,7 +170,7 @@ impl<K:Hash + Eq,V> HashMap<K, V> { -> SearchResult { let mut ret = TableFull; self.bucket_sequence(hash, |i| { - match self.buckets[i] { + match self.buckets.as_slice()[i] { Some(ref bkt) if bkt.hash == hash && k.equiv(&bkt.key) => { ret = FoundEntry(i); false }, @@ -194,7 +195,7 @@ impl<K:Hash + Eq,V> HashMap<K, V> { self.resize_at = resize_at(new_capacity); let old_buckets = replace(&mut self.buckets, - vec::from_fn(new_capacity, |_| None)); + Vec::from_fn(new_capacity, |_| None)); self.size = 0; for bucket in old_buckets.move_iter() { @@ -213,7 +214,7 @@ impl<K:Hash + Eq,V> HashMap<K, V> { #[inline] fn value_for_bucket<'a>(&'a self, idx: uint) -> &'a V { - match self.buckets[idx] { + match self.buckets.as_slice()[idx] { Some(ref bkt) => &bkt.value, None => fail!("HashMap::find: internal logic error"), } @@ -221,7 +222,7 @@ impl<K:Hash + Eq,V> HashMap<K, V> { #[inline] fn mut_value_for_bucket<'a>(&'a mut self, idx: uint) -> &'a mut V { - match self.buckets[idx] { + match self.buckets.as_mut_slice()[idx] { Some(ref mut bkt) => &mut bkt.value, None => unreachable!() } @@ -234,13 +235,12 @@ impl<K:Hash + Eq,V> HashMap<K, V> { match self.bucket_for_key_with_hash(hash, &k) { TableFull => { fail!("Internal logic error"); } FoundHole(idx) => { - self.buckets[idx] = Some(Bucket{hash: hash, key: k, - value: v}); + self.buckets.as_mut_slice()[idx] = Some(Bucket{hash: hash, key: k, value: v}); self.size += 1; None } FoundEntry(idx) => { - match self.buckets[idx] { + match self.buckets.as_mut_slice()[idx] { None => { fail!("insert_internal: Internal logic error") } Some(ref mut b) => { b.hash = hash; @@ -273,7 +273,7 @@ impl<K:Hash + Eq,V> HashMap<K, V> { }; let len_buckets = self.buckets.len(); - let bucket = self.buckets[idx].take(); + let bucket = self.buckets.as_mut_slice()[idx].take(); let value = bucket.map(|bucket| bucket.value); @@ -281,8 +281,8 @@ impl<K:Hash + Eq,V> HashMap<K, V> { what our new size is ahead of time before we start insertions */ let size = self.size - 1; idx = self.next_bucket(idx, len_buckets); - while self.buckets[idx].is_some() { - let bucket = self.buckets[idx].take(); + while self.buckets.as_slice()[idx].is_some() { + let bucket = self.buckets.as_mut_slice()[idx].take(); self.insert_opt_bucket(bucket); idx = self.next_bucket(idx, len_buckets); } @@ -300,7 +300,7 @@ impl<K:Hash + Eq,V> Container for HashMap<K, V> { impl<K:Hash + Eq,V> Mutable for HashMap<K, V> { /// Clear the map, removing all key-value pairs. fn clear(&mut self) { - for bkt in self.buckets.mut_iter() { + for bkt in self.buckets.as_mut_slice().mut_iter() { *bkt = None; } self.size = 0; @@ -380,7 +380,7 @@ impl<K: Hash + Eq, V> HashMap<K, V> { k0: k0, k1: k1, resize_at: resize_at(cap), size: 0, - buckets: vec::from_fn(cap, |_| None) + buckets: Vec::from_fn(cap, |_| None) } } @@ -455,7 +455,7 @@ impl<K: Hash + Eq, V> HashMap<K, V> { FoundEntry(idx) => { found(&k, self.mut_value_for_bucket(idx), a); idx } FoundHole(idx) => { let v = not_found(&k, a); - self.buckets[idx] = Some(Bucket{hash: hash, key: k, value: v}); + self.buckets.as_mut_slice()[idx] = Some(Bucket{hash: hash, key: k, value: v}); self.size += 1; idx } @@ -541,14 +541,14 @@ impl<K: Hash + Eq, V> HashMap<K, V> { /// An iterator visiting all key-value pairs in arbitrary order. /// Iterator element type is (&'a K, &'a V). pub fn iter<'a>(&'a self) -> Entries<'a, K, V> { - Entries { iter: self.buckets.iter() } + Entries { iter: self.buckets.as_slice().iter() } } /// An iterator visiting all key-value pairs in arbitrary order, /// with mutable references to the values. /// Iterator element type is (&'a K, &'a mut V). pub fn mut_iter<'a>(&'a mut self) -> MutEntries<'a, K, V> { - MutEntries { iter: self.buckets.mut_iter() } + MutEntries { iter: self.buckets.as_mut_slice().mut_iter() } } /// Creates a consuming iterator, that is, one that moves each key-value @@ -599,17 +599,17 @@ impl<K:Hash + Eq + Clone,V:Clone> Clone for HashMap<K,V> { /// HashMap iterator #[deriving(Clone)] pub struct Entries<'a, K, V> { - priv iter: vec::Items<'a, Option<Bucket<K, V>>>, + priv iter: Items<'a, Option<Bucket<K, V>>>, } /// HashMap mutable values iterator pub struct MutEntries<'a, K, V> { - priv iter: vec::MutItems<'a, Option<Bucket<K, V>>>, + priv iter: MutItems<'a, Option<Bucket<K, V>>>, } /// HashMap move iterator pub struct MoveEntries<K, V> { - priv iter: vec::MoveItems<Option<Bucket<K, V>>>, + priv iter: vec_ng::MoveItems<Option<Bucket<K, V>>>, } /// HashMap keys iterator @@ -623,12 +623,12 @@ pub type Values<'a, K, V> = /// HashSet iterator #[deriving(Clone)] pub struct SetItems<'a, K> { - priv iter: vec::Items<'a, Option<Bucket<K, ()>>>, + priv iter: Items<'a, Option<Bucket<K, ()>>>, } /// HashSet move iterator pub struct SetMoveItems<K> { - priv iter: vec::MoveItems<Option<Bucket<K, ()>>>, + priv iter: vec_ng::MoveItems<Option<Bucket<K, ()>>>, } impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> { @@ -807,7 +807,7 @@ impl<T:Hash + Eq> HashSet<T> { /// An iterator visiting all elements in arbitrary order. /// Iterator element type is &'a T. pub fn iter<'a>(&'a self) -> SetItems<'a, T> { - SetItems { iter: self.map.buckets.iter() } + SetItems { iter: self.map.buckets.as_slice().iter() } } /// Creates a consuming iterator, that is, one that moves each value out diff --git a/src/libstd/io/test.rs b/src/libstd/io/test.rs index 92b2cfa8be2..d81de989df7 100644 --- a/src/libstd/io/test.rs +++ b/src/libstd/io/test.rs @@ -34,6 +34,7 @@ macro_rules! iotest ( use io::net::udp::*; #[cfg(unix)] use io::net::unix::*; + use io::timer::*; use io::process::*; use str; use util; diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs index d156a7460e1..4bf89a1d559 100644 --- a/src/libstd/io/timer.rs +++ b/src/libstd/io/timer.rs @@ -96,61 +96,177 @@ impl Timer { #[cfg(test)] mod test { - use prelude::*; - use super::*; - - #[test] - fn test_io_timer_sleep_simple() { + iotest!(fn test_io_timer_sleep_simple() { let mut timer = Timer::new().unwrap(); timer.sleep(1); - } + }) - #[test] - fn test_io_timer_sleep_oneshot() { + iotest!(fn test_io_timer_sleep_oneshot() { let mut timer = Timer::new().unwrap(); timer.oneshot(1).recv(); - } + }) - #[test] - fn test_io_timer_sleep_oneshot_forget() { + iotest!(fn test_io_timer_sleep_oneshot_forget() { let mut timer = Timer::new().unwrap(); timer.oneshot(100000000000); - } + }) - #[test] - fn oneshot_twice() { + iotest!(fn oneshot_twice() { let mut timer = Timer::new().unwrap(); let port1 = timer.oneshot(10000); let port = timer.oneshot(1); port.recv(); - assert!(port1.recv_opt().is_none()); - } + assert_eq!(port1.recv_opt(), None); + }) - #[test] - fn test_io_timer_oneshot_then_sleep() { + iotest!(fn test_io_timer_oneshot_then_sleep() { let mut timer = Timer::new().unwrap(); let port = timer.oneshot(100000000000); timer.sleep(1); // this should invalidate the port - assert!(port.recv_opt().is_none()); - } - #[test] - fn test_io_timer_sleep_periodic() { + assert_eq!(port.recv_opt(), None); + }) + + iotest!(fn test_io_timer_sleep_periodic() { let mut timer = Timer::new().unwrap(); let port = timer.periodic(1); port.recv(); port.recv(); port.recv(); - } + }) - #[test] - fn test_io_timer_sleep_periodic_forget() { + iotest!(fn test_io_timer_sleep_periodic_forget() { let mut timer = Timer::new().unwrap(); timer.periodic(100000000000); - } + }) - #[test] - fn test_io_timer_sleep_standalone() { + iotest!(fn test_io_timer_sleep_standalone() { sleep(1) - } + }) + + iotest!(fn oneshot() { + let mut timer = Timer::new().unwrap(); + + let port = timer.oneshot(1); + port.recv(); + assert!(port.recv_opt().is_none()); + + let port = timer.oneshot(1); + port.recv(); + assert!(port.recv_opt().is_none()); + }) + + iotest!(fn override() { + let mut timer = Timer::new().unwrap(); + let oport = timer.oneshot(100); + let pport = timer.periodic(100); + timer.sleep(1); + assert_eq!(oport.recv_opt(), None); + assert_eq!(pport.recv_opt(), None); + timer.oneshot(1).recv(); + }) + + iotest!(fn period() { + let mut timer = Timer::new().unwrap(); + let port = timer.periodic(1); + port.recv(); + port.recv(); + let port2 = timer.periodic(1); + port2.recv(); + port2.recv(); + }) + + iotest!(fn sleep() { + let mut timer = Timer::new().unwrap(); + timer.sleep(1); + timer.sleep(1); + }) + + iotest!(fn oneshot_fail() { + let mut timer = Timer::new().unwrap(); + let _port = timer.oneshot(1); + fail!(); + } #[should_fail]) + + iotest!(fn period_fail() { + let mut timer = Timer::new().unwrap(); + let _port = timer.periodic(1); + fail!(); + } #[should_fail]) + + iotest!(fn normal_fail() { + let _timer = Timer::new().unwrap(); + fail!(); + } #[should_fail]) + + iotest!(fn closing_channel_during_drop_doesnt_kill_everything() { + // see issue #10375 + let mut timer = Timer::new().unwrap(); + let timer_port = timer.periodic(1000); + + do spawn { + timer_port.recv_opt(); + } + + // when we drop the TimerWatcher we're going to destroy the channel, + // which must wake up the task on the other end + }) + + iotest!(fn reset_doesnt_switch_tasks() { + // similar test to the one above. + let mut timer = Timer::new().unwrap(); + let timer_port = timer.periodic(1000); + + do spawn { + timer_port.recv_opt(); + } + + timer.oneshot(1); + }) + + iotest!(fn reset_doesnt_switch_tasks2() { + // similar test to the one above. + let mut timer = Timer::new().unwrap(); + let timer_port = timer.periodic(1000); + + do spawn { + timer_port.recv_opt(); + } + + timer.sleep(1); + }) + + iotest!(fn sender_goes_away_oneshot() { + let port = { + let mut timer = Timer::new().unwrap(); + timer.oneshot(1000) + }; + assert_eq!(port.recv_opt(), None); + }) + + iotest!(fn sender_goes_away_period() { + let port = { + let mut timer = Timer::new().unwrap(); + timer.periodic(1000) + }; + assert_eq!(port.recv_opt(), None); + }) + + iotest!(fn receiver_goes_away_oneshot() { + let mut timer1 = Timer::new().unwrap(); + timer1.oneshot(1); + let mut timer2 = Timer::new().unwrap(); + // while sleeping, the prevous timer should fire and not have its + // callback do something terrible. + timer2.sleep(2); + }) + + iotest!(fn receiver_goes_away_period() { + let mut timer1 = Timer::new().unwrap(); + timer1.periodic(1); + let mut timer2 = Timer::new().unwrap(); + // while sleeping, the prevous timer should fire and not have its + // callback do something terrible. + timer2.sleep(2); + }) } diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs index 8081c6ed8db..a65da914373 100644 --- a/src/libstd/iter.rs +++ b/src/libstd/iter.rs @@ -670,21 +670,21 @@ pub trait DoubleEndedIterator<A>: Iterator<A> { /// Yield an element from the end of the range, returning `None` if the range is empty. fn next_back(&mut self) -> Option<A>; - /// Flip the direction of the iterator + /// Change the direction of the iterator /// - /// The inverted iterator flips the ends on an iterator that can already + /// The flipped iterator swaps the ends on an iterator that can already /// be iterated from the front and from the back. /// /// - /// If the iterator also implements RandomAccessIterator, the inverted + /// If the iterator also implements RandomAccessIterator, the flipped /// iterator is also random access, with the indices starting at the back /// of the original iterator. /// - /// Note: Random access with inverted indices still only applies to the first + /// Note: Random access with flipped indices still only applies to the first /// `uint::max_value` elements of the original iterator. #[inline] - fn invert(self) -> Invert<Self> { - Invert{iter: self} + fn rev(self) -> Rev<Self> { + Rev{iter: self} } } @@ -759,30 +759,30 @@ pub trait ExactSize<A> : DoubleEndedIterator<A> { // Adaptors that may overflow in `size_hint` are not, i.e. `Chain`. impl<A, T: ExactSize<A>> ExactSize<(uint, A)> for Enumerate<T> {} impl<'a, A, T: ExactSize<A>> ExactSize<A> for Inspect<'a, A, T> {} -impl<A, T: ExactSize<A>> ExactSize<A> for Invert<T> {} +impl<A, T: ExactSize<A>> ExactSize<A> for Rev<T> {} impl<'a, A, B, T: ExactSize<A>> ExactSize<B> for Map<'a, A, B, T> {} impl<A, B, T: ExactSize<A>, U: ExactSize<B>> ExactSize<(A, B)> for Zip<T, U> {} /// An double-ended iterator with the direction inverted #[deriving(Clone)] -pub struct Invert<T> { +pub struct Rev<T> { priv iter: T } -impl<A, T: DoubleEndedIterator<A>> Iterator<A> for Invert<T> { +impl<A, T: DoubleEndedIterator<A>> Iterator<A> for Rev<T> { #[inline] fn next(&mut self) -> Option<A> { self.iter.next_back() } #[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() } } -impl<A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for Invert<T> { +impl<A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for Rev<T> { #[inline] fn next_back(&mut self) -> Option<A> { self.iter.next() } } impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterator<A> - for Invert<T> { + for Rev<T> { #[inline] fn indexable(&self) -> uint { self.iter.indexable() } #[inline] @@ -2590,12 +2590,12 @@ mod tests { } #[test] - fn test_invert() { + fn test_rev() { let xs = [2, 4, 6, 8, 10, 12, 14, 16]; let mut it = xs.iter(); it.next(); it.next(); - assert_eq!(it.invert().map(|&x| x).collect::<~[int]>(), ~[16, 14, 12, 10, 8, 6]); + assert_eq!(it.rev().map(|&x| x).collect::<~[int]>(), ~[16, 14, 12, 10, 8, 6]); } #[test] @@ -2662,7 +2662,7 @@ mod tests { fn test_double_ended_chain() { let xs = [1, 2, 3, 4, 5]; let ys = ~[7, 9, 11]; - let mut it = xs.iter().chain(ys.iter()).invert(); + let mut it = xs.iter().chain(ys.iter()).rev(); assert_eq!(it.next().unwrap(), &11) assert_eq!(it.next().unwrap(), &9) assert_eq!(it.next_back().unwrap(), &1) @@ -2764,10 +2764,10 @@ mod tests { } #[test] - fn test_random_access_invert() { + fn test_random_access_rev() { let xs = [1, 2, 3, 4, 5]; - check_randacc_iter(xs.iter().invert(), xs.len()); - let mut it = xs.iter().invert(); + check_randacc_iter(xs.iter().rev(), xs.len()); + let mut it = xs.iter().rev(); it.next(); it.next_back(); it.next(); @@ -2833,13 +2833,13 @@ mod tests { #[test] fn test_double_ended_range() { - assert_eq!(range(11i, 14).invert().collect::<~[int]>(), ~[13i, 12, 11]); - for _ in range(10i, 0).invert() { + assert_eq!(range(11i, 14).rev().collect::<~[int]>(), ~[13i, 12, 11]); + for _ in range(10i, 0).rev() { fail!("unreachable"); } - assert_eq!(range(11u, 14).invert().collect::<~[uint]>(), ~[13u, 12, 11]); - for _ in range(10u, 0).invert() { + assert_eq!(range(11u, 14).rev().collect::<~[uint]>(), ~[13u, 12, 11]); + for _ in range(10u, 0).rev() { fail!("unreachable"); } } @@ -2886,11 +2886,11 @@ mod tests { assert_eq!(range(0i, 5).collect::<~[int]>(), ~[0i, 1, 2, 3, 4]); assert_eq!(range(-10i, -1).collect::<~[int]>(), ~[-10, -9, -8, -7, -6, -5, -4, -3, -2]); - assert_eq!(range(0i, 5).invert().collect::<~[int]>(), ~[4, 3, 2, 1, 0]); + assert_eq!(range(0i, 5).rev().collect::<~[int]>(), ~[4, 3, 2, 1, 0]); assert_eq!(range(200, -5).collect::<~[int]>(), ~[]); - assert_eq!(range(200, -5).invert().collect::<~[int]>(), ~[]); + assert_eq!(range(200, -5).rev().collect::<~[int]>(), ~[]); assert_eq!(range(200, 200).collect::<~[int]>(), ~[]); - assert_eq!(range(200, 200).invert().collect::<~[int]>(), ~[]); + assert_eq!(range(200, 200).rev().collect::<~[int]>(), ~[]); assert_eq!(range(0i, 100).size_hint(), (100, Some(100))); // this test is only meaningful when sizeof uint < sizeof u64 @@ -2902,11 +2902,11 @@ mod tests { #[test] fn test_range_inclusive() { assert_eq!(range_inclusive(0i, 5).collect::<~[int]>(), ~[0i, 1, 2, 3, 4, 5]); - assert_eq!(range_inclusive(0i, 5).invert().collect::<~[int]>(), ~[5i, 4, 3, 2, 1, 0]); + assert_eq!(range_inclusive(0i, 5).rev().collect::<~[int]>(), ~[5i, 4, 3, 2, 1, 0]); assert_eq!(range_inclusive(200, -5).collect::<~[int]>(), ~[]); - assert_eq!(range_inclusive(200, -5).invert().collect::<~[int]>(), ~[]); + assert_eq!(range_inclusive(200, -5).rev().collect::<~[int]>(), ~[]); assert_eq!(range_inclusive(200, 200).collect::<~[int]>(), ~[200]); - assert_eq!(range_inclusive(200, 200).invert().collect::<~[int]>(), ~[200]); + assert_eq!(range_inclusive(200, 200).rev().collect::<~[int]>(), ~[200]); } #[test] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f4f83892a9c..7e53a0071bd 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -110,6 +110,7 @@ pub mod char; pub mod tuple; pub mod vec; +pub mod vec_ng; pub mod at_vec; pub mod str; diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 77ac226a7f1..6f2d64ff668 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -3225,7 +3225,7 @@ pub mod funcs { pub fn calloc(nobj: size_t, size: size_t) -> *c_void; pub fn malloc(size: size_t) -> *mut c_void; pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; - pub fn free(p: *c_void); + pub fn free(p: *mut c_void); pub fn exit(status: c_int) -> !; // Omitted: atexit. pub fn system(s: *c_char) -> c_int; @@ -3548,6 +3548,7 @@ pub mod funcs { pub fn setsid() -> pid_t; pub fn setuid(uid: uid_t) -> c_int; pub fn sleep(secs: c_uint) -> c_uint; + pub fn usleep(secs: c_uint) -> c_int; pub fn sysconf(name: c_int) -> c_long; pub fn tcgetpgrp(fd: c_int) -> pid_t; pub fn ttyname(fd: c_int) -> *c_char; diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs index 7ef7a256c16..7406fe8ee40 100644 --- a/src/libstd/local_data.rs +++ b/src/libstd/local_data.rs @@ -41,10 +41,9 @@ local_data::get(key_vector, |opt| assert_eq!(*opt.unwrap(), ~[4])); // magic. use cast; -use libc; use prelude::*; use rt::task::{Task, LocalStorage}; -use util; +use util::replace; /** * Indexes a task-local data slot. This pointer is used for comparison to @@ -87,7 +86,7 @@ impl<T: 'static> LocalData for T {} // n.b. If TLS is used heavily in future, this could be made more efficient with // a proper map. #[doc(hidden)] -pub type Map = ~[Option<(*libc::c_void, TLSValue, LoanState)>]; +pub type Map = ~[Option<(*u8, TLSValue, LoanState)>]; type TLSValue = ~LocalData; // Gets the map from the runtime. Lazily initialises if not done so already. @@ -128,7 +127,7 @@ impl LoanState { } } -fn key_to_key_value<T: 'static>(key: Key<T>) -> *libc::c_void { +fn key_to_key_value<T: 'static>(key: Key<T>) -> *u8 { unsafe { cast::transmute(key) } } @@ -151,7 +150,7 @@ pub fn pop<T: 'static>(key: Key<T>) -> Option<T> { // Move the data out of the `entry` slot via util::replace. // This is guaranteed to succeed because we already matched // on `Some` above. - let data = match util::replace(entry, None) { + let data = match replace(entry, None) { Some((_, data, _)) => data, None => abort() }; @@ -302,7 +301,7 @@ pub fn set<T: 'static>(key: Key<T>, data: T) { let data = ~data as ~LocalData:; fn insertion_position(map: &mut Map, - key: *libc::c_void) -> Option<uint> { + key: *u8) -> Option<uint> { // First see if the map contains this key already let curspot = map.iter().position(|entry| { match *entry { diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 5b0c75ef174..0af8f155c68 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -285,20 +285,16 @@ impl Signed for f32 { #[inline] fn abs(&self) -> f32 { abs(*self) } - /// /// The positive difference of two numbers. Returns `0.0` if the number is less than or /// equal to `other`, otherwise the difference between`self` and `other` is returned. - /// #[inline] fn abs_sub(&self, other: &f32) -> f32 { abs_sub(*self, *other) } - /// /// # Returns /// /// - `1.0` if the number is positive, `+0.0` or `INFINITY` /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` /// - `NAN` if the number is NaN - /// #[inline] fn signum(&self) -> f32 { if self.is_nan() { NAN } else { copysign(1.0, *self) } @@ -330,14 +326,12 @@ impl Round for f32 { #[inline] fn trunc(&self) -> f32 { trunc(*self) } - /// /// The fractional part of the number, satisfying: /// /// ```rust /// let x = 1.65f32; /// assert!(x == x.trunc() + x.fract()) /// ``` - /// #[inline] fn fract(&self) -> f32 { *self - self.trunc() } } @@ -490,7 +484,6 @@ impl Real for f32 { #[inline] fn tanh(&self) -> f32 { tanh(*self) } - /// /// Inverse hyperbolic sine /// /// # Returns @@ -498,7 +491,6 @@ impl Real for f32 { /// - on success, the inverse hyperbolic sine of `self` will be returned /// - `self` if `self` is `0.0`, `-0.0`, `INFINITY`, or `NEG_INFINITY` /// - `NAN` if `self` is `NAN` - /// #[inline] fn asinh(&self) -> f32 { match *self { @@ -507,7 +499,6 @@ impl Real for f32 { } } - /// /// Inverse hyperbolic cosine /// /// # Returns @@ -515,7 +506,6 @@ impl Real for f32 { /// - on success, the inverse hyperbolic cosine of `self` will be returned /// - `INFINITY` if `self` is `INFINITY` /// - `NAN` if `self` is `NAN` or `self < 1.0` (including `NEG_INFINITY`) - /// #[inline] fn acosh(&self) -> f32 { match *self { @@ -524,7 +514,6 @@ impl Real for f32 { } } - /// /// Inverse hyperbolic tangent /// /// # Returns @@ -535,7 +524,6 @@ impl Real for f32 { /// - `NEG_INFINITY` if `self` is `-1.0` /// - `NAN` if the `self` is `NAN` or outside the domain of `-1.0 <= self <= 1.0` /// (including `INFINITY` and `NEG_INFINITY`) - /// #[inline] fn atanh(&self) -> f32 { 0.5 * ((2.0 * *self) / (1.0 - *self)).ln_1p() @@ -643,12 +631,10 @@ impl Float for f32 { ldexp(x, exp as c_int) } - /// /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying: /// /// - `self = x * pow(2, exp)` /// - `0.5 <= abs(x) < 1.0` - /// #[inline] fn frexp(&self) -> (f32, int) { let mut exp = 0; @@ -656,25 +642,19 @@ impl Float for f32 { (x, exp as int) } - /// /// Returns the exponential of the number, minus `1`, in a way that is accurate /// even if the number is close to zero - /// #[inline] fn exp_m1(&self) -> f32 { exp_m1(*self) } - /// /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately /// than if the operations were performed separately - /// #[inline] fn ln_1p(&self) -> f32 { ln_1p(*self) } - /// /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This /// produces a more accurate result with better performance than a separate multiplication /// operation followed by an add. - /// #[inline] fn mul_add(&self, a: f32, b: f32) -> f32 { mul_add(*self, a, b) @@ -708,35 +688,30 @@ impl Float for f32 { // Section: String Conversions // -/// /// Converts a float to a string /// /// # Arguments /// /// * num - The float value -/// #[inline] pub fn to_str(num: f32) -> ~str { let (r, _) = strconv::float_to_str_common( - num, 10u, true, strconv::SignNeg, strconv::DigAll); + num, 10u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false); r } -/// /// Converts a float to a string in hexadecimal format /// /// # Arguments /// /// * num - The float value -/// #[inline] pub fn to_str_hex(num: f32) -> ~str { let (r, _) = strconv::float_to_str_common( - num, 16u, true, strconv::SignNeg, strconv::DigAll); + num, 16u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false); r } -/// /// Converts a float to a string in a given radix, and a flag indicating /// whether it's a special value /// @@ -744,14 +719,12 @@ pub fn to_str_hex(num: f32) -> ~str { /// /// * num - The float value /// * radix - The base to use -/// #[inline] pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) { strconv::float_to_str_common(num, rdx, true, - strconv::SignNeg, strconv::DigAll) + strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false) } -/// /// Converts a float to a string with exactly the number of /// provided significant digits /// @@ -759,15 +732,13 @@ pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) { /// /// * num - The float value /// * digits - The number of significant digits -/// #[inline] pub fn to_str_exact(num: f32, dig: uint) -> ~str { let (r, _) = strconv::float_to_str_common( - num, 10u, true, strconv::SignNeg, strconv::DigExact(dig)); + num, 10u, true, strconv::SignNeg, strconv::DigExact(dig), strconv::ExpNone, false); r } -/// /// Converts a float to a string with a maximum number of /// significant digits /// @@ -775,11 +746,40 @@ pub fn to_str_exact(num: f32, dig: uint) -> ~str { /// /// * num - The float value /// * digits - The number of significant digits -/// #[inline] pub fn to_str_digits(num: f32, dig: uint) -> ~str { let (r, _) = strconv::float_to_str_common( - num, 10u, true, strconv::SignNeg, strconv::DigMax(dig)); + num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpNone, false); + r +} + +/// Converts a float to a string using the exponential notation with exactly the number of +/// provided digits after the decimal point in the significand +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of digits after the decimal point +/// * upper - Use `E` instead of `e` for the exponent sign +#[inline] +pub fn to_str_exp_exact(num: f32, dig: uint, upper: bool) -> ~str { + let (r, _) = strconv::float_to_str_common( + num, 10u, true, strconv::SignNeg, strconv::DigExact(dig), strconv::ExpDec, upper); + r +} + +/// Converts a float to a string using the exponential notation with the maximum number of +/// digits after the decimal point in the significand +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of digits after the decimal point +/// * upper - Use `E` instead of `e` for the exponent sign +#[inline] +pub fn to_str_exp_digits(num: f32, dig: uint, upper: bool) -> ~str { + let (r, _) = strconv::float_to_str_common( + num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpDec, upper); r } @@ -804,14 +804,13 @@ impl num::ToStrRadix for f32 { #[inline] fn to_str_radix(&self, rdx: uint) -> ~str { let (r, special) = strconv::float_to_str_common( - *self, rdx, true, strconv::SignNeg, strconv::DigAll); + *self, rdx, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false); if special { fail!("number has a special value, \ try to_str_radix_special() if those are expected") } r } } -/// /// Convert a string in base 16 to a float. /// Accepts a optional binary exponent. /// @@ -837,7 +836,6 @@ impl num::ToStrRadix for f32 { /// /// `None` if the string did not represent a valid number. Otherwise, /// `Some(n)` where `n` is the floating-point number represented by `[num]`. -/// #[inline] pub fn from_str_hex(num: &str) -> Option<f32> { strconv::from_str_common(num, 16u, true, true, true, @@ -845,7 +843,6 @@ pub fn from_str_hex(num: &str) -> Option<f32> { } impl FromStr for f32 { - /// /// Convert a string in base 10 to a float. /// Accepts a optional decimal exponent. /// @@ -871,7 +868,6 @@ impl FromStr for f32 { /// /// `None` if the string did not represent a valid number. Otherwise, /// `Some(n)` where `n` is the floating-point number represented by `num`. - /// #[inline] fn from_str(val: &str) -> Option<f32> { strconv::from_str_common(val, 10u, true, true, true, @@ -880,7 +876,6 @@ impl FromStr for f32 { } impl num::FromStrRadix for f32 { - /// /// Convert a string in an given base to a float. /// /// Due to possible conflicts, this function does **not** accept @@ -898,7 +893,6 @@ impl num::FromStrRadix for f32 { /// /// `None` if the string did not represent a valid number. Otherwise, /// `Some(n)` where `n` is the floating-point number represented by `num`. - /// #[inline] fn from_str_radix(val: &str, rdx: uint) -> Option<f32> { strconv::from_str_common(val, rdx, true, true, false, diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 95e5797ae93..1155a89876e 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -287,20 +287,16 @@ impl Signed for f64 { #[inline] fn abs(&self) -> f64 { abs(*self) } - /// /// The positive difference of two numbers. Returns `0.0` if the number is less than or /// equal to `other`, otherwise the difference between`self` and `other` is returned. - /// #[inline] fn abs_sub(&self, other: &f64) -> f64 { abs_sub(*self, *other) } - /// /// # Returns /// /// - `1.0` if the number is positive, `+0.0` or `INFINITY` /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` /// - `NAN` if the number is NaN - /// #[inline] fn signum(&self) -> f64 { if self.is_nan() { NAN } else { copysign(1.0, *self) } @@ -332,14 +328,12 @@ impl Round for f64 { #[inline] fn trunc(&self) -> f64 { trunc(*self) } - /// /// The fractional part of the number, satisfying: /// /// ```rust /// let x = 1.65f64; /// assert!(x == x.trunc() + x.fract()) /// ``` - /// #[inline] fn fract(&self) -> f64 { *self - self.trunc() } } @@ -492,7 +486,6 @@ impl Real for f64 { #[inline] fn tanh(&self) -> f64 { tanh(*self) } - /// /// Inverse hyperbolic sine /// /// # Returns @@ -500,7 +493,6 @@ impl Real for f64 { /// - on success, the inverse hyperbolic sine of `self` will be returned /// - `self` if `self` is `0.0`, `-0.0`, `INFINITY`, or `NEG_INFINITY` /// - `NAN` if `self` is `NAN` - /// #[inline] fn asinh(&self) -> f64 { match *self { @@ -509,7 +501,6 @@ impl Real for f64 { } } - /// /// Inverse hyperbolic cosine /// /// # Returns @@ -517,7 +508,6 @@ impl Real for f64 { /// - on success, the inverse hyperbolic cosine of `self` will be returned /// - `INFINITY` if `self` is `INFINITY` /// - `NAN` if `self` is `NAN` or `self < 1.0` (including `NEG_INFINITY`) - /// #[inline] fn acosh(&self) -> f64 { match *self { @@ -526,7 +516,6 @@ impl Real for f64 { } } - /// /// Inverse hyperbolic tangent /// /// # Returns @@ -537,7 +526,6 @@ impl Real for f64 { /// - `NEG_INFINITY` if `self` is `-1.0` /// - `NAN` if the `self` is `NAN` or outside the domain of `-1.0 <= self <= 1.0` /// (including `INFINITY` and `NEG_INFINITY`) - /// #[inline] fn atanh(&self) -> f64 { 0.5 * ((2.0 * *self) / (1.0 - *self)).ln_1p() @@ -645,12 +633,10 @@ impl Float for f64 { ldexp(x, exp as c_int) } - /// /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying: /// /// - `self = x * pow(2, exp)` /// - `0.5 <= abs(x) < 1.0` - /// #[inline] fn frexp(&self) -> (f64, int) { let mut exp = 0; @@ -658,25 +644,19 @@ impl Float for f64 { (x, exp as int) } - /// /// Returns the exponential of the number, minus `1`, in a way that is accurate /// even if the number is close to zero - /// #[inline] fn exp_m1(&self) -> f64 { exp_m1(*self) } - /// /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately /// than if the operations were performed separately - /// #[inline] fn ln_1p(&self) -> f64 { ln_1p(*self) } - /// /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This /// produces a more accurate result with better performance than a separate multiplication /// operation followed by an add. - /// #[inline] fn mul_add(&self, a: f64, b: f64) -> f64 { mul_add(*self, a, b) @@ -710,35 +690,30 @@ impl Float for f64 { // Section: String Conversions // -/// /// Converts a float to a string /// /// # Arguments /// /// * num - The float value -/// #[inline] pub fn to_str(num: f64) -> ~str { let (r, _) = strconv::float_to_str_common( - num, 10u, true, strconv::SignNeg, strconv::DigAll); + num, 10u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false); r } -/// /// Converts a float to a string in hexadecimal format /// /// # Arguments /// /// * num - The float value -/// #[inline] pub fn to_str_hex(num: f64) -> ~str { let (r, _) = strconv::float_to_str_common( - num, 16u, true, strconv::SignNeg, strconv::DigAll); + num, 16u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false); r } -/// /// Converts a float to a string in a given radix, and a flag indicating /// whether it's a special value /// @@ -746,14 +721,12 @@ pub fn to_str_hex(num: f64) -> ~str { /// /// * num - The float value /// * radix - The base to use -/// #[inline] pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) { strconv::float_to_str_common(num, rdx, true, - strconv::SignNeg, strconv::DigAll) + strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false) } -/// /// Converts a float to a string with exactly the number of /// provided significant digits /// @@ -761,15 +734,13 @@ pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) { /// /// * num - The float value /// * digits - The number of significant digits -/// #[inline] pub fn to_str_exact(num: f64, dig: uint) -> ~str { let (r, _) = strconv::float_to_str_common( - num, 10u, true, strconv::SignNeg, strconv::DigExact(dig)); + num, 10u, true, strconv::SignNeg, strconv::DigExact(dig), strconv::ExpNone, false); r } -/// /// Converts a float to a string with a maximum number of /// significant digits /// @@ -777,11 +748,40 @@ pub fn to_str_exact(num: f64, dig: uint) -> ~str { /// /// * num - The float value /// * digits - The number of significant digits -/// #[inline] pub fn to_str_digits(num: f64, dig: uint) -> ~str { let (r, _) = strconv::float_to_str_common( - num, 10u, true, strconv::SignNeg, strconv::DigMax(dig)); + num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpNone, false); + r +} + +/// Converts a float to a string using the exponential notation with exactly the number of +/// provided digits after the decimal point in the significand +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of digits after the decimal point +/// * upper - Use `E` instead of `e` for the exponent sign +#[inline] +pub fn to_str_exp_exact(num: f64, dig: uint, upper: bool) -> ~str { + let (r, _) = strconv::float_to_str_common( + num, 10u, true, strconv::SignNeg, strconv::DigExact(dig), strconv::ExpDec, upper); + r +} + +/// Converts a float to a string using the exponential notation with the maximum number of +/// digits after the decimal point in the significand +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of digits after the decimal point +/// * upper - Use `E` instead of `e` for the exponent sign +#[inline] +pub fn to_str_exp_digits(num: f64, dig: uint, upper: bool) -> ~str { + let (r, _) = strconv::float_to_str_common( + num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpDec, upper); r } @@ -806,14 +806,13 @@ impl num::ToStrRadix for f64 { #[inline] fn to_str_radix(&self, rdx: uint) -> ~str { let (r, special) = strconv::float_to_str_common( - *self, rdx, true, strconv::SignNeg, strconv::DigAll); + *self, rdx, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false); if special { fail!("number has a special value, \ try to_str_radix_special() if those are expected") } r } } -/// /// Convert a string in base 16 to a float. /// Accepts a optional binary exponent. /// @@ -839,7 +838,6 @@ impl num::ToStrRadix for f64 { /// /// `None` if the string did not represent a valid number. Otherwise, /// `Some(n)` where `n` is the floating-point number represented by `[num]`. -/// #[inline] pub fn from_str_hex(num: &str) -> Option<f64> { strconv::from_str_common(num, 16u, true, true, true, @@ -847,7 +845,6 @@ pub fn from_str_hex(num: &str) -> Option<f64> { } impl FromStr for f64 { - /// /// Convert a string in base 10 to a float. /// Accepts a optional decimal exponent. /// @@ -873,7 +870,6 @@ impl FromStr for f64 { /// /// `none` if the string did not represent a valid number. Otherwise, /// `Some(n)` where `n` is the floating-point number represented by `num`. - /// #[inline] fn from_str(val: &str) -> Option<f64> { strconv::from_str_common(val, 10u, true, true, true, @@ -882,7 +878,6 @@ impl FromStr for f64 { } impl num::FromStrRadix for f64 { - /// /// Convert a string in an given base to a float. /// /// Due to possible conflicts, this function does **not** accept @@ -900,7 +895,6 @@ impl num::FromStrRadix for f64 { /// /// `None` if the string did not represent a valid number. Otherwise, /// `Some(n)` where `n` is the floating-point number represented by `num`. - /// #[inline] fn from_str_radix(val: &str, rdx: uint) -> Option<f64> { strconv::from_str_common(val, rdx, true, true, false, diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index bf9e6b739f2..30abe86866e 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -207,11 +207,13 @@ pub fn int_to_str_bytes_common<T:NumCast * # Arguments * - `num` - The number to convert. Accepts any number that * implements the numeric traits. - * - `radix` - Base to use. Accepts only the values 2-36. + * - `radix` - Base to use. Accepts only the values 2-36. If the exponential notation + * is used, then this base is only used for the significand. The exponent + * itself always printed using a base of 10. * - `negative_zero` - Whether to treat the special value `-0` as * `-0` or as `+0`. * - `sign` - How to emit the sign. Options are: - * - `SignNone`: No sign at all. Basically emits `abs(num)`. + * - `SignNone`: No sign at all. The exponent sign is also omitted. * - `SignNeg`: Only `-` on negative values. * - `SignAll`: Both `+` on positive, and `-` on negative numbers. * - `digits` - The amount of digits to use for emitting the @@ -220,6 +222,17 @@ pub fn int_to_str_bytes_common<T:NumCast * fractions! * - `DigMax(uint)`: Maximum N digits, truncating any trailing zeros. * - `DigExact(uint)`: Exactly N digits. + * - `exp_format` - Whether or not to use the exponential (scientific) notation. + * Options are: + * - `ExpNone`: Do not use the exponential notation. + * - `ExpDec`: Use the exponential notation with the exponent having a base of 10, + * and exponent sign being `'e'` or `'E'` depending on the value of + * the `exp_upper` argument. E.g. the number 1000 would be printed as 1e3. + * - `ExpBin`: Use the exponential notation with the exponent having a base of 2, + * and exponent sign being `'p'` or `'P'` depending on the value of + * the `exp_upper` argument. E.g. the number 8 would be printed as 1p3. + * - `exp_capital` - Whether or not to use a capital letter for the exponent sign, if + * exponential notation is desired. * * # Return value * A tuple containing the byte vector, and a boolean flag indicating @@ -229,12 +242,26 @@ pub fn int_to_str_bytes_common<T:NumCast * * # Failure * - Fails if `radix` < 2 or `radix` > 36. + * - Fails if `radix` > 14 and `exp_format` is `ExpDec` due to conflict + * between digit and exponent sign `'e'`. + * - Fails if `radix` > 25 and `exp_format` is `ExpBin` due to conflict + * between digit and exponent sign `'p'`. */ pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+Round+ Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>( num: T, radix: uint, negative_zero: bool, - sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) { + sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool + ) -> (~[u8], bool) { assert!(2 <= radix && radix <= 36); + match exp_format { + ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e' + => fail!("float_to_str_bytes_common: radix {} incompatible with \ + use of 'e' as decimal exponent", radix), + ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p' + => fail!("float_to_str_bytes_common: radix {} incompatible with \ + use of 'p' as binary exponent", radix), + _ => () + } let _0: T = Zero::zero(); let _1: T = One::one(); @@ -260,6 +287,23 @@ pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+Round+ let mut buf: ~[u8] = ~[]; let radix_gen: T = cast(radix as int).unwrap(); + let (num, exp) = match exp_format { + ExpNone => (num, 0i32), + ExpDec | ExpBin => { + if num == _0 { + (num, 0i32) + } else { + let (exp, exp_base) = match exp_format { + ExpDec => (num.abs().log10().floor(), cast::<f64, T>(10.0f64).unwrap()), + ExpBin => (num.abs().log2().floor(), cast::<f64, T>(2.0f64).unwrap()), + ExpNone => unreachable!() + }; + + (num / exp_base.powf(&exp), cast::<T, i32>(exp).unwrap()) + } + } + }; + // First emit the non-fractional part, looping at least once to make // sure at least a `0` gets emitted. let mut deccum = num.trunc(); @@ -413,6 +457,21 @@ pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+Round+ } } + match exp_format { + ExpNone => (), + _ => { + buf.push(match exp_format { + ExpDec if exp_upper => 'E', + ExpDec if !exp_upper => 'e', + ExpBin if exp_upper => 'P', + ExpBin if !exp_upper => 'p', + _ => unreachable!() + } as u8); + + int_to_str_bytes_common(exp, 10, sign, |c| buf.push(c)); + } + } + (buf, false) } @@ -424,9 +483,10 @@ pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+Round+ pub fn float_to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Float+Round+ Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>( num: T, radix: uint, negative_zero: bool, - sign: SignFormat, digits: SignificantDigits) -> (~str, bool) { + sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_capital: bool + ) -> (~str, bool) { let (bytes, special) = float_to_str_bytes_common(num, radix, - negative_zero, sign, digits); + negative_zero, sign, digits, exp_format, exp_capital); (str::from_utf8_owned(bytes).unwrap(), special) } diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 36ce3e93127..93762a3cdd5 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -44,9 +44,9 @@ use unstable::finally::Finally; use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst}; /// Delegates to the libc close() function, returning the same return value. -pub fn close(fd: c_int) -> c_int { +pub fn close(fd: int) -> int { unsafe { - libc::close(fd) + libc::close(fd as c_int) as int } } @@ -57,7 +57,7 @@ static BUF_BYTES : uint = 2048u; pub fn getcwd() -> Path { use c_str::CString; - let mut buf = [0 as libc::c_char, ..BUF_BYTES]; + let mut buf = [0 as c_char, ..BUF_BYTES]; unsafe { if libc::getcwd(buf.as_mut_ptr(), buf.len() as size_t).is_null() { fail!() @@ -164,7 +164,7 @@ pub fn env() -> ~[(~str,~str)] { os::last_os_error()); } let mut result = ~[]; - c_str::from_c_multistring(ch as *libc::c_char, None, |cstr| { + c_str::from_c_multistring(ch as *c_char, None, |cstr| { result.push(cstr.as_str().unwrap().to_owned()); }); FreeEnvironmentStringsA(ch); @@ -173,7 +173,7 @@ pub fn env() -> ~[(~str,~str)] { #[cfg(unix)] unsafe fn get_env_pairs() -> ~[~str] { extern { - fn rust_env_pairs() -> **libc::c_char; + fn rust_env_pairs() -> **c_char; } let environ = rust_env_pairs(); if environ as uint == 0 { @@ -306,9 +306,9 @@ pub struct Pipe { #[cfg(unix)] pub fn pipe() -> Pipe { unsafe { - let mut fds = Pipe {input: 0 as c_int, - out: 0 as c_int }; - assert_eq!(libc::pipe(&mut fds.input), (0 as c_int)); + let mut fds = Pipe {input: 0, + out: 0}; + assert_eq!(libc::pipe(&mut fds.input), 0); return Pipe {input: fds.input, out: fds.out}; } } @@ -321,13 +321,13 @@ pub fn pipe() -> Pipe { // 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 std::run. - let mut fds = Pipe {input: 0 as c_int, - out: 0 as c_int }; + let mut fds = Pipe {input: 0, + out: 0}; let res = libc::pipe(&mut fds.input, 1024 as ::libc::c_uint, (libc::O_BINARY | libc::O_NOINHERIT) as c_int); - assert_eq!(res, 0 as c_int); - assert!((fds.input != -1 as c_int && fds.input != 0 as c_int)); - assert!((fds.out != -1 as c_int && fds.input != 0 as c_int)); + assert_eq!(res, 0); + assert!((fds.input != -1 && fds.input != 0 )); + assert!((fds.out != -1 && fds.input != 0)); return Pipe {input: fds.input, out: fds.out}; } } @@ -699,7 +699,7 @@ pub fn get_exit_status() -> int { } #[cfg(target_os = "macos")] -unsafe fn load_argc_and_argv(argc: c_int, argv: **c_char) -> ~[~str] { +unsafe fn load_argc_and_argv(argc: int, argv: **c_char) -> ~[~str] { let mut args = ~[]; for i in range(0u, argc as uint) { args.push(str::raw::from_c_str(*argv.offset(i as int))); @@ -715,7 +715,7 @@ unsafe fn load_argc_and_argv(argc: c_int, argv: **c_char) -> ~[~str] { #[cfg(target_os = "macos")] fn real_args() -> ~[~str] { unsafe { - let (argc, argv) = (*_NSGetArgc() as c_int, + let (argc, argv) = (*_NSGetArgc() as int, *_NSGetArgv() as **c_char); load_argc_and_argv(argc, argv) } @@ -833,7 +833,7 @@ pub struct MemoryMap { /// Pointer to the memory created or modified by this map. data: *mut u8, /// Number of bytes this map applies to - len: size_t, + len: uint, /// Type of mapping kind: MemoryMapKind } @@ -842,7 +842,7 @@ pub struct MemoryMap { pub enum MemoryMapKind { /// Memory-mapped file. On Windows, the inner pointer is a handle to the mapping, and /// corresponds to `CreateFileMapping`. Elsewhere, it is null. - MapFile(*c_void), + MapFile(*u8), /// Virtual memory map. Usually used to change the permissions of a given chunk of memory. /// Corresponds to `VirtualAlloc` on Windows. MapVirtual @@ -857,7 +857,7 @@ pub enum MapOption { /// The memory should be executable MapExecutable, /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on POSIX. - MapAddr(*c_void), + MapAddr(*u8), /// Create a memory mapping for a file with a given fd. MapFd(c_int), /// When using `MapFd`, the start of the map is `uint` bytes from the start of the file. @@ -881,7 +881,7 @@ pub enum MapError { /// using `MapFd`, the target of the fd didn't have enough resources to fulfill the request. ErrNoMem, /// Unrecognized error. The inner value is the unrecognized errno. - ErrUnknown(libc::c_int), + ErrUnknown(int), /// ## The following are win32-specific /// /// Unsupported combination of protection flags (`MapReadable`/`MapWritable`/`MapExecutable`). @@ -926,12 +926,12 @@ impl MemoryMap { pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> { use libc::off_t; - let mut addr: *c_void = ptr::null(); - let mut prot: c_int = 0; - let mut flags: c_int = libc::MAP_PRIVATE; - let mut fd: c_int = -1; - let mut offset: off_t = 0; - let len = round_up(min_len, page_size()) as size_t; + let mut addr: *u8 = ptr::null(); + let mut prot = 0; + let mut flags = libc::MAP_PRIVATE; + let mut fd = -1; + let mut offset = 0; + let len = round_up(min_len, page_size()); for &o in options.iter() { match o { @@ -952,7 +952,7 @@ impl MemoryMap { if fd == -1 { flags |= libc::MAP_ANON; } let r = unsafe { - libc::mmap(addr, len, prot, flags, fd, offset) + libc::mmap(addr as *c_void, len as size_t, prot, flags, fd, offset) }; if r.equiv(&libc::MAP_FAILED) { Err(match errno() as c_int { @@ -961,7 +961,7 @@ impl MemoryMap { libc::EINVAL => ErrUnaligned, libc::ENODEV => ErrNoMapSupport, libc::ENOMEM => ErrNoMem, - code => ErrUnknown(code) + code => ErrUnknown(code as int) }) } else { Ok(MemoryMap { @@ -987,7 +987,7 @@ impl Drop for MemoryMap { /// Unmap the mapping. Fails the task if `munmap` fails. fn drop(&mut self) { unsafe { - match libc::munmap(self.data as *c_void, self.len) { + match libc::munmap(self.data as *c_void, self.len as libc::size_t) { 0 => (), -1 => match errno() as c_int { libc::EINVAL => error!("invalid addr or len"), @@ -1011,7 +1011,7 @@ impl MemoryMap { let mut executable = false; let mut fd: c_int = -1; let mut offset: uint = 0; - let len = round_up(min_len, page_size()) as SIZE_T; + let len = round_up(min_len, page_size()); for &o in options.iter() { match o { @@ -1040,7 +1040,7 @@ impl MemoryMap { } let r = unsafe { libc::VirtualAlloc(lpAddress, - len, + len as SIZE_T, libc::MEM_COMMIT | libc::MEM_RESERVE, flProtect) }; @@ -1085,7 +1085,7 @@ impl MemoryMap { _ => Ok(MemoryMap { data: r as *mut u8, len: len, - kind: MapFile(mapping as *c_void) + kind: MapFile(mapping as *u8) }) } } @@ -1116,7 +1116,7 @@ impl Drop for MemoryMap { match self.kind { MapVirtual => { if libc::VirtualFree(self.data as *mut c_void, - self.len, + self.len as size_t, libc::MEM_RELEASE) == FALSE { error!("VirtualFree failed: {}", errno()); } diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index 666b8977cc9..cc0705ee76f 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -17,7 +17,7 @@ use clone::Clone; use container::Container; use cmp::Eq; use from_str::FromStr; -use iter::{AdditiveIterator, DoubleEndedIterator, Extendable, Invert, Iterator, Map}; +use iter::{AdditiveIterator, DoubleEndedIterator, Extendable, Rev, Iterator, Map}; use option::{Option, Some, None}; use str; use str::{CharSplits, OwnedStr, Str, StrVector, StrSlice}; @@ -35,7 +35,7 @@ pub type StrComponents<'a> = Map<'a, &'a str, Option<&'a str>, /// /// Each component is yielded as Option<&str> for compatibility with PosixPath, but /// every component in WindowsPath is guaranteed to be Some. -pub type RevStrComponents<'a> = Invert<Map<'a, &'a str, Option<&'a str>, +pub type RevStrComponents<'a> = Rev<Map<'a, &'a str, Option<&'a str>, CharSplits<'a, char>>>; /// Iterator that yields successive components of a Path as &[u8] @@ -571,8 +571,8 @@ impl GenericPath for Path { fn ends_with_path(&self, child: &Path) -> bool { if !child.is_relative() { return false; } - let mut selfit = self.str_components().invert(); - let mut childit = child.str_components().invert(); + let mut selfit = self.str_components().rev(); + let mut childit = child.str_components().rev(); loop { match (selfit.next(), childit.next()) { (Some(a), Some(b)) => if a != b { return false; }, @@ -628,7 +628,7 @@ impl Path { /// Returns an iterator that yields each component of the path in reverse as an Option<&str> /// See str_components() for details. pub fn rev_str_components<'a>(&'a self) -> RevStrComponents<'a> { - self.str_components().invert() + self.str_components().rev() } /// Returns an iterator that yields each component of the path in turn as a &[u8]. diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs index 48e796f0f4a..fe82ac74069 100644 --- a/src/libstd/rc.rs +++ b/src/libstd/rc.rs @@ -78,7 +78,7 @@ impl<T> Drop for Rc<T> { if (*self.ptr).strong == 0 { read_ptr(self.borrow()); // destroy the contained object if (*self.ptr).weak == 0 { - exchange_free(self.ptr as *mut u8 as *i8) + exchange_free(self.ptr as *u8) } } } @@ -153,7 +153,7 @@ impl<T> Drop for Weak<T> { if self.ptr != 0 as *mut RcBox<T> { (*self.ptr).weak -= 1; if (*self.ptr).weak == 0 && (*self.ptr).strong == 0 { - exchange_free(self.ptr as *mut u8 as *i8) + exchange_free(self.ptr as *u8) } } } diff --git a/src/libstd/reflect.rs b/src/libstd/reflect.rs index e619e404dac..c0af649f26c 100644 --- a/src/libstd/reflect.rs +++ b/src/libstd/reflect.rs @@ -17,7 +17,6 @@ Runtime type reflection #[allow(missing_doc)]; use unstable::intrinsics::{Disr, Opaque, TyDesc, TyVisitor}; -use libc::c_void; use mem; use unstable::raw; @@ -28,7 +27,7 @@ use unstable::raw; * then build a MovePtrAdaptor wrapped around your struct. */ pub trait MovePtr { - fn move_ptr(&mut self, adjustment: |*c_void| -> *c_void); + fn move_ptr(&mut self, adjustment: |*u8| -> *u8); fn push_ptr(&mut self); fn pop_ptr(&mut self); } @@ -50,12 +49,12 @@ pub fn MovePtrAdaptor<V:TyVisitor + MovePtr>(v: V) -> MovePtrAdaptor<V> { impl<V:TyVisitor + MovePtr> MovePtrAdaptor<V> { #[inline] pub fn bump(&mut self, sz: uint) { - self.inner.move_ptr(|p| ((p as uint) + sz) as *c_void) + self.inner.move_ptr(|p| ((p as uint) + sz) as *u8) } #[inline] pub fn align(&mut self, a: uint) { - self.inner.move_ptr(|p| align(p as uint, a) as *c_void) + self.inner.move_ptr(|p| align(p as uint, a) as *u8) } #[inline] diff --git a/src/libstd/repr.rs b/src/libstd/repr.rs index 8919f9f8903..e3b34147c01 100644 --- a/src/libstd/repr.rs +++ b/src/libstd/repr.rs @@ -21,7 +21,6 @@ use char; use container::Container; use io; use iter::Iterator; -use libc::c_void; use option::{Some, None}; use ptr; use reflect; @@ -98,13 +97,13 @@ enum VariantState { } pub struct ReprVisitor<'a> { - priv ptr: *c_void, - priv ptr_stk: ~[*c_void], + priv ptr: *u8, + priv ptr_stk: ~[*u8], priv var_stk: ~[VariantState], priv writer: &'a mut io::Writer } -pub fn ReprVisitor<'a>(ptr: *c_void, +pub fn ReprVisitor<'a>(ptr: *u8, writer: &'a mut io::Writer) -> ReprVisitor<'a> { ReprVisitor { ptr: ptr, @@ -116,7 +115,7 @@ pub fn ReprVisitor<'a>(ptr: *c_void, impl<'a> MovePtr for ReprVisitor<'a> { #[inline] - fn move_ptr(&mut self, adjustment: |*c_void| -> *c_void) { + fn move_ptr(&mut self, adjustment: |*u8| -> *u8) { self.ptr = adjustment(self.ptr); } fn push_ptr(&mut self) { @@ -133,7 +132,7 @@ impl<'a> ReprVisitor<'a> { #[inline] pub fn get<T>(&mut self, f: |&mut ReprVisitor, &T|) -> bool { unsafe { - f(self, transmute::<*c_void,&T>(self.ptr)); + f(self, transmute::<*u8,&T>(self.ptr)); } true } @@ -144,7 +143,7 @@ impl<'a> ReprVisitor<'a> { } #[inline] - pub fn visit_ptr_inner(&mut self, ptr: *c_void, inner: *TyDesc) -> bool { + pub fn visit_ptr_inner(&mut self, ptr: *u8, inner: *TyDesc) -> bool { unsafe { // This should call the constructor up above, but due to limiting // issues we have to recreate it here. @@ -200,7 +199,7 @@ impl<'a> ReprVisitor<'a> { } else { self.writer.write(", ".as_bytes()); } - self.visit_ptr_inner(p as *c_void, inner); + self.visit_ptr_inner(p as *u8, inner); p = align(unsafe { ptr::offset(p, sz as int) as uint }, al) as *u8; left -= dec; } @@ -298,20 +297,20 @@ impl<'a> TyVisitor for ReprVisitor<'a> { self.writer.write(['@' as u8]); self.write_mut_qualifier(mtbl); self.get::<&raw::Box<()>>(|this, b| { - let p = ptr::to_unsafe_ptr(&b.data) as *c_void; + let p = ptr::to_unsafe_ptr(&b.data) as *u8; this.visit_ptr_inner(p, inner); }) } fn visit_uniq(&mut self, _mtbl: uint, inner: *TyDesc) -> bool { self.writer.write(['~' as u8]); - self.get::<*c_void>(|this, b| { + self.get::<*u8>(|this, b| { this.visit_ptr_inner(*b, inner); }) } fn visit_ptr(&mut self, mtbl: uint, _inner: *TyDesc) -> bool { - self.get::<*c_void>(|this, p| { + self.get::<*u8>(|this, p| { write!(this.writer, "({} as *", *p); this.write_mut_qualifier(mtbl); this.writer.write("())".as_bytes()); @@ -321,7 +320,7 @@ impl<'a> TyVisitor for ReprVisitor<'a> { fn visit_rptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool { self.writer.write(['&' as u8]); self.write_mut_qualifier(mtbl); - self.get::<*c_void>(|this, p| { + self.get::<*u8>(|this, p| { this.visit_ptr_inner(*p, inner); }) } @@ -584,7 +583,7 @@ impl<'a> TyVisitor for ReprVisitor<'a> { fn visit_opaque_box(&mut self) -> bool { self.writer.write(['@' as u8]); self.get::<&raw::Box<()>>(|this, b| { - let p = ptr::to_unsafe_ptr(&b.data) as *c_void; + let p = ptr::to_unsafe_ptr(&b.data) as *u8; this.visit_ptr_inner(p, b.type_desc); }) } @@ -594,7 +593,7 @@ impl<'a> TyVisitor for ReprVisitor<'a> { pub fn write_repr<T>(writer: &mut io::Writer, object: &T) { unsafe { - let ptr = ptr::to_unsafe_ptr(object) as *c_void; + let ptr = ptr::to_unsafe_ptr(object) as *u8; let tydesc = get_tydesc::<T>(); let u = ReprVisitor(ptr, writer); let mut v = reflect::MovePtrAdaptor(u); diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs new file mode 100644 index 00000000000..6f9be64a73d --- /dev/null +++ b/src/libstd/rt/at_exit_imp.rs @@ -0,0 +1,72 @@ +// 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. + +//! Implementation of running at_exit routines +//! +//! Documentation can be found on the `rt::at_exit` function. + +use cast; +use iter::Iterator; +use option::{Some, None}; +use ptr::RawPtr; +use unstable::sync::Exclusive; +use util; +use vec::OwnedVector; + +type Queue = Exclusive<~[proc()]>; + +// You'll note that these variables are *not* atomic, and this is done on +// purpose. This module is designed to have init() called *once* in a +// single-task context, and then run() is called only once in another +// single-task context. As a result of this, only the `push` function is +// thread-safe, and it assumes that the `init` function has run previously. +static mut QUEUE: *mut Queue = 0 as *mut Queue; +static mut RUNNING: bool = false; + +pub fn init() { + unsafe { + rtassert!(!RUNNING); + rtassert!(QUEUE.is_null()); + let state: ~Queue = ~Exclusive::new(~[]); + QUEUE = cast::transmute(state); + } +} + +pub fn push(f: proc()) { + unsafe { + rtassert!(!RUNNING); + rtassert!(!QUEUE.is_null()); + let state: &mut Queue = cast::transmute(QUEUE); + let mut f = Some(f); + state.with(|arr| { + arr.push(f.take_unwrap()); + }); + } +} + +pub fn run() { + let vec = unsafe { + rtassert!(!RUNNING); + rtassert!(!QUEUE.is_null()); + RUNNING = true; + let state: ~Queue = cast::transmute(QUEUE); + QUEUE = 0 as *mut Queue; + let mut vec = None; + state.with(|arr| { + vec = Some(util::replace(arr, ~[])); + }); + vec.take_unwrap() + }; + + + for f in vec.move_iter() { + f(); + } +} diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index 00195f726cb..6bee8cb70f5 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use libc::{c_void, c_char, size_t, uintptr_t, free, malloc, realloc}; +use libc::{c_void, size_t, free, malloc, realloc}; use ptr::{RawPtr, mut_null}; use unstable::intrinsics::{TyDesc, abort}; use unstable::raw; @@ -31,7 +31,7 @@ fn align_to(size: uint, align: uint) -> uint { /// A wrapper around libc::malloc, aborting on out-of-memory #[inline] -pub unsafe fn malloc_raw(size: uint) -> *mut c_void { +pub unsafe fn malloc_raw(size: uint) -> *mut u8 { // `malloc(0)` may allocate, but it may also return a null pointer // http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html if size == 0 { @@ -42,25 +42,25 @@ pub unsafe fn malloc_raw(size: uint) -> *mut c_void { // we need a non-allocating way to print an error here abort(); } - p + p as *mut u8 } } /// A wrapper around libc::realloc, aborting on out-of-memory #[inline] -pub unsafe fn realloc_raw(ptr: *mut c_void, size: uint) -> *mut c_void { +pub unsafe fn realloc_raw(ptr: *mut u8, size: uint) -> *mut u8 { // `realloc(ptr, 0)` may allocate, but it may also return a null pointer // http://pubs.opengroup.org/onlinepubs/9699919799/functions/realloc.html if size == 0 { - free(ptr as *c_void); + free(ptr as *mut c_void); mut_null() } else { - let p = realloc(ptr, size as size_t); + let p = realloc(ptr as *mut c_void, size as size_t); if p.is_null() { // we need a non-allocating way to print an error here abort(); } - p + p as *mut u8 } } @@ -68,22 +68,22 @@ pub unsafe fn realloc_raw(ptr: *mut c_void, size: uint) -> *mut c_void { #[cfg(not(test))] #[lang="exchange_malloc"] #[inline] -pub unsafe fn exchange_malloc(size: uintptr_t) -> *c_char { - malloc_raw(size as uint) as *c_char +pub unsafe fn exchange_malloc(size: uint) -> *u8 { + malloc_raw(size) as *u8 } // FIXME: #7496 #[cfg(not(test))] #[lang="closure_exchange_malloc"] #[inline] -pub unsafe fn closure_exchange_malloc_(td: *c_char, size: uintptr_t) -> *c_char { +pub unsafe fn closure_exchange_malloc_(td: *u8, size: uint) -> *u8 { closure_exchange_malloc(td, size) } #[inline] -pub unsafe fn closure_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { +pub unsafe fn closure_exchange_malloc(td: *u8, size: uint) -> *u8 { let td = td as *TyDesc; - let size = size as uint; + let size = size; assert!(td.is_not_null()); @@ -93,7 +93,7 @@ pub unsafe fn closure_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { let alloc = p as *mut raw::Box<()>; (*alloc).type_desc = td; - alloc as *c_char + alloc as *u8 } // NB: Calls to free CANNOT be allowed to fail, as throwing an exception from @@ -101,13 +101,13 @@ pub unsafe fn closure_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { #[cfg(not(test))] #[lang="exchange_free"] #[inline] -pub unsafe fn exchange_free_(ptr: *c_char) { +pub unsafe fn exchange_free_(ptr: *u8) { exchange_free(ptr) } #[inline] -pub unsafe fn exchange_free(ptr: *c_char) { - free(ptr as *c_void); +pub unsafe fn exchange_free(ptr: *u8) { + free(ptr as *mut c_void); } #[cfg(test)] diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs index 90179612272..36e3bf858e3 100644 --- a/src/libstd/rt/local_heap.rs +++ b/src/libstd/rt/local_heap.rs @@ -12,8 +12,6 @@ use cast; use iter::Iterator; -use libc::{c_void, uintptr_t}; -use libc; use mem; use ops::Drop; use option::{Option, None, Some}; @@ -223,7 +221,7 @@ impl MemoryRegion { let total_size = size + AllocHeader::size(); let alloc: *AllocHeader = unsafe { - global_heap::realloc_raw(orig_alloc as *mut libc::c_void, + global_heap::realloc_raw(orig_alloc as *mut u8, total_size) as *AllocHeader }; @@ -243,7 +241,7 @@ impl MemoryRegion { self.release(cast::transmute(alloc)); rtassert!(self.live_allocations > 0); self.live_allocations -= 1; - global_heap::exchange_free(alloc as *libc::c_char) + global_heap::exchange_free(alloc as *u8) } } @@ -294,12 +292,12 @@ impl Drop for MemoryRegion { } #[inline] -pub unsafe fn local_malloc(td: *libc::c_char, size: libc::uintptr_t) -> *libc::c_char { +pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 { // XXX: Unsafe borrow for speed. Lame. let task: Option<*mut Task> = Local::try_unsafe_borrow(); match task { Some(task) => { - (*task).heap.alloc(td as *TyDesc, size as uint) as *libc::c_char + (*task).heap.alloc(td as *TyDesc, size) as *u8 } None => rtabort!("local malloc outside of task") } @@ -307,7 +305,7 @@ pub unsafe fn local_malloc(td: *libc::c_char, size: libc::uintptr_t) -> *libc::c // A little compatibility function #[inline] -pub unsafe fn local_free(ptr: *libc::c_char) { +pub unsafe fn local_free(ptr: *u8) { // XXX: Unsafe borrow for speed. Lame. let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow(); match task_ptr { diff --git a/src/libstd/rt/local_ptr.rs b/src/libstd/rt/local_ptr.rs index f4efd8e27d0..d4e57ab19b1 100644 --- a/src/libstd/rt/local_ptr.rs +++ b/src/libstd/rt/local_ptr.rs @@ -81,25 +81,75 @@ pub mod compiled { use cast; use option::{Option, Some, None}; use ptr::RawPtr; - #[cfg(not(test))] use libc::c_void; #[cfg(test)] pub use realstd::rt::shouldnt_be_public::RT_TLS_PTR; #[cfg(not(test))] #[thread_local] - pub static mut RT_TLS_PTR: *mut c_void = 0 as *mut c_void; + pub static mut RT_TLS_PTR: *mut u8 = 0 as *mut u8; pub fn init() {} pub unsafe fn cleanup() {} + // Rationale for all of these functions being inline(never) + // + // The #[thread_local] annotation gets propagated all the way through to + // LLVM, meaning the global is specially treated by LLVM to lower it to an + // efficient sequence of instructions. This also involves dealing with fun + // stuff in object files and whatnot. Regardless, it turns out this causes + // trouble with green threads and lots of optimizations turned on. The + // following case study was done on linux x86_64, but I would imagine that + // other platforms are similar. + // + // On linux, the instruction sequence for loading the tls pointer global + // looks like: + // + // mov %fs:0x0, %rax + // mov -0x8(%rax), %rbx + // + // This code leads me to believe that (%fs:0x0) is a table, and then the + // table contains the TLS values for the process. Hence, the slot at offset + // -0x8 is the task TLS pointer. This leads us to the conclusion that this + // table is the actual thread local part of each thread. The kernel sets up + // the fs segment selector to point at the right region of memory for each + // thread. + // + // Optimizations lead me to believe that this code is lowered to these + // instructions in the LLVM codegen passes, because you'll see code like + // this when everything is optimized: + // + // mov %fs:0x0, %r14 + // mov -0x8(%r14), %rbx + // // do something with %rbx, the rust Task pointer + // + // ... // <- do more things + // + // mov -0x8(%r14), %rbx + // // do something else with %rbx + // + // Note that the optimization done here is that the first load is not + // duplicated during the lower instructions. This means that the %fs:0x0 + // memory location is only dereferenced once. + // + // Normally, this is actually a good thing! With green threads, however, + // it's very possible for the code labeled "do more things" to context + // switch to another thread. If this happens, then we *must* re-load %fs:0x0 + // because it's changed (we're on a different thread). If we don't re-load + // the table location, then we'll be reading the original thread's TLS + // values, not our thread's TLS values. + // + // Hence, we never inline these functions. By never inlining, we're + // guaranteed that loading the table is a local decision which is forced to + // *always* happen. + /// Give a pointer to thread-local storage. /// /// # Safety note /// /// Does not validate the pointer type. - #[inline] + #[inline(never)] // see comments above pub unsafe fn put<T>(sched: ~T) { RT_TLS_PTR = cast::transmute(sched) } @@ -109,7 +159,7 @@ pub mod compiled { /// # Safety note /// /// Does not validate the pointer type. - #[inline] + #[inline(never)] // see comments above pub unsafe fn take<T>() -> ~T { let ptr = RT_TLS_PTR; rtassert!(!ptr.is_null()); @@ -124,7 +174,7 @@ pub mod compiled { /// # Safety note /// /// Does not validate the pointer type. - #[inline] + #[inline(never)] // see comments above pub unsafe fn try_take<T>() -> Option<~T> { let ptr = RT_TLS_PTR; if ptr.is_null() { @@ -143,18 +193,20 @@ pub mod compiled { /// /// Does not validate the pointer type. /// Leaves the old pointer in TLS for speed. - #[inline] + #[inline(never)] // see comments above pub unsafe fn unsafe_take<T>() -> ~T { cast::transmute(RT_TLS_PTR) } /// Check whether there is a thread-local pointer installed. + #[inline(never)] // see comments above pub fn exists() -> bool { unsafe { RT_TLS_PTR.is_not_null() } } + #[inline(never)] // see comments above pub unsafe fn unsafe_borrow<T>() -> *mut T { if RT_TLS_PTR.is_null() { rtabort!("thread-local pointer is null. bogus!"); @@ -162,6 +214,7 @@ pub mod compiled { RT_TLS_PTR as *mut T } + #[inline(never)] // see comments above pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> { if RT_TLS_PTR.is_null() { None @@ -176,7 +229,6 @@ pub mod compiled { /// thread-local value. pub mod native { use cast; - use libc::c_void; use option::{Option, Some, None}; use ptr; use ptr::RawPtr; @@ -205,7 +257,7 @@ pub mod native { #[inline] pub unsafe fn put<T>(sched: ~T) { let key = tls_key(); - let void_ptr: *mut c_void = cast::transmute(sched); + let void_ptr: *mut u8 = cast::transmute(sched); tls::set(key, void_ptr); } @@ -217,7 +269,7 @@ pub mod native { #[inline] pub unsafe fn take<T>() -> ~T { let key = tls_key(); - let void_ptr: *mut c_void = tls::get(key); + let void_ptr: *mut u8 = tls::get(key); if void_ptr.is_null() { rtabort!("thread-local pointer is null. bogus!"); } @@ -235,7 +287,7 @@ pub mod native { pub unsafe fn try_take<T>() -> Option<~T> { match maybe_tls_key() { Some(key) => { - let void_ptr: *mut c_void = tls::get(key); + let void_ptr: *mut u8 = tls::get(key); if void_ptr.is_null() { None } else { @@ -257,7 +309,7 @@ pub mod native { #[inline] pub unsafe fn unsafe_take<T>() -> ~T { let key = tls_key(); - let void_ptr: *mut c_void = tls::get(key); + let void_ptr: *mut u8 = tls::get(key); if void_ptr.is_null() { rtabort!("thread-local pointer is null. bogus!"); } diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 40e9a3ec5b2..7aa966802f2 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -127,6 +127,9 @@ mod util; // Global command line argument storage pub mod args; +// Support for running procedures when a program has exited. +mod at_exit_imp; + /// The default error code of the rust runtime if the main task fails instead /// of exiting cleanly. pub static DEFAULT_ERROR_CODE: int = 101; @@ -171,9 +174,27 @@ pub fn init(argc: int, argv: **u8) { env::init(); logging::init(); local_ptr::init(); + at_exit_imp::init(); } } +/// Enqueues a procedure to run when the runtime is cleaned up +/// +/// The procedure passed to this function will be executed as part of the +/// runtime cleanup phase. For normal rust programs, this means that it will run +/// after all other tasks have exited. +/// +/// The procedure is *not* executed with a local `Task` available to it, so +/// primitives like logging, I/O, channels, spawning, etc, are *not* available. +/// This is meant for "bare bones" usage to clean up runtime details, this is +/// not meant as a general-purpose "let's clean everything up" function. +/// +/// It is forbidden for procedures to register more `at_exit` handlers when they +/// are running, and doing so will lead to a process abort. +pub fn at_exit(f: proc()) { + at_exit_imp::push(f); +} + /// One-time runtime cleanup. /// /// This function is unsafe because it performs no checks to ensure that the @@ -184,6 +205,7 @@ pub fn init(argc: int, argv: **u8) { /// Invoking cleanup while portions of the runtime are still in use may cause /// undefined behavior. pub unsafe fn cleanup() { + at_exit_imp::run(); args::cleanup(); local_ptr::cleanup(); } diff --git a/src/libstd/rt/thread.rs b/src/libstd/rt/thread.rs index f4f4aaa2765..b5262424c06 100644 --- a/src/libstd/rt/thread.rs +++ b/src/libstd/rt/thread.rs @@ -196,7 +196,7 @@ mod imp { use unstable::intrinsics; pub type rust_thread = libc::pthread_t; - pub type rust_thread_return = *libc::c_void; + pub type rust_thread_return = *u8; pub unsafe fn create(stack: uint, p: ~proc()) -> rust_thread { let mut native: libc::pthread_t = intrinsics::uninit(); diff --git a/src/libstd/rt/thread_local_storage.rs b/src/libstd/rt/thread_local_storage.rs index d5affdd5173..40d9523cf3a 100644 --- a/src/libstd/rt/thread_local_storage.rs +++ b/src/libstd/rt/thread_local_storage.rs @@ -10,7 +10,6 @@ #[allow(dead_code)]; -use libc::c_void; #[cfg(unix)] use libc::c_int; #[cfg(unix)] @@ -27,12 +26,12 @@ pub unsafe fn create(key: &mut Key) { } #[cfg(unix)] -pub unsafe fn set(key: Key, value: *mut c_void) { +pub unsafe fn set(key: Key, value: *mut u8) { assert_eq!(0, pthread_setspecific(key, value)); } #[cfg(unix)] -pub unsafe fn get(key: Key) -> *mut c_void { +pub unsafe fn get(key: Key) -> *mut u8 { pthread_getspecific(key) } @@ -55,8 +54,8 @@ type pthread_key_t = ::libc::c_uint; extern { fn pthread_key_create(key: *mut pthread_key_t, dtor: *u8) -> c_int; fn pthread_key_delete(key: pthread_key_t) -> c_int; - fn pthread_getspecific(key: pthread_key_t) -> *mut c_void; - fn pthread_setspecific(key: pthread_key_t, value: *mut c_void) -> c_int; + fn pthread_getspecific(key: pthread_key_t) -> *mut u8; + fn pthread_setspecific(key: pthread_key_t, value: *mut u8) -> c_int; } #[cfg(windows)] @@ -70,13 +69,13 @@ pub unsafe fn create(key: &mut Key) { } #[cfg(windows)] -pub unsafe fn set(key: Key, value: *mut c_void) { - assert!(0 != TlsSetValue(key, value)) +pub unsafe fn set(key: Key, value: *mut u8) { + assert!(0 != TlsSetValue(key, value as *mut ::libc::c_void)) } #[cfg(windows)] -pub unsafe fn get(key: Key) -> *mut c_void { - TlsGetValue(key) +pub unsafe fn get(key: Key) -> *mut u8 { + TlsGetValue(key) as *mut u8 } #[cfg(windows)] diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index ffe254574eb..6f3aa4c4fd0 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -59,7 +59,6 @@ use any::{Any, AnyRefExt}; use c_str::CString; use cast; use kinds::Send; -use libc::{c_void, c_char, size_t}; use option::{Some, None, Option}; use prelude::drop; use ptr::RawPtr; @@ -79,7 +78,7 @@ mod libunwind { #[allow(non_camel_case_types)]; #[allow(dead_code)] // these are just bindings - use libc::{uintptr_t, uint64_t}; + use libc::{uintptr_t}; #[cfg(not(target_arch = "arm"))] #[repr(C)] @@ -118,7 +117,7 @@ mod libunwind { _URC_FAILURE = 9, // used only by ARM EABI } - pub type _Unwind_Exception_Class = uint64_t; + pub type _Unwind_Exception_Class = u64; pub type _Unwind_Word = uintptr_t; @@ -164,6 +163,7 @@ impl Unwinder { pub fn try(&mut self, f: ||) { use unstable::raw::Closure; + use libc::{c_void}; unsafe { let closure: Closure = cast::transmute(f); @@ -365,10 +365,11 @@ pub mod eabi { /// The arguments are normally generated by the compiler, and need to /// have static lifetimes. #[inline(never)] #[cold] // this is the slow path, please never inline this -pub fn begin_unwind_raw(msg: *c_char, file: *c_char, line: size_t) -> ! { +pub fn begin_unwind_raw(msg: *u8, file: *u8, line: uint) -> ! { + use libc::c_char; #[inline] - fn static_char_ptr(p: *c_char) -> &'static str { - let s = unsafe { CString::new(p, false) }; + fn static_char_ptr(p: *u8) -> &'static str { + let s = unsafe { CString::new(p as *c_char, false) }; match s.as_str() { Some(s) => unsafe { cast::transmute::<&str, &'static str>(s) }, None => rtabort!("message wasn't utf8?") diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index a5d5a4677f1..b482e2fb67f 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -70,7 +70,6 @@ pub fn default_sched_threads() -> uint { pub fn dumb_println(args: &fmt::Arguments) { use io; - use libc; struct Stderr; impl io::Writer for Stderr { diff --git a/src/libstd/run.rs b/src/libstd/run.rs index f460d3f4944..f42163791a6 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -331,7 +331,6 @@ pub fn process_output(prog: &str, args: &[~str]) -> Option<ProcessOutput> { #[cfg(test)] mod tests { use prelude::*; - use libc::c_int; use os; use run; use str; @@ -339,6 +338,7 @@ mod tests { use unstable::running_on_valgrind; use io::pipe::PipeStream; use io::{io_error, FileNotFound}; + use libc::c_int; #[test] #[cfg(not(target_os="android"))] // FIXME(#10380) @@ -410,9 +410,9 @@ mod tests { err_fd: Some(pipe_err.out) }).expect("failed to exec `cat`"); - os::close(pipe_in.input); - os::close(pipe_out.out); - os::close(pipe_err.out); + os::close(pipe_in.input as int); + os::close(pipe_out.out as int); + os::close(pipe_err.out as int); do spawn { writeclose(pipe_in.out, "test"); diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 95a02e1631a..22c9ae606d3 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -102,7 +102,7 @@ use clone::{Clone, DeepClone}; use container::{Container, Mutable}; use iter::{Iterator, FromIterator, Extendable, range}; use iter::{Filter, AdditiveIterator, Map}; -use iter::{Invert, DoubleEndedIterator, ExactSize}; +use iter::{Rev, DoubleEndedIterator, ExactSize}; use libc; use num::{Saturating}; use option::{None, Option, Some}; @@ -376,11 +376,11 @@ impl<'a> DoubleEndedIterator<(uint, char)> for CharOffsets<'a> { /// External iterator for a string's characters in reverse order. /// Use with the `std::iter` module. -pub type RevChars<'a> = Invert<Chars<'a>>; +pub type RevChars<'a> = Rev<Chars<'a>>; /// External iterator for a string's characters and their byte offsets in reverse order. /// Use with the `std::iter` module. -pub type RevCharOffsets<'a> = Invert<CharOffsets<'a>>; +pub type RevCharOffsets<'a> = Rev<CharOffsets<'a>>; /// External iterator for a string's bytes. /// Use with the `std::iter` module. @@ -389,7 +389,7 @@ pub type Bytes<'a> = /// External iterator for a string's bytes in reverse order. /// Use with the `std::iter` module. -pub type RevBytes<'a> = Invert<Bytes<'a>>; +pub type RevBytes<'a> = Rev<Bytes<'a>>; /// An iterator over the substrings of a string, separated by `sep`. #[deriving(Clone)] @@ -405,7 +405,7 @@ pub struct CharSplits<'a, Sep> { /// An iterator over the substrings of a string, separated by `sep`, /// starting from the back of the string. -pub type RevCharSplits<'a, Sep> = Invert<CharSplits<'a, Sep>>; +pub type RevCharSplits<'a, Sep> = Rev<CharSplits<'a, Sep>>; /// An iterator over the substrings of a string, separated by `sep`, /// splitting at most `count` times. @@ -486,7 +486,7 @@ for CharSplits<'a, Sep> { let mut next_split = None; if self.only_ascii { - for (idx, byte) in self.string.bytes().enumerate().invert() { + for (idx, byte) in self.string.bytes().enumerate().rev() { if self.sep.matches(byte as char) && byte < 128u8 { next_split = Some((idx, idx + 1)); break; @@ -1980,7 +1980,7 @@ impl<'a> StrSlice<'a> for &'a str { #[inline] fn chars_rev(&self) -> RevChars<'a> { - self.chars().invert() + self.chars().rev() } #[inline] @@ -1990,7 +1990,7 @@ impl<'a> StrSlice<'a> for &'a str { #[inline] fn bytes_rev(&self) -> RevBytes<'a> { - self.bytes().invert() + self.bytes().rev() } #[inline] @@ -2000,7 +2000,7 @@ impl<'a> StrSlice<'a> for &'a str { #[inline] fn char_indices_rev(&self) -> RevCharOffsets<'a> { - self.char_indices().invert() + self.char_indices().rev() } #[inline] @@ -2035,7 +2035,7 @@ impl<'a> StrSlice<'a> for &'a str { #[inline] fn rsplit<Sep: CharEq>(&self, sep: Sep) -> RevCharSplits<'a, Sep> { - self.split(sep).invert() + self.split(sep).rev() } #[inline] @@ -3789,11 +3789,11 @@ mod tests { fn test_rev_split_char_iterator_no_trailing() { let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - let mut split: ~[&str] = data.split('\n').invert().collect(); + let mut split: ~[&str] = data.split('\n').rev().collect(); split.reverse(); assert_eq!(split, ~["", "Märy häd ä little lämb", "Little lämb", ""]); - let mut split: ~[&str] = data.split_terminator('\n').invert().collect(); + let mut split: ~[&str] = data.split_terminator('\n').rev().collect(); split.reverse(); assert_eq!(split, ~["", "Märy häd ä little lämb", "Little lämb"]); } diff --git a/src/libstd/sync/atomics.rs b/src/libstd/sync/atomics.rs index bc9d99c0f37..30d9ede8a43 100644 --- a/src/libstd/sync/atomics.rs +++ b/src/libstd/sync/atomics.rs @@ -24,7 +24,6 @@ use unstable::intrinsics; use cast; use option::{Option,Some,None}; -use libc::c_void; use ops::Drop; use util::NonCopyable; @@ -73,7 +72,7 @@ pub struct AtomicPtr<T> { */ #[unsafe_no_drop_flag] pub struct AtomicOption<T> { - priv p: *mut c_void + priv p: *mut u8 } pub enum Ordering { diff --git a/src/libstd/sync/deque.rs b/src/libstd/sync/deque.rs index e99e9ef0940..e740862fddf 100644 --- a/src/libstd/sync/deque.rs +++ b/src/libstd/sync/deque.rs @@ -389,7 +389,7 @@ impl<T: Send> Buffer<T> { impl<T: Send> Drop for Buffer<T> { fn drop(&mut self) { // It is assumed that all buffers are empty on drop. - unsafe { libc::free(self.storage as *libc::c_void) } + unsafe { libc::free(self.storage as *mut libc::c_void) } } } diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index ead9cec9943..8b9b41f027c 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -728,7 +728,7 @@ mod test_map { fn test_each_reverse_break() { let mut m = TrieMap::new(); - for x in range(uint::max_value - 10000, uint::max_value).invert() { + for x in range(uint::max_value - 10000, uint::max_value).rev() { m.insert(x, x / 2); } @@ -781,7 +781,7 @@ mod test_map { let last = uint::max_value; let mut map = TrieMap::new(); - for x in range(first, last).invert() { + for x in range(first, last).rev() { map.insert(x, x / 2); } @@ -803,7 +803,7 @@ mod test_map { let last = uint::max_value; let mut map = TrieMap::new(); - for x in range(first, last).invert() { + for x in range(first, last).rev() { map.insert(x, x / 2); } diff --git a/src/libstd/unstable/dynamic_lib.rs b/src/libstd/unstable/dynamic_lib.rs index 24568fe13e5..8529b69c6eb 100644 --- a/src/libstd/unstable/dynamic_lib.rs +++ b/src/libstd/unstable/dynamic_lib.rs @@ -18,12 +18,11 @@ A simple wrapper over the platform's dynamic library facilities use c_str::ToCStr; use cast; use path; -use libc; use ops::*; use option::*; use result::*; -pub struct DynamicLibrary { priv handle: *libc::c_void } +pub struct DynamicLibrary { priv handle: *u8} impl Drop for DynamicLibrary { fn drop(&mut self) { @@ -142,14 +141,14 @@ pub mod dl { use str; use result::*; - pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void { + pub unsafe fn open_external(filename: &path::Path) -> *u8 { filename.with_c_str(|raw_name| { - dlopen(raw_name, Lazy as libc::c_int) + dlopen(raw_name, Lazy as libc::c_int) as *u8 }) } - pub unsafe fn open_internal() -> *libc::c_void { - dlopen(ptr::null(), Lazy as libc::c_int) + pub unsafe fn open_internal() -> *u8 { + dlopen(ptr::null(), Lazy as libc::c_int) as *u8 } pub fn check_for_errors_in<T>(f: || -> T) -> Result<T, ~str> { @@ -174,11 +173,11 @@ pub mod dl { } } - pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void { - dlsym(handle, symbol) + pub unsafe fn symbol(handle: *u8, symbol: *libc::c_char) -> *u8 { + dlsym(handle as *libc::c_void, symbol) as *u8 } - pub unsafe fn close(handle: *libc::c_void) { - dlclose(handle); () + pub unsafe fn close(handle: *u8) { + dlclose(handle as *libc::c_void); () } pub enum RTLD { @@ -206,16 +205,16 @@ pub mod dl { use ptr; use result::{Ok, Err, Result}; - pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void { + pub unsafe fn open_external(filename: &path::Path) -> *u8 { os::win32::as_utf16_p(filename.as_str().unwrap(), |raw_name| { - LoadLibraryW(raw_name) + LoadLibraryW(raw_name as *libc::c_void) as *u8 }) } - pub unsafe fn open_internal() -> *libc::c_void { + pub unsafe fn open_internal() -> *u8 { let handle = ptr::null(); GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &handle as **libc::c_void); - handle + handle as *u8 } pub fn check_for_errors_in<T>(f: || -> T) -> Result<T, ~str> { @@ -233,17 +232,17 @@ pub mod dl { } } - pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void { - GetProcAddress(handle, symbol) + pub unsafe fn symbol(handle: *u8, symbol: *libc::c_char) -> *u8 { + GetProcAddress(handle as *libc::c_void, symbol) as *u8 } - pub unsafe fn close(handle: *libc::c_void) { - FreeLibrary(handle); () + pub unsafe fn close(handle: *u8) { + FreeLibrary(handle as *libc::c_void); () } #[link_name = "kernel32"] extern "system" { - fn SetLastError(error: u32); - fn LoadLibraryW(name: *u16) -> *libc::c_void; + fn SetLastError(error: libc::size_t); + fn LoadLibraryW(name: *libc::c_void) -> *libc::c_void; fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *u16, handle: **libc::c_void) -> *libc::c_void; fn GetProcAddress(handle: *libc::c_void, name: *libc::c_char) -> *libc::c_void; diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index 8460152ff7b..046d3fc820d 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -11,25 +11,24 @@ //! Runtime calls emitted by the compiler. use c_str::ToCStr; -use libc::{c_char, size_t, uintptr_t}; #[cold] #[lang="fail_"] -pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! { +pub fn fail_(expr: *u8, file: *u8, line: uint) -> ! { ::rt::begin_unwind_raw(expr, file, line); } #[cold] #[lang="fail_bounds_check"] -pub fn fail_bounds_check(file: *c_char, line: size_t, index: size_t, len: size_t) -> ! { +pub fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! { let msg = format!("index out of bounds: the len is {} but the index is {}", len as uint, index as uint); - msg.with_c_str(|buf| fail_(buf, file, line)) + msg.with_c_str(|buf| fail_(buf as *u8, file, line)) } #[lang="malloc"] #[inline] -pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { +pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 { ::rt::local_heap::local_malloc(td, size) } @@ -38,6 +37,6 @@ pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { // problem occurs, call exit instead. #[lang="free"] #[inline] -pub unsafe fn local_free(ptr: *c_char) { +pub unsafe fn local_free(ptr: *u8) { ::rt::local_heap::local_free(ptr); } diff --git a/src/libstd/unstable/mutex.rs b/src/libstd/unstable/mutex.rs index 81317b7de79..69c6204cc32 100644 --- a/src/libstd/unstable/mutex.rs +++ b/src/libstd/unstable/mutex.rs @@ -48,7 +48,6 @@ #[allow(non_camel_case_types)]; use int; -use libc::c_void; use sync::atomics; pub struct Mutex { @@ -133,38 +132,37 @@ impl Mutex { if cond != 0 { imp::free_cond(cond) } } - unsafe fn getlock(&mut self) -> *c_void { + unsafe fn getlock(&mut self) -> uint{ match self.lock.load(atomics::Relaxed) { 0 => {} - n => return n as *c_void + n => return n } let lock = imp::init_lock(); match self.lock.compare_and_swap(0, lock, atomics::SeqCst) { - 0 => return lock as *c_void, + 0 => return lock, _ => {} } imp::free_lock(lock); - return self.lock.load(atomics::Relaxed) as *c_void; + self.lock.load(atomics::Relaxed) } - unsafe fn getcond(&mut self) -> *c_void { + unsafe fn getcond(&mut self) -> uint { match self.cond.load(atomics::Relaxed) { 0 => {} - n => return n as *c_void + n => return n } let cond = imp::init_cond(); match self.cond.compare_and_swap(0, cond, atomics::SeqCst) { - 0 => return cond as *c_void, + 0 => return cond, _ => {} } imp::free_cond(cond); - return self.cond.load(atomics::Relaxed) as *c_void; + self.cond.load(atomics::Relaxed) } } #[cfg(unix)] mod imp { - use libc::c_void; use libc; use ptr; use rt::global_heap::malloc_raw; @@ -175,49 +173,49 @@ mod imp { type pthread_condattr_t = libc::c_void; pub unsafe fn init_lock() -> uint { - let block = malloc_raw(rust_pthread_mutex_t_size() as uint) as *c_void; + let block = malloc_raw(rust_pthread_mutex_t_size() as uint) as *mut pthread_mutex_t; let n = pthread_mutex_init(block, ptr::null()); assert_eq!(n, 0); return block as uint; } pub unsafe fn init_cond() -> uint { - let block = malloc_raw(rust_pthread_cond_t_size() as uint) as *c_void; + let block = malloc_raw(rust_pthread_cond_t_size() as uint) as *mut pthread_cond_t; let n = pthread_cond_init(block, ptr::null()); assert_eq!(n, 0); return block as uint; } pub unsafe fn free_lock(h: uint) { - let block = h as *c_void; + let block = h as *mut libc::c_void; assert_eq!(pthread_mutex_destroy(block), 0); libc::free(block); } pub unsafe fn free_cond(h: uint) { - let block = h as *c_void; + let block = h as *mut pthread_cond_t; assert_eq!(pthread_cond_destroy(block), 0); libc::free(block); } - pub unsafe fn lock(l: *pthread_mutex_t) { - assert_eq!(pthread_mutex_lock(l), 0); + pub unsafe fn lock(l: uint) { + assert_eq!(pthread_mutex_lock(l as *mut pthread_mutex_t), 0); } - pub unsafe fn trylock(l: *c_void) -> bool { - pthread_mutex_trylock(l) == 0 + pub unsafe fn trylock(l: uint) -> bool { + pthread_mutex_trylock(l as *mut pthread_mutex_t) == 0 } - pub unsafe fn unlock(l: *pthread_mutex_t) { - assert_eq!(pthread_mutex_unlock(l), 0); + pub unsafe fn unlock(l: uint) { + assert_eq!(pthread_mutex_unlock(l as *mut pthread_mutex_t), 0); } - pub unsafe fn wait(cond: *pthread_cond_t, m: *pthread_mutex_t) { - assert_eq!(pthread_cond_wait(cond, m), 0); + pub unsafe fn wait(cond: uint, m: uint) { + assert_eq!(pthread_cond_wait(cond as *mut pthread_cond_t, m as *mut pthread_mutex_t), 0); } - pub unsafe fn signal(cond: *pthread_cond_t) { - assert_eq!(pthread_cond_signal(cond), 0); + pub unsafe fn signal(cond: uint) { + assert_eq!(pthread_cond_signal(cond as *mut pthread_cond_t), 0); } extern { @@ -226,19 +224,19 @@ mod imp { } extern { - fn pthread_mutex_init(lock: *pthread_mutex_t, + fn pthread_mutex_init(lock: *mut pthread_mutex_t, attr: *pthread_mutexattr_t) -> libc::c_int; - fn pthread_mutex_destroy(lock: *pthread_mutex_t) -> libc::c_int; - fn pthread_cond_init(cond: *pthread_cond_t, + fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int; + fn pthread_cond_init(cond: *mut pthread_cond_t, attr: *pthread_condattr_t) -> libc::c_int; - fn pthread_cond_destroy(cond: *pthread_cond_t) -> libc::c_int; - fn pthread_mutex_lock(lock: *pthread_mutex_t) -> libc::c_int; - fn pthread_mutex_trylock(lock: *pthread_mutex_t) -> libc::c_int; - fn pthread_mutex_unlock(lock: *pthread_mutex_t) -> libc::c_int; + fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> libc::c_int; + fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int; + fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int; + fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int; - fn pthread_cond_wait(cond: *pthread_cond_t, - lock: *pthread_mutex_t) -> libc::c_int; - fn pthread_cond_signal(cond: *pthread_cond_t) -> libc::c_int; + fn pthread_cond_wait(cond: *mut pthread_cond_t, + lock: *mut pthread_mutex_t) -> libc::c_int; + fn pthread_cond_signal(cond: *mut pthread_cond_t) -> libc::c_int; } } @@ -265,7 +263,7 @@ mod imp { pub unsafe fn free_lock(h: uint) { DeleteCriticalSection(h as LPCRITICAL_SECTION); - libc::free(h as *c_void); + libc::free(h as *mut c_void); } pub unsafe fn free_cond(h: uint) { @@ -273,25 +271,25 @@ mod imp { libc::CloseHandle(block); } - pub unsafe fn lock(l: *c_void) { + pub unsafe fn lock(l: uint) { EnterCriticalSection(l as LPCRITICAL_SECTION) } - pub unsafe fn trylock(l: *c_void) -> bool { + pub unsafe fn trylock(l: uint) -> bool { TryEnterCriticalSection(l as LPCRITICAL_SECTION) != 0 } - pub unsafe fn unlock(l: *c_void) { + pub unsafe fn unlock(l: uint) { LeaveCriticalSection(l as LPCRITICAL_SECTION) } - pub unsafe fn wait(cond: *c_void, m: *c_void) { + pub unsafe fn wait(cond: uint, m: uint) { unlock(m); WaitForSingleObject(cond as HANDLE, libc::INFINITE); lock(m); } - pub unsafe fn signal(cond: *c_void) { + pub unsafe fn signal(cond: uint) { assert!(SetEvent(cond as HANDLE) != 0); } diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 27e949a5640..41cae372dbb 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -109,7 +109,6 @@ use cmp::{Eq, TotalOrd, Ordering, Less, Equal, Greater}; use cmp; use default::Default; use iter::*; -use libc::{c_char, c_void}; use num::{Integer, CheckedAdd, Saturating}; use option::{None, Option, Some}; use ptr::to_unsafe_ptr; @@ -961,7 +960,7 @@ pub trait ImmutableVector<'a, T> { fn flat_map<U>(&self, f: |t: &T| -> ~[U]) -> ~[U]; /// Returns a pointer to the element at the given index, without doing /// bounds checking. - unsafe fn unsafe_ref(&self, index: uint) -> *T; + unsafe fn unsafe_ref(self, index: uint) -> &'a T; /** * Returns an unsafe pointer to the vector's buffer @@ -1068,7 +1067,7 @@ impl<'a,T> ImmutableVector<'a, T> for &'a [T] { #[inline] fn rev_iter(self) -> RevItems<'a, T> { - self.iter().invert() + self.iter().rev() } #[inline] @@ -1150,8 +1149,8 @@ impl<'a,T> ImmutableVector<'a, T> for &'a [T] { } #[inline] - unsafe fn unsafe_ref(&self, index: uint) -> *T { - self.repr().data.offset(index as int) + unsafe fn unsafe_ref(self, index: uint) -> &'a T { + cast::transmute(self.repr().data.offset(index as int)) } #[inline] @@ -1465,7 +1464,7 @@ impl<T> OwnedVector<T> for ~[T] { #[inline] fn move_rev_iter(self) -> RevMoveItems<T> { - self.move_iter().invert() + self.move_iter().rev() } fn reserve(&mut self, n: uint) { @@ -1478,8 +1477,8 @@ impl<T> OwnedVector<T> for ~[T] { if alloc / mem::nonzero_size_of::<T>() != n || size < alloc { fail!("vector size is too large: {}", n); } - *ptr = realloc_raw(*ptr as *mut c_void, size) - as *mut Vec<()>; + *ptr = realloc_raw(*ptr as *mut u8, size) + as *mut Vec<()>; (**ptr).alloc = alloc; } } @@ -1513,7 +1512,7 @@ impl<T> OwnedVector<T> for ~[T] { let ptr: *mut *mut Vec<()> = cast::transmute(self); let alloc = (**ptr).fill; let size = alloc + mem::size_of::<Vec<()>>(); - *ptr = realloc_raw(*ptr as *mut c_void, size) as *mut Vec<()>; + *ptr = realloc_raw(*ptr as *mut u8, size) as *mut Vec<()>; (**ptr).alloc = alloc; } } @@ -2184,7 +2183,7 @@ pub trait MutableVector<'a, T> { fn move_from(self, src: ~[T], start: uint, end: uint) -> uint; /// Returns an unsafe mutable pointer to the element in index - unsafe fn unsafe_mut_ref(self, index: uint) -> *mut T; + unsafe fn unsafe_mut_ref(self, index: uint) -> &'a mut T; /// Return an unsafe mutable pointer to the vector's buffer. /// @@ -2301,7 +2300,7 @@ impl<'a,T> MutableVector<'a, T> for &'a mut [T] { #[inline] fn mut_rev_iter(self) -> RevMutItems<'a, T> { - self.mut_iter().invert() + self.mut_iter().rev() } #[inline] @@ -2362,8 +2361,8 @@ impl<'a,T> MutableVector<'a, T> for &'a mut [T] { } #[inline] - unsafe fn unsafe_mut_ref(self, index: uint) -> *mut T { - ptr::mut_offset(self.repr().data as *mut T, index as int) + unsafe fn unsafe_mut_ref(self, index: uint) -> &'a mut T { + cast::transmute(ptr::mut_offset(self.repr().data as *mut T, index as int)) } #[inline] @@ -2715,7 +2714,7 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> { } iterator!{struct Items -> *T, &'a T} -pub type RevItems<'a, T> = Invert<Items<'a, T>>; +pub type RevItems<'a, T> = Rev<Items<'a, T>>; impl<'a, T> ExactSize<&'a T> for Items<'a, T> {} impl<'a, T> ExactSize<&'a mut T> for MutItems<'a, T> {} @@ -2725,7 +2724,7 @@ impl<'a, T> Clone for Items<'a, T> { } iterator!{struct MutItems -> *mut T, &'a mut T} -pub type RevMutItems<'a, T> = Invert<MutItems<'a, T>>; +pub type RevMutItems<'a, T> = Rev<MutItems<'a, T>>; /// An iterator over the subslices of the vector which are separated /// by elements that match `pred`. @@ -2877,13 +2876,13 @@ impl<T> Drop for MoveItems<T> { // destroy the remaining elements for _x in *self {} unsafe { - exchange_free(self.allocation as *u8 as *c_char) + exchange_free(self.allocation as *u8) } } } /// An iterator that moves out of a vector in reverse order. -pub type RevMoveItems<T> = Invert<MoveItems<T>>; +pub type RevMoveItems<T> = Rev<MoveItems<T>>; impl<A> FromIterator<A> for ~[A] { fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> ~[A] { @@ -3986,7 +3985,7 @@ mod tests { assert_eq!(v.chunks(3).collect::<~[&[int]]>(), ~[&[1i,2,3], &[4,5]]); assert_eq!(v.chunks(6).collect::<~[&[int]]>(), ~[&[1i,2,3,4,5]]); - assert_eq!(v.chunks(2).invert().collect::<~[&[int]]>(), ~[&[5i], &[3,4], &[1,2]]); + assert_eq!(v.chunks(2).rev().collect::<~[&[int]]>(), ~[&[5i], &[3,4], &[1,2]]); let it = v.chunks(2); assert_eq!(it.indexable(), 3); assert_eq!(it.idx(0).unwrap(), &[1,2]); @@ -4242,9 +4241,9 @@ mod tests { } #[test] - fn test_mut_splitator_invert() { + fn test_mut_splitator_rev() { let mut xs = [1,2,0,3,4,0,0,5,6,0]; - for slice in xs.mut_split(|x| *x == 0).invert().take(4) { + for slice in xs.mut_split(|x| *x == 0).rev().take(4) { slice.reverse(); } assert_eq!(xs, [1,2,0,4,3,0,0,6,5,0]); @@ -4263,9 +4262,9 @@ mod tests { } #[test] - fn test_mut_chunks_invert() { + fn test_mut_chunks_rev() { let mut v = [0u8, 1, 2, 3, 4, 5, 6]; - for (i, chunk) in v.mut_chunks(3).invert().enumerate() { + for (i, chunk) in v.mut_chunks(3).rev().enumerate() { for x in chunk.mut_iter() { *x = i as u8; } diff --git a/src/libstd/vec_ng.rs b/src/libstd/vec_ng.rs new file mode 100644 index 00000000000..e503497d95d --- /dev/null +++ b/src/libstd/vec_ng.rs @@ -0,0 +1,231 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <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. + +// Migrate documentation over from `std::vec` when it is removed. +#[doc(hidden)]; + +use prelude::*; +use container::Container; +use mem::size_of; +use cast::{forget, transmute}; +use rt::global_heap::{malloc_raw, realloc_raw}; +use vec::Items; +use unstable::raw::Slice; +use ptr::{offset, read_ptr}; +use libc::{free, c_void}; +use unstable::intrinsics::move_val_init; + +pub struct Vec<T> { + priv len: uint, + priv cap: uint, + priv ptr: *mut T +} + +impl<T> Vec<T> { + #[inline] + pub fn new() -> Vec<T> { + Vec { len: 0, cap: 0, ptr: 0 as *mut T } + } + + pub fn with_capacity(capacity: uint) -> Vec<T> { + if capacity == 0 { + Vec::new() + } else { + let size = capacity.checked_mul(&size_of::<T>()).expect("capacity overflow"); + let ptr = unsafe { malloc_raw(size) }; + Vec { len: 0, cap: capacity, ptr: ptr as *mut T } + } + } + + pub fn from_fn(length: uint, op: |uint| -> T) -> Vec<T> { + unsafe { + let mut xs = Vec::with_capacity(length); + while xs.len < length { + move_val_init(xs.as_mut_slice().unsafe_mut_ref(xs.len), op(xs.len)); + xs.len += 1; + } + xs + } + } +} + +impl<T: Clone> Vec<T> { + pub fn from_elem(length: uint, value: T) -> Vec<T> { + unsafe { + let mut xs = Vec::with_capacity(length); + while xs.len < length { + move_val_init(xs.as_mut_slice().unsafe_mut_ref(xs.len), value.clone()); + xs.len += 1; + } + xs + } + } +} + +impl<T> Container for Vec<T> { + #[inline] + fn len(&self) -> uint { + self.len + } +} + +impl<T> Vec<T> { + #[inline] + pub fn capacity(&self) -> uint { + self.cap + } + + pub fn reserve_exact(&mut self, capacity: uint) { + if capacity >= self.len { + let size = capacity.checked_mul(&size_of::<T>()).expect("capacity overflow"); + self.cap = capacity; + unsafe { + self.ptr = realloc_raw(self.ptr as *mut u8, size) as *mut T; + } + } + } + + pub fn shrink_to_fit(&mut self) { + if self.len == 0 { + unsafe { free(self.ptr as *mut c_void) }; + self.cap = 0; + self.ptr = 0 as *mut T; + } else { + unsafe { + // Overflow check is unnecessary as the vector is already at least this large. + self.ptr = realloc_raw(self.ptr as *mut u8, self.len * size_of::<T>()) as *mut T; + } + self.cap = self.len; + } + } + + #[inline] + pub fn pop(&mut self) -> Option<T> { + if self.len == 0 { + None + } else { + unsafe { + self.len -= 1; + Some(read_ptr(self.as_slice().unsafe_ref(self.len()))) + } + } + } + + #[inline] + pub fn push(&mut self, value: T) { + if self.len == self.cap { + if self.cap == 0 { self.cap += 2 } + let old_size = self.cap * size_of::<T>(); + self.cap = self.cap * 2; + let size = old_size * 2; + if old_size > size { fail!("capacity overflow") } + unsafe { + self.ptr = realloc_raw(self.ptr as *mut u8, size) as *mut T; + } + } + + unsafe { + let end = offset(self.ptr as *T, self.len as int) as *mut T; + move_val_init(&mut *end, value); + self.len += 1; + } + } + + pub fn truncate(&mut self, len: uint) { + unsafe { + let mut i = len; + // drop any extra elements + while i < self.len { + read_ptr(self.as_slice().unsafe_ref(i)); + i += 1; + } + } + self.len = len; + } + + #[inline] + pub fn as_slice<'a>(&'a self) -> &'a [T] { + let slice = Slice { data: self.ptr as *T, len: self.len }; + unsafe { transmute(slice) } + } + + #[inline] + pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] { + let slice = Slice { data: self.ptr as *T, len: self.len }; + unsafe { transmute(slice) } + } + + #[inline] + pub fn move_iter(self) -> MoveItems<T> { + unsafe { + let iter = transmute(self.as_slice().iter()); + let ptr = self.ptr as *mut c_void; + forget(self); + MoveItems { allocation: ptr, iter: iter } + } + } + + #[inline] + pub unsafe fn set_len(&mut self, len: uint) { + self.len = len; + } +} + + +#[unsafe_destructor] +impl<T> Drop for Vec<T> { + fn drop(&mut self) { + unsafe { + for x in self.as_mut_slice().iter() { + read_ptr(x); + } + free(self.ptr as *mut c_void) + } + } +} + +pub struct MoveItems<T> { + priv allocation: *mut c_void, // the block of memory allocated for the vector + priv iter: Items<'static, T> +} + +impl<T> Iterator<T> for MoveItems<T> { + #[inline] + fn next(&mut self) -> Option<T> { + unsafe { + self.iter.next().map(|x| read_ptr(x)) + } + } + + #[inline] + fn size_hint(&self) -> (uint, Option<uint>) { + self.iter.size_hint() + } +} + +impl<T> DoubleEndedIterator<T> for MoveItems<T> { + #[inline] + fn next_back(&mut self) -> Option<T> { + unsafe { + self.iter.next_back().map(|x| read_ptr(x)) + } + } +} + +#[unsafe_destructor] +impl<T> Drop for MoveItems<T> { + fn drop(&mut self) { + // destroy the remaining elements + for _x in *self {} + unsafe { + free(self.allocation) + } + } +} diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index ebf02f7691e..d81999c1e5f 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -308,10 +308,6 @@ impl CodeMap { } } - pub fn adjust_span(&self, sp: Span) -> Span { - sp - } - pub fn span_to_str(&self, sp: Span) -> ~str { { let files = self.files.borrow(); diff --git a/src/libsyntax/crateid.rs b/src/libsyntax/crateid.rs index 0bb1eec512b..0831f319ce7 100644 --- a/src/libsyntax/crateid.rs +++ b/src/libsyntax/crateid.rs @@ -70,7 +70,11 @@ impl FromStr for CrateId { }; let version = if !hash_version.is_empty() { - Some(hash_version.to_owned()) + if hash_version == "0.0" { + None + } else { + Some(hash_version.to_owned()) + } } else { None }; @@ -93,6 +97,10 @@ impl CrateId { Some(ref version) => version.as_slice(), } } + + pub fn short_name_with_version(&self) -> ~str { + format!("{}-{}", self.name, self.version_or_default()) + } } #[test] diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 0eca56e2691..a9d3f6fea24 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -19,12 +19,16 @@ use extra::term; static BUG_REPORT_URL: &'static str = "http://static.rust-lang.org/doc/master/complement-bugreport.html"; +// maximum number of lines we will print for each error; arbitrary. +static MAX_LINES: uint = 6u; pub trait Emitter { fn emit(&self, cmsp: Option<(&codemap::CodeMap, Span)>, msg: &str, lvl: Level); + fn custom_emit(&self, cm: &codemap::CodeMap, + sp: Span, msg: &str, lvl: Level); } /// This structure is used to signify that a task has failed with a fatal error @@ -55,6 +59,9 @@ impl SpanHandler { pub fn span_note(@self, sp: Span, msg: &str) { self.handler.emit(Some((&*self.cm, sp)), msg, Note); } + pub fn span_end_note(@self, sp: Span, msg: &str) { + self.handler.custom_emit(&*self.cm, sp, msg, Note); + } pub fn span_bug(@self, sp: Span, msg: &str) -> ! { self.span_fatal(sp, ice_msg(msg)); } @@ -122,6 +129,10 @@ impl Handler { lvl: Level) { self.emit.emit(cmsp, msg, lvl); } + pub fn custom_emit(@self, cm: &codemap::CodeMap, + sp: Span, msg: &str, lvl: Level) { + self.emit.custom_emit(cm, sp, msg, lvl); + } } pub fn ice_msg(msg: &str) -> ~str { @@ -239,17 +250,34 @@ impl Emitter for DefaultEmitter { msg: &str, lvl: Level) { match cmsp { - Some((cm, sp)) => { - let sp = cm.adjust_span(sp); - let ss = cm.span_to_str(sp); - let lines = cm.span_to_lines(sp); - print_diagnostic(ss, lvl, msg); - highlight_lines(cm, sp, lvl, lines); - print_macro_backtrace(cm, sp); - } + Some((cm, sp)) => emit(cm, sp, msg, lvl, false), None => print_diagnostic("", lvl, msg), } } + + fn custom_emit(&self, cm: &codemap::CodeMap, + sp: Span, msg: &str, lvl: Level) { + emit(cm, sp, msg, lvl, true); + } +} + +fn emit(cm: &codemap::CodeMap, sp: Span, + msg: &str, lvl: Level, custom: bool) { + let ss = cm.span_to_str(sp); + let lines = cm.span_to_lines(sp); + if custom { + // we want to tell compiletest/runtest to look at the last line of the + // span (since `custom_highlight_lines` displays an arrow to the end of + // the span) + let span_end = Span { lo: sp.hi, hi: sp.hi, expn_info: sp.expn_info}; + let ses = cm.span_to_str(span_end); + print_diagnostic(ses, lvl, msg); + custom_highlight_lines(cm, sp, lvl, lines); + } else { + print_diagnostic(ss, lvl, msg); + highlight_lines(cm, sp, lvl, lines); + } + print_macro_backtrace(cm, sp); } fn highlight_lines(cm: &codemap::CodeMap, @@ -260,12 +288,10 @@ fn highlight_lines(cm: &codemap::CodeMap, let mut err = io::stderr(); let err = &mut err as &mut io::Writer; - // arbitrarily only print up to six lines of the error - let max_lines = 6u; let mut elided = false; let mut display_lines = lines.lines.as_slice(); - if display_lines.len() > max_lines { - display_lines = display_lines.slice(0u, max_lines); + if display_lines.len() > MAX_LINES { + display_lines = display_lines.slice(0u, MAX_LINES); elided = true; } // Print the offending lines @@ -319,6 +345,44 @@ fn highlight_lines(cm: &codemap::CodeMap, } } +// Here are the differences between this and the normal `highlight_lines`: +// `custom_highlight_lines` will always put arrow on the last byte of the +// span (instead of the first byte). Also, when the span is too long (more +// than 6 lines), `custom_highlight_lines` will print the first line, then +// dot dot dot, then last line, whereas `highlight_lines` prints the first +// six lines. +fn custom_highlight_lines(cm: &codemap::CodeMap, + sp: Span, + lvl: Level, + lines: &codemap::FileLines) { + let fm = lines.file; + let mut err = io::stderr(); + let err = &mut err as &mut io::Writer; + + let lines = lines.lines.as_slice(); + if lines.len() > MAX_LINES { + write!(err, "{}:{} {}\n", fm.name, + lines[0] + 1, fm.get_line(lines[0] as int)); + write!(err, "...\n"); + let last_line = lines[lines.len()-1]; + write!(err, "{}:{} {}\n", fm.name, + last_line + 1, fm.get_line(last_line as int)); + } else { + for line in lines.iter() { + write!(err, "{}:{} {}\n", fm.name, + *line + 1, fm.get_line(*line as int)); + } + } + let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1]+1); + let hi = cm.lookup_char_pos(sp.hi); + // Span seems to use half-opened interval, so subtract 1 + let skip = last_line_start.len() + hi.col.to_uint() - 1; + let mut s = ~""; + skip.times(|| s.push_char(' ')); + s.push_char('^'); + print_maybe_styled(s + "\n", term::attr::ForegroundColor(lvl.color())); +} + fn print_macro_backtrace(cm: &codemap::CodeMap, sp: Span) { for ei in sp.expn_info.iter() { let ss = ei.callee.span.as_ref().map_or(~"", |span| cm.span_to_str(*span)); diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index fbaa086c7d3..2c817365390 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -556,7 +556,7 @@ impl SyntaxEnv { } fn find_escape_frame<'a>(&'a mut self) -> &'a mut MapChainFrame { - for (i, frame) in self.chain.mut_iter().enumerate().invert() { + for (i, frame) in self.chain.mut_iter().enumerate().rev() { if !frame.info.macros_escape || i == 0 { return frame } @@ -565,7 +565,7 @@ impl SyntaxEnv { } pub fn find<'a>(&'a self, k: &Name) -> Option<&'a SyntaxExtension> { - for frame in self.chain.iter().invert() { + for frame in self.chain.iter().rev() { match frame.map.find(k) { Some(v) => return Some(v), None => {} diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index 8e7947a3d31..bbf6f7fff7f 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -687,6 +687,8 @@ impl<'a> Context<'a> { "b" => "Bool", "c" => "Char", "d" | "i" => "Signed", + "e" => "LowerExp", + "E" => "UpperExp", "f" => "Float", "o" => "Octal", "p" => "Pointer", diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4e1703fe6b0..557e7e04ebf 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2021,7 +2021,7 @@ impl Parser { let es = self.parse_unspanned_seq( &token::LPAREN, &token::RPAREN, - seq_sep_trailing_disallowed(token::COMMA), + seq_sep_trailing_allowed(token::COMMA), |p| p.parse_expr() ); hi = self.last_span.hi; @@ -2994,6 +2994,7 @@ impl Parser { if self.look_ahead(1, |t| *t != token::RPAREN) { while self.token == token::COMMA { self.bump(); + if self.token == token::RPAREN { break; } fields.push(self.parse_pat()); } } @@ -3573,7 +3574,7 @@ impl Parser { self.parse_unspanned_seq( &token::LPAREN, &token::RPAREN, - seq_sep_trailing_disallowed(token::COMMA), + seq_sep_trailing_allowed(token::COMMA), |p| { if p.token == token::DOTDOTDOT { p.bump(); diff --git a/src/llvm b/src/llvm -Subproject 8841dcef357e051c34a46030db7c7b1a83f9b1d +Subproject 535989a92ce1f6f6488c94a2c8f4ed438349f16 diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 95b950973d1..96cd67dcec4 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2013-12-29 +2014-01-22 diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index 0a37e93f6e7..4c75ca494ff 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -52,13 +52,13 @@ fn descending<M: MutableMap<uint, uint>>(map: &mut M, n_keys: uint) { println!(" Descending integers:"); timed("insert", || { - for i in range(0, n_keys).invert() { + for i in range(0, n_keys).rev() { map.insert(i, i + 1); } }); timed("search", || { - for i in range(0, n_keys).invert() { + for i in range(0, n_keys).rev() { assert_eq!(map.find(&i).unwrap(), &(i + 1)); } }); diff --git a/src/test/bench/shootout-meteor.rs b/src/test/bench/shootout-meteor.rs index c5b01e68fc4..53d188962e8 100644 --- a/src/test/bench/shootout-meteor.rs +++ b/src/test/bench/shootout-meteor.rs @@ -220,7 +220,7 @@ fn handle_sol(raw_sol: &List<u64>, data: &mut Data) -> bool { // reverse order, i.e. the board rotated by half a turn. data.nb += 2; let sol1 = to_utf8(raw_sol); - let sol2: ~str = sol1.chars().invert().collect(); + let sol2: ~str = sol1.chars().rev().collect(); if data.nb == 2 { data.min = sol1.clone(); diff --git a/src/test/compile-fail/borrowck-borrow-mut-object-twice.rs b/src/test/compile-fail/borrowck-borrow-mut-object-twice.rs index 502d7e017b5..c338aac2ddf 100644 --- a/src/test/compile-fail/borrowck-borrow-mut-object-twice.rs +++ b/src/test/compile-fail/borrowck-borrow-mut-object-twice.rs @@ -18,7 +18,7 @@ trait Foo { fn test(x: &mut Foo) { let _y = x.f1(); - x.f2(); //~ ERROR cannot borrow `*x` as mutable more than once at a time + x.f2(); //~ ERROR cannot borrow `*x` because it is already borrowed as mutable } fn main() {} diff --git a/src/test/compile-fail/borrowck-report-with-custom-diagnostic.rs b/src/test/compile-fail/borrowck-report-with-custom-diagnostic.rs new file mode 100644 index 00000000000..3c01045369f --- /dev/null +++ b/src/test/compile-fail/borrowck-report-with-custom-diagnostic.rs @@ -0,0 +1,31 @@ +#[allow(dead_code)]; +fn main() { + // Original borrow ends at end of function + let mut x = 1u; + let y = &mut x; + let z = &x; //~ ERROR cannot borrow +} +//~^ NOTE previous borrow ends here + +fn foo() { + match true { + true => { + // Original borrow ends at end of match arm + let mut x = 1u; + let y = &x; + let z = &mut x; //~ ERROR cannot borrow + } + //~^ NOTE previous borrow ends here + false => () + } +} + +fn bar() { + // Original borrow ends at end of closure + || { + let mut x = 1u; + let y = &mut x; + let z = &mut x; //~ ERROR cannot borrow + }; + //~^ NOTE previous borrow ends here +} diff --git a/src/test/compile-fail/mut-cant-alias.rs b/src/test/compile-fail/mut-cant-alias.rs index f031467328f..5b8079b832e 100644 --- a/src/test/compile-fail/mut-cant-alias.rs +++ b/src/test/compile-fail/mut-cant-alias.rs @@ -14,5 +14,5 @@ fn main() { let m = RefCell::new(0); let mut b = m.borrow_mut(); let b1 = b.get(); - let b2 = b.get(); //~ ERROR cannot borrow `b` as mutable more than once at a time + let b2 = b.get(); //~ ERROR cannot borrow `b` because it is already borrowed as mutable } diff --git a/src/test/compile-fail/vec-mut-iter-borrow.rs b/src/test/compile-fail/vec-mut-iter-borrow.rs index 19c786b553f..21ffc1ae7f9 100644 --- a/src/test/compile-fail/vec-mut-iter-borrow.rs +++ b/src/test/compile-fail/vec-mut-iter-borrow.rs @@ -12,6 +12,6 @@ fn main() { let mut xs = ~[1, 2, 3, 4]; for x in xs.mut_iter() { - xs.push(1) //~ ERROR cannot borrow `xs` as mutable + xs.push(1) //~ ERROR cannot borrow `xs` because it is already borrowed as mutable } } diff --git a/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs b/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs index 0ba2bfd1595..a8b7dc3d382 100644 --- a/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs +++ b/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs @@ -9,6 +9,7 @@ // except according to those terms. // xfail-fast +// xfail-android #[deny(unused_variable)]; diff --git a/src/test/run-pass/exponential-notation.rs b/src/test/run-pass/exponential-notation.rs new file mode 100644 index 00000000000..254c093e703 --- /dev/null +++ b/src/test/run-pass/exponential-notation.rs @@ -0,0 +1,34 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <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. + +#[feature(macro_rules)]; + +use s = std::num::strconv; +use to_str = std::num::strconv::float_to_str_common; + +macro_rules! t(($a:expr, $b:expr) => { { let (r, _) = $a; assert_eq!(r, $b.to_owned()) } }) + +pub fn main() { + // Basic usage + t!(to_str(1.2345678e-5, 10u, true, s::SignNeg, s::DigMax(6), s::ExpDec, false), + "1.234568e-5") + + // Hexadecimal output + t!(to_str(7.281738281250e+01, 16u, true, s::SignAll, s::DigMax(6), s::ExpBin, false), + "+1.2345p+6") + t!(to_str(-1.777768135071e-02, 16u, true, s::SignAll, s::DigMax(6), s::ExpBin, false), + "-1.2345p-6") + + // Some denormals + t!(to_str(4.9406564584124654e-324, 10u, true, s::SignNeg, s::DigMax(6), s::ExpBin, false), + "1p-1074") + t!(to_str(2.2250738585072009e-308, 10u, true, s::SignNeg, s::DigMax(6), s::ExpBin, false), + "1p-1022") +} diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 76759d04ab4..610cba1eb1f 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -219,6 +219,14 @@ pub fn main() { t!(format!("{:+10.3f}", 1.0f64), " +1.000"); t!(format!("{:+10.3f}", -1.0f64), " -1.000"); + t!(format!("{:e}", 1.2345e6f32), "1.2345e6"); + t!(format!("{:e}", 1.2345e6f64), "1.2345e6"); + t!(format!("{:E}", 1.2345e6f64), "1.2345E6"); + t!(format!("{:.3e}", 1.2345e6f64), "1.234e6"); + t!(format!("{:10.3e}", 1.2345e6f64), " 1.234e6"); + t!(format!("{:+10.3e}", 1.2345e6f64), " +1.234e6"); + t!(format!("{:+10.3e}", -1.2345e6f64), " -1.234e6"); + // Escaping t!(format!("\\{"), "{"); t!(format!("\\}"), "}"); diff --git a/src/test/run-pass/trailing-comma.rs b/src/test/run-pass/trailing-comma.rs new file mode 100644 index 00000000000..13d79959f81 --- /dev/null +++ b/src/test/run-pass/trailing-comma.rs @@ -0,0 +1,16 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <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. + +fn f(_: int,) {} + +pub fn main() { + f(0,); + let (_, _,) = (1, 1,); +} |
