diff options
295 files changed, 5698 insertions, 9574 deletions
diff --git a/doc/rust.md b/doc/rust.md index 2f5c310ec83..d285253ffe2 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -744,7 +744,7 @@ There are several kinds of view item: ##### Extern mod declarations ~~~~~~~~ {.ebnf .gram} -extern_mod_decl : "extern" "mod" ident [ '(' link_attrs ')' ] ? ; +extern_mod_decl : "extern" "mod" ident [ '(' link_attrs ')' ] ? [ '=' string_lit ] ? ; link_attrs : link_attr [ ',' link_attrs ] + ; link_attr : ident '=' literal ; ~~~~~~~~ @@ -755,13 +755,25 @@ as the `ident` provided in the `extern_mod_decl`. The external crate is resolved to a specific `soname` at compile time, and a runtime linkage requirement to that `soname` is passed to the linker for -loading at runtime. The `soname` is resolved at compile time by scanning the -compiler's library path and matching the `link_attrs` provided in the -`use_decl` against any `#link` attributes that were declared on the external -crate when it was compiled. If no `link_attrs` are provided, a default `name` -attribute is assumed, equal to the `ident` given in the `use_decl`. - -Three examples of `extern mod` declarations: +loading at runtime. +The `soname` is resolved at compile time by scanning the compiler's library path +and matching the `link_attrs` provided in the `use_decl` against any `#link` attributes that +were declared on the external crate when it was compiled. +If no `link_attrs` are provided, +a default `name` attribute is assumed, +equal to the `ident` given in the `use_decl`. + +Optionally, an identifier in an `extern mod` declaration may be followed by an equals sign, +then a string literal denoting a relative path on the filesystem. +This path should exist in one of the directories in the Rust path, +which by default contains the `.rust` subdirectory of the current directory and each of its parents, +as well as any directories in the colon-separated (or semicolon-separated on Windows) +list of paths that is the `RUST_PATH` environment variable. +The meaning of `extern mod a = "b/c/d";`, supposing that `/a` is in the RUST_PATH, +is that the name `a` should be taken as a reference to the crate whose absolute location is +`/a/b/c/d`. + +Four examples of `extern mod` declarations: ~~~~~~~~{.xfail-test} extern mod pcre (uuid = "54aba0f8-a7b1-4beb-92f1-4cf625264841"); @@ -769,6 +781,8 @@ extern mod pcre (uuid = "54aba0f8-a7b1-4beb-92f1-4cf625264841"); extern mod extra; // equivalent to: extern mod extra ( name = "extra" ); extern mod rustextra (name = "extra"); // linking to 'extra' under another name + +extern mod complicated_mod = "some-file/in/the-rust/path"; ~~~~~~~~ ##### Use declarations diff --git a/doc/tutorial-ffi.md b/doc/tutorial-ffi.md index 047b57e56a6..d1aa793e5fc 100644 --- a/doc/tutorial-ffi.md +++ b/doc/tutorial-ffi.md @@ -228,6 +228,48 @@ unsafe fn kaboom(ptr: *int) -> int { *ptr } This function can only be called from an `unsafe` block or another `unsafe` function. +# Accessing foreign globals + +Foreign APIs often export a global variable which could do something like track +global state. In order to access these variables, you declare them in `extern` +blocks with the `static` keyword: + +~~~{.xfail-test} +use std::libc; + +#[link_args = "-lreadline"] +extern { + static rl_readline_version: libc::c_int; +} + +fn main() { + println(fmt!("You have readline version %d installed.", + rl_readline_version as int)); +} +~~~ + +Alternatively, you may need to alter global state provided by a foreign +interface. To do this, statics can be declared with `mut` so rust can mutate +them. + +~~~{.xfail-test} +use std::libc; +use std::ptr; + +#[link_args = "-lreadline"] +extern { + static mut rl_prompt: *libc::c_char; +} + +fn main() { + do "[my-awesome-shell] $".as_c_str |buf| { + unsafe { rl_prompt = buf; } + // get a line, process it + unsafe { rl_prompt = ptr::null(); } + } +} +~~~ + # Foreign calling conventions Most foreign code exposes a C ABI, and Rust uses the platform's C calling convention by default when diff --git a/doc/tutorial.md b/doc/tutorial.md index 6e6b804aa9d..f4264b0d5af 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -1305,7 +1305,7 @@ match crayons[0] { A vector can be destructured using pattern matching: ~~~~ -let numbers: [int, ..3] = [1, 2, 3]; +let numbers: &[int] = &[1, 2, 3]; let score = match numbers { [] => 0, [a] => a * 10, @@ -2195,7 +2195,7 @@ use std::float::consts::pi; # impl Shape for CircleStruct { fn area(&self) -> float { pi * square(self.radius) } } let concrete = @CircleStruct{center:Point{x:3f,y:4f},radius:5f}; -let mycircle: Circle = concrete as @Circle; +let mycircle: @Circle = concrete as @Circle; let nonsense = mycircle.radius() * mycircle.area(); ~~~ @@ -2288,8 +2288,8 @@ pub mod farm { } impl Farm { - priv fn feed_chickens(&self) { ... } - priv fn feed_cows(&self) { ... } + fn feed_chickens(&self) { ... } + fn feed_cows(&self) { ... } pub fn add_chicken(&self, c: Chicken) { ... } } diff --git a/mk/install.mk b/mk/install.mk index 07cb21217ae..4b50c5aa796 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -199,7 +199,7 @@ endef $(foreach target,$(CFG_TARGET_TRIPLES), \ $(if $(findstring $(target),"arm-linux-androideabi"), \ $(if $(findstring adb,$(CFG_ADB)), \ - $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[_A-Za-z0-9-]+[[:blank:]]+device')), \ + $(if $(findstring device,$(shell $(CFG_ADB) devices 2>/dev/null | grep -E '^[_A-Za-z0-9-]+[[:blank:]]+device')), \ $(info install: install-runtime-target for $(target) enabled \ $(info install: android device attached) \ $(eval $(call DEF_ADB_DEVICE_STATUS, true))), \ diff --git a/mk/rt.mk b/mk/rt.mk index da950dffab5..0aeeec3b487 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -66,30 +66,21 @@ RUNTIME_CXXS_$(1)_$(2) := \ rt/sync/timer.cpp \ rt/sync/lock_and_signal.cpp \ rt/sync/rust_thread.cpp \ - rt/rust.cpp \ rt/rust_builtin.cpp \ rt/rust_run_program.cpp \ rt/rust_env.cpp \ rt/rust_rng.cpp \ - rt/rust_sched_loop.cpp \ - rt/rust_sched_launcher.cpp \ - rt/rust_sched_driver.cpp \ - rt/rust_scheduler.cpp \ - rt/rust_sched_reaper.cpp \ - rt/rust_task.cpp \ rt/rust_stack.cpp \ rt/rust_upcall.cpp \ rt/rust_uv.cpp \ rt/rust_crate_map.cpp \ - rt/rust_log.cpp \ rt/rust_gc_metadata.cpp \ rt/rust_util.cpp \ + rt/rust_log.cpp \ rt/rust_exchange_alloc.cpp \ rt/isaac/randport.cpp \ rt/miniz.cpp \ - rt/rust_kernel.cpp \ rt/rust_abi.cpp \ - rt/rust_debug.cpp \ rt/memory_region.cpp \ rt/boxed_region.cpp \ rt/arch/$$(HOST_$(1))/context.cpp \ diff --git a/mk/tests.mk b/mk/tests.mk index 682ea3e5f69..349ffc63d97 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -123,7 +123,7 @@ endef $(foreach target,$(CFG_TARGET_TRIPLES), \ $(if $(findstring $(target),"arm-linux-androideabi"), \ $(if $(findstring adb,$(CFG_ADB)), \ - $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[_A-Za-z0-9-]+[[:blank:]]+device')), \ + $(if $(findstring device,$(shell $(CFG_ADB) devices 2>/dev/null | grep -E '^[_A-Za-z0-9-]+[[:blank:]]+device')), \ $(info check: $(target) test enabled \ $(info check: android device attached) \ $(eval $(call DEF_ADB_DEVICE_STATUS, true))), \ @@ -348,7 +348,9 @@ $(3)/stage$(1)/test/rustpkgtest-$(2)$$(X_$(2)): \ $$(RUSTPKG_LIB) $$(RUSTPKG_INPUTS) \ $$(SREQ$(1)_T_$(2)_H_$(3)) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) \ - $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) + $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) \ + $$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$$(X_$(2)) \ + $$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(2)) @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index a07da151afc..5e3687d7057 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -142,7 +142,7 @@ fn parse_check_line(line: &str) -> Option<~str> { fn parse_exec_env(line: &str) -> Option<(~str, ~str)> { do parse_name_value_directive(line, ~"exec-env").map |nv| { // nv is either FOO or FOO=BAR - let mut strs: ~[~str] = nv.splitn_iter('=', 1).transform(|s| s.to_owned()).collect(); + let mut strs: ~[~str] = nv.splitn_iter('=', 1).map(|s| s.to_owned()).collect(); match strs.len() { 1u => (strs.pop(), ~""), diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 0d1c5c8eb43..0fb64152d37 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -350,13 +350,13 @@ fn check_expected_errors(expected_errors: ~[errors::ExpectedError], fatal(~"process did not return an error status"); } - let prefixes = expected_errors.iter().transform(|ee| { + let prefixes = expected_errors.iter().map(|ee| { fmt!("%s:%u:", testfile.to_str(), ee.line) }).collect::<~[~str]>(); fn to_lower( s : &str ) -> ~str { let i = s.iter(); - let c : ~[char] = i.transform( |c| { + let c : ~[char] = i.map( |c| { if c.is_ascii() { c.to_ascii().to_lower().to_char() } else { @@ -412,8 +412,8 @@ fn check_expected_errors(expected_errors: ~[errors::ExpectedError], } } - for i in range(0u, found_flags.len()) { - if !found_flags[i] { + for (i, &flag) in found_flags.iter().enumerate() { + if !flag { let ee = &expected_errors[i]; fatal_ProcRes(fmt!("expected %s on line %u not found: %s", ee.kind, ee.line, ee.msg), ProcRes); @@ -760,7 +760,7 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps, let cmdline = make_cmdline("", args.prog, args.args); // get bare program string - let mut tvec: ~[~str] = args.prog.split_iter('/').transform(|ts| ts.to_owned()).collect(); + let mut tvec: ~[~str] = args.prog.split_iter('/').map(|ts| ts.to_owned()).collect(); let prog_short = tvec.pop(); // copy to target @@ -938,7 +938,7 @@ fn disassemble_extract(config: &config, _props: &TestProps, fn count_extracted_lines(p: &Path) -> uint { let x = io::read_whole_file_str(&p.with_filetype("ll")).unwrap(); - x.line_iter().len_() + x.line_iter().len() } diff --git a/src/etc/emacs/rust-mode.el b/src/etc/emacs/rust-mode.el index 87c505e69d0..ecb223f896c 100644 --- a/src/etc/emacs/rust-mode.el +++ b/src/etc/emacs/rust-mode.el @@ -29,6 +29,11 @@ table)) +(defcustom rust-indent-offset default-tab-width + "*Indent Rust code by this number of spaces. + +The initializer is `DEFAULT-TAB-WIDTH'.") + (defun rust-paren-level () (nth 0 (syntax-ppss))) (defun rust-in-str-or-cmnt () (nth 8 (syntax-ppss))) (defun rust-rewind-past-str-cmnt () (goto-char (nth 8 (syntax-ppss)))) @@ -49,10 +54,10 @@ (let ((level (rust-paren-level))) (cond ;; A function return type is 1 level indented - ((looking-at "->") (* default-tab-width (+ level 1))) + ((looking-at "->") (* rust-indent-offset (+ level 1))) ;; A closing brace is 1 level unindended - ((looking-at "}") (* default-tab-width (- level 1))) + ((looking-at "}") (* rust-indent-offset (- level 1))) ;; If we're in any other token-tree / sexp, then: ;; - [ or ( means line up with the opening token @@ -70,18 +75,18 @@ (goto-char pt) (back-to-indentation) (if (looking-at "\\<else\\>") - (* default-tab-width (+ 1 level)) + (* rust-indent-offset (+ 1 level)) (progn (goto-char pt) (beginning-of-line) (rust-rewind-irrelevant) (end-of-line) (if (looking-back "[{};,]") - (* default-tab-width level) + (* rust-indent-offset level) (back-to-indentation) (if (looking-at "#") - (* default-tab-width level) - (* default-tab-width (+ 1 level)))))))))) + (* rust-indent-offset level) + (* rust-indent-offset (+ 1 level)))))))))) ;; Otherwise we're in a column-zero definition (t 0)))))) 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 a6415beab36..b1180098bd2 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 @@ -50,6 +50,7 @@ <keyword>for</keyword> <keyword>if</keyword> <keyword>impl</keyword> + <keyword>in</keyword> <keyword>let</keyword> <keyword>log</keyword> <keyword>loop</keyword> diff --git a/src/libextra/arc.rs b/src/libextra/arc.rs index 17f4cbbd152..5f00f1abae0 100644 --- a/src/libextra/arc.rs +++ b/src/libextra/arc.rs @@ -596,14 +596,14 @@ mod tests { let (c,p) = (Cell::new(c), Cell::new(p)); do task::spawn || { // wait until parent gets in - comm::recv_one(p.take()); + p.take().recv(); do arc2.access_cond |state, cond| { *state = true; cond.signal(); } } do arc.access_cond |state, cond| { - comm::send_one(c.take(), ()); + c.take().send(()); assert!(!*state); while !*state { cond.wait(); @@ -847,22 +847,16 @@ mod tests { } assert_eq!(*state, 42); *state = 31337; - // FIXME: #7372: hits type inference bug with iterators // send to other readers - for i in range(0u, reader_convos.len()) { - match reader_convos[i] { - (ref rc, _) => rc.send(()), - } + for &(ref rc, _) in reader_convos.iter() { + rc.send(()) } } let read_mode = arc.downgrade(write_mode); do (&read_mode).read |state| { - // FIXME: #7372: hits type inference bug with iterators // complete handshake with other readers - for i in range(0u, reader_convos.len()) { - match reader_convos[i] { - (_, ref rp) => rp.recv(), - } + for &(_, ref rp) in reader_convos.iter() { + rp.recv() } wc1.send(()); // tell writer to try again assert_eq!(*state, 31337); diff --git a/src/libextra/bitv.rs b/src/libextra/bitv.rs index 6dedd9ee4dd..63d62bd4809 100644 --- a/src/libextra/bitv.rs +++ b/src/libextra/bitv.rs @@ -145,14 +145,16 @@ impl BigBitv { let len = b.storage.len(); assert_eq!(self.storage.len(), len); let mut changed = false; - for i in range(0, len) { + for (i, (a, b)) in self.storage.mut_iter() + .zip(b.storage.iter()) + .enumerate() { let mask = big_mask(nbits, i); - let w0 = self.storage[i] & mask; - let w1 = b.storage[i] & mask; + let w0 = *a & mask; + let w1 = *b & mask; let w = op(w0, w1) & mask; if w0 != w { changed = true; - self.storage[i] = w; + *a = w; } } changed @@ -160,7 +162,7 @@ impl BigBitv { #[inline] pub fn each_storage(&mut self, op: &fn(v: &mut uint) -> bool) -> bool { - range(0u, self.storage.len()).advance(|i| op(&mut self.storage[i])) + self.storage.mut_iter().advance(|elt| op(elt)) } #[inline] @@ -205,10 +207,9 @@ impl BigBitv { #[inline] pub fn equals(&self, b: &BigBitv, nbits: uint) -> bool { - let len = b.storage.len(); - for i in range(0, len) { + for (i, elt) in b.storage.iter().enumerate() { let mask = big_mask(nbits, i); - if mask & self.storage[i] != mask & b.storage[i] { + if mask & self.storage[i] != mask & *elt { return false; } } @@ -868,7 +869,7 @@ impl BitvSet { let min = num::min(self.bitv.storage.len(), other.bitv.storage.len()); self.bitv.storage.slice(0, min).iter().enumerate() .zip(Repeat::new(&other.bitv.storage)) - .transform(|((i, &w), o_store)| (i * uint::bits, w, o_store[i])) + .map(|((i, &w), o_store)| (i * uint::bits, w, o_store[i])) } /// Visits each word in self or other that extends beyond the other. This @@ -887,11 +888,11 @@ impl BitvSet { if olen < slen { self.bitv.storage.slice_from(olen).iter().enumerate() .zip(Repeat::new(olen)) - .transform(|((i, &w), min)| (true, (i + min) * uint::bits, w)) + .map(|((i, &w), min)| (true, (i + min) * uint::bits, w)) } else { other.bitv.storage.slice_from(slen).iter().enumerate() .zip(Repeat::new(slen)) - .transform(|((i, &w), min)| (false, (i + min) * uint::bits, w)) + .map(|((i, &w), min)| (false, (i + min) * uint::bits, w)) } } } diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index b0839a55795..19a72b0029f 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -63,7 +63,7 @@ pub struct MutDListIterator<'self, T> { /// DList consuming iterator #[deriving(Clone)] -pub struct ConsumeIterator<T> { +pub struct MoveIterator<T> { priv list: DList<T> } @@ -391,14 +391,14 @@ impl<T> DList<T> { /// Consume the list into an iterator yielding elements by value #[inline] - pub fn consume_iter(self) -> ConsumeIterator<T> { - ConsumeIterator{list: self} + pub fn move_iter(self) -> MoveIterator<T> { + MoveIterator{list: self} } /// Consume the list into an iterator yielding elements by value, in reverse #[inline] - pub fn consume_rev_iter(self) -> Invert<ConsumeIterator<T>> { - self.consume_iter().invert() + pub fn move_rev_iter(self) -> Invert<MoveIterator<T>> { + self.move_iter().invert() } } @@ -557,7 +557,7 @@ impl<'self, A> ListInsertion<A> for MutDListIterator<'self, A> { } } -impl<A> Iterator<A> for ConsumeIterator<A> { +impl<A> Iterator<A> for MoveIterator<A> { #[inline] fn next(&mut self) -> Option<A> { self.list.pop_front() } @@ -567,7 +567,7 @@ impl<A> Iterator<A> for ConsumeIterator<A> { } } -impl<A> DoubleEndedIterator<A> for ConsumeIterator<A> { +impl<A> DoubleEndedIterator<A> for MoveIterator<A> { #[inline] fn next_back(&mut self) -> Option<A> { self.list.pop_back() } } @@ -600,7 +600,7 @@ impl<A: Eq> Eq for DList<A> { impl<A: Clone> Clone for DList<A> { fn clone(&self) -> DList<A> { - self.iter().transform(|x| x.clone()).collect() + self.iter().map(|x| x.clone()).collect() } } @@ -690,7 +690,7 @@ mod tests { #[cfg(test)] fn list_from<T: Clone>(v: &[T]) -> DList<T> { - v.iter().transform(|x| (*x).clone()).collect() + v.iter().map(|x| (*x).clone()).collect() } #[test] @@ -721,7 +721,7 @@ mod tests { check_links(&m); let sum = v + u; assert_eq!(sum.len(), m.len()); - for elt in sum.consume_iter() { + for elt in sum.move_iter() { assert_eq!(m.pop_front(), Some(elt)) } } @@ -745,7 +745,7 @@ mod tests { check_links(&m); let sum = u + v; assert_eq!(sum.len(), m.len()); - for elt in sum.consume_iter() { + for elt in sum.move_iter() { assert_eq!(m.pop_front(), Some(elt)) } } @@ -770,7 +770,7 @@ mod tests { m.rotate_backward(); check_links(&m); m.push_front(9); check_links(&m); m.rotate_forward(); check_links(&m); - assert_eq!(~[3,9,5,1,2], m.consume_iter().collect()); + assert_eq!(~[3,9,5,1,2], m.move_iter().collect()); } #[test] @@ -900,7 +900,7 @@ mod tests { } check_links(&m); assert_eq!(m.len(), 3 + len * 2); - assert_eq!(m.consume_iter().collect::<~[int]>(), ~[-2,0,1,2,3,4,5,6,7,8,9,0,1]); + assert_eq!(m.move_iter().collect::<~[int]>(), ~[-2,0,1,2,3,4,5,6,7,8,9,0,1]); } #[test] @@ -911,7 +911,7 @@ mod tests { m.merge(n, |a, b| a <= b); assert_eq!(m.len(), len); check_links(&m); - let res = m.consume_iter().collect::<~[int]>(); + let res = m.move_iter().collect::<~[int]>(); assert_eq!(res, ~[-1, 0, 0, 0, 1, 3, 5, 6, 7, 2, 7, 7, 9]); } @@ -927,7 +927,7 @@ mod tests { m.push_back(4); m.insert_ordered(3); check_links(&m); - assert_eq!(~[2,3,4], m.consume_iter().collect::<~[int]>()); + assert_eq!(~[2,3,4], m.move_iter().collect::<~[int]>()); } #[test] @@ -1003,7 +1003,7 @@ mod tests { check_links(&m); let mut i = 0u; - for (a, &b) in m.consume_iter().zip(v.iter()) { + for (a, &b) in m.move_iter().zip(v.iter()) { i += 1; assert_eq!(a, b); } @@ -1014,7 +1014,7 @@ mod tests { fn bench_collect_into(b: &mut test::BenchHarness) { let v = &[0, ..64]; do b.iter { - let _: DList<int> = v.iter().transform(|x| *x).collect(); + let _: DList<int> = v.iter().map(|x| *x).collect(); } } @@ -1075,33 +1075,33 @@ mod tests { #[bench] fn bench_iter(b: &mut test::BenchHarness) { let v = &[0, ..128]; - let m: DList<int> = v.iter().transform(|&x|x).collect(); + let m: DList<int> = v.iter().map(|&x|x).collect(); do b.iter { - assert!(m.iter().len_() == 128); + assert!(m.iter().len() == 128); } } #[bench] fn bench_iter_mut(b: &mut test::BenchHarness) { let v = &[0, ..128]; - let mut m: DList<int> = v.iter().transform(|&x|x).collect(); + let mut m: DList<int> = v.iter().map(|&x|x).collect(); do b.iter { - assert!(m.mut_iter().len_() == 128); + assert!(m.mut_iter().len() == 128); } } #[bench] fn bench_iter_rev(b: &mut test::BenchHarness) { let v = &[0, ..128]; - let m: DList<int> = v.iter().transform(|&x|x).collect(); + let m: DList<int> = v.iter().map(|&x|x).collect(); do b.iter { - assert!(m.rev_iter().len_() == 128); + assert!(m.rev_iter().len() == 128); } } #[bench] fn bench_iter_mut_rev(b: &mut test::BenchHarness) { let v = &[0, ..128]; - let mut m: DList<int> = v.iter().transform(|&x|x).collect(); + let mut m: DList<int> = v.iter().map(|&x|x).collect(); do b.iter { - assert!(m.mut_rev_iter().len_() == 128); + assert!(m.mut_rev_iter().len() == 128); } } } diff --git a/src/libextra/fileinput.rs b/src/libextra/fileinput.rs index 7a36b25eac5..e268e83bf3f 100644 --- a/src/libextra/fileinput.rs +++ b/src/libextra/fileinput.rs @@ -129,27 +129,27 @@ struct FileInput_ { `Some(path)` is the file represented by `path`, `None` is `stdin`. Consumed as the files are read. */ - priv files: ~[Option<Path>], + files: ~[Option<Path>], /** The current file: `Some(r)` for an open file, `None` before starting and after reading everything. */ - priv current_reader: Option<@io::Reader>, - priv state: FileInputState, + current_reader: Option<@io::Reader>, + state: FileInputState, /** Used to keep track of whether we need to insert the newline at the end of a file that is missing it, which is needed to separate the last and first lines. */ - priv previous_was_newline: bool + previous_was_newline: bool } // XXX: remove this when Reader has &mut self. Should be removable via // "self.fi." -> "self." and renaming FileInput_. Documentation above // will likely have to be updated to use `let mut in = ...`. pub struct FileInput { - priv fi: @mut FileInput_ + fi: @mut FileInput_ } impl FileInput { @@ -198,7 +198,7 @@ impl FileInput { FileInput::from_vec(pathed) } - priv fn current_file_eof(&self) -> bool { + fn current_file_eof(&self) -> bool { match self.fi.current_reader { None => false, Some(r) => r.eof() @@ -240,7 +240,7 @@ impl FileInput { Returns `true` if it had to move to the next file and did so successfully. */ - priv fn next_file_if_eof(&self) -> bool { + fn next_file_if_eof(&self) -> bool { match self.fi.current_reader { None => self.next_file(), Some(r) => { @@ -353,7 +353,7 @@ a literal `-`. */ // XXX: stupid, unclear name pub fn pathify(vec: &[~str], stdin_hyphen : bool) -> ~[Option<Path>] { - vec.iter().transform(|str| { + vec.iter().map(|str| { if stdin_hyphen && "-" == *str { None } else { diff --git a/src/libextra/flate.rs b/src/libextra/flate.rs index 8024b9aa159..ed8cbcd0663 100644 --- a/src/libextra/flate.rs +++ b/src/libextra/flate.rs @@ -43,8 +43,10 @@ static LZ_NONE : c_int = 0x0; // Huffman-coding only. static LZ_FAST : c_int = 0x1; // LZ with only one probe static LZ_NORM : c_int = 0x80; // LZ with 128 probes, "normal" static LZ_BEST : c_int = 0xfff; // LZ with 4095 probes, "best" +static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum +static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum -pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { +fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] { do bytes.as_imm_buf |b, len| { unsafe { let mut outsz : size_t = 0; @@ -52,7 +54,7 @@ pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { rustrt::tdefl_compress_mem_to_heap(b as *c_void, len as size_t, &mut outsz, - LZ_NORM); + flags); assert!(res as int != 0); let out = vec::raw::from_buf_raw(res as *u8, outsz as uint); @@ -62,7 +64,15 @@ pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { } } -pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { +pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { + deflate_bytes_internal(bytes, LZ_NORM) +} + +pub fn deflate_bytes_zlib(bytes: &[u8]) -> ~[u8] { + deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER) +} + +fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] { do bytes.as_imm_buf |b, len| { unsafe { let mut outsz : size_t = 0; @@ -70,7 +80,7 @@ pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { rustrt::tinfl_decompress_mem_to_heap(b as *c_void, len as size_t, &mut outsz, - 0); + flags); assert!(res as int != 0); let out = vec::raw::from_buf_raw(res as *u8, outsz as uint); @@ -80,6 +90,14 @@ pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { } } +pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { + inflate_bytes_internal(bytes, 0) +} + +pub fn inflate_bytes_zlib(bytes: &[u8]) -> ~[u8] { + inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER) +} + #[cfg(test)] mod tests { use super::*; @@ -109,4 +127,12 @@ mod tests { assert_eq!(input, out); } } + + #[test] + fn test_zlib_flate() { + let bytes = ~[1, 2, 3, 4, 5]; + let deflated = deflate_bytes(bytes); + let inflated = inflate_bytes(deflated); + assert_eq!(inflated, bytes); + } } diff --git a/src/libextra/future.rs b/src/libextra/future.rs index 7d2a0658969..391e4baa8c9 100644 --- a/src/libextra/future.rs +++ b/src/libextra/future.rs @@ -28,7 +28,7 @@ use std::cast; use std::cell::Cell; -use std::comm::{PortOne, oneshot, send_one, recv_one}; +use std::comm::{PortOne, oneshot}; use std::task; use std::util::replace; @@ -46,7 +46,7 @@ impl<A> Drop for Future<A> { fn drop(&self) {} } -priv enum FutureState<A> { +enum FutureState<A> { Pending(~fn() -> A), Evaluating, Forced(A) @@ -123,7 +123,7 @@ pub fn from_port<A:Send>(port: PortOne<A>) -> Future<A> { let port = Cell::new(port); do from_fn { - recv_one(port.take()) + port.take().recv() } } @@ -152,7 +152,7 @@ pub fn spawn<A:Send>(blk: ~fn() -> A) -> Future<A> { let chan = Cell::new(chan); do task::spawn { let chan = chan.take(); - send_one(chan, blk()); + chan.send(blk()); } return from_port(port); @@ -163,7 +163,7 @@ mod test { use future::*; use std::cell::Cell; - use std::comm::{oneshot, send_one}; + use std::comm::oneshot; use std::task; #[test] @@ -175,7 +175,7 @@ mod test { #[test] fn test_from_port() { let (po, ch) = oneshot(); - send_one(ch, ~"whale"); + ch.send(~"whale"); let mut f = from_port(po); assert_eq!(f.get(), ~"whale"); } diff --git a/src/libextra/getopts.rs b/src/libextra/getopts.rs index 15aac8ef47c..000520fe41e 100644 --- a/src/libextra/getopts.rs +++ b/src/libextra/getopts.rs @@ -114,7 +114,8 @@ pub enum Occur { pub struct Opt { name: Name, hasarg: HasArg, - occur: Occur + occur: Occur, + aliases: ~[Opt], } fn mkname(nm: &str) -> Name { @@ -127,29 +128,29 @@ fn mkname(nm: &str) -> Name { /// Create an option that is required and takes an argument pub fn reqopt(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: Yes, occur: Req}; + return Opt {name: mkname(name), hasarg: Yes, occur: Req, aliases: ~[]}; } /// Create an option that is optional and takes an argument pub fn optopt(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: Yes, occur: Optional}; + return Opt {name: mkname(name), hasarg: Yes, occur: Optional, aliases: ~[]}; } /// Create an option that is optional and does not take an argument pub fn optflag(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: No, occur: Optional}; + return Opt {name: mkname(name), hasarg: No, occur: Optional, aliases: ~[]}; } /** Create an option that is optional, does not take an argument, * and may occur multiple times. */ pub fn optflagmulti(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: No, occur: Multi}; + return Opt {name: mkname(name), hasarg: No, occur: Multi, aliases: ~[]}; } /// Create an option that is optional and takes an optional argument pub fn optflagopt(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: Maybe, occur: Optional}; + return Opt {name: mkname(name), hasarg: Maybe, occur: Optional, aliases: ~[]}; } /** @@ -157,7 +158,7 @@ pub fn optflagopt(name: &str) -> Opt { * multiple times */ pub fn optmulti(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: Yes, occur: Multi}; + return Opt {name: mkname(name), hasarg: Yes, occur: Multi, aliases: ~[]}; } #[deriving(Clone, Eq)] @@ -189,7 +190,20 @@ fn name_str(nm: &Name) -> ~str { } fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> { - opts.iter().position(|opt| opt.name == nm) + // search main options + let pos = opts.iter().position(|opt| opt.name == nm); + if pos.is_some() { + return pos + } + + // search in aliases + for candidate in opts.iter() { + if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() { + return opts.iter().position(|opt| opt.name == candidate.name); + } + } + + None } /** @@ -488,8 +502,6 @@ pub mod groups { use getopts::{HasArg, Long, Maybe, Multi, No, Occur, Opt, Optional, Req}; use getopts::{Short, Yes}; - use std::vec; - /** one group of options, e.g., both -h and --help, along with * their shared description and properties */ @@ -542,6 +554,20 @@ pub mod groups { occur: Optional}; } + /// Create a long option that can occur more than once and does not + /// take an argument + pub fn optflagmulti(short_name: &str, long_name: &str, + desc: &str) -> OptGroup { + let len = short_name.len(); + assert!(len == 1 || len == 0); + return OptGroup {short_name: short_name.to_owned(), + long_name: long_name.to_owned(), + hint: ~"", + desc: desc.to_owned(), + hasarg: No, + occur: Multi}; + } + /// Create a long option that is optional and takes an optional argument pub fn optflagopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup { @@ -573,7 +599,7 @@ pub mod groups { // translate OptGroup into Opt // (both short and long names correspond to different Opts) - pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] { + pub fn long_to_short(lopt: &OptGroup) -> Opt { let OptGroup{short_name: short_name, long_name: long_name, hasarg: hasarg, @@ -581,24 +607,29 @@ pub mod groups { _} = (*lopt).clone(); match (short_name.len(), long_name.len()) { - (0,0) => fail!("this long-format option was given no name"), - - (0,_) => ~[Opt {name: Long((long_name)), - hasarg: hasarg, - occur: occur}], - - (1,0) => ~[Opt {name: Short(short_name.char_at(0)), - hasarg: hasarg, - occur: occur}], - - (1,_) => ~[Opt {name: Short(short_name.char_at(0)), - hasarg: hasarg, - occur: occur}, - Opt {name: Long((long_name)), - hasarg: hasarg, - occur: occur}], - - (_,_) => fail!("something is wrong with the long-form opt") + (0,0) => fail!("this long-format option was given no name"), + + (0,_) => Opt {name: Long((long_name)), + hasarg: hasarg, + occur: occur, + aliases: ~[]}, + + (1,0) => Opt {name: Short(short_name.char_at(0)), + hasarg: hasarg, + occur: occur, + aliases: ~[]}, + + (1,_) => Opt {name: Long((long_name)), + hasarg: hasarg, + occur: occur, + aliases: ~[Opt { + name: Short(short_name.char_at(0)), + hasarg: hasarg, + occur: occur, + aliases: ~[] + }]}, + + (_,_) => fail!("something is wrong with the long-form opt") } } @@ -606,7 +637,7 @@ pub mod groups { * Parse command line args with the provided long format options */ pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result { - ::getopts::getopts(args, vec::flat_map(opts, long_to_short)) + ::getopts::getopts(args, opts.map(long_to_short)) } /** @@ -616,7 +647,7 @@ pub mod groups { let desc_sep = "\n" + " ".repeat(24); - let mut rows = opts.iter().transform(|optref| { + let mut rows = opts.iter().map(|optref| { let OptGroup{short_name: short_name, long_name: long_name, hint: hint, @@ -708,9 +739,9 @@ pub mod groups { * Fails during iteration if the string contains a non-whitespace * sequence longer than the limit. */ - priv fn each_split_within<'a>(ss: &'a str, - lim: uint, - it: &fn(&'a str) -> bool) -> bool { + fn each_split_within<'a>(ss: &'a str, + lim: uint, + it: &fn(&'a str) -> bool) -> bool { // Just for fun, let's write this as an state machine: enum SplitWithinState { @@ -778,7 +809,7 @@ pub mod groups { } #[test] - priv fn test_split_within() { + fn test_split_within() { fn t(s: &str, i: uint, u: &[~str]) { let mut v = ~[]; do each_split_within(s, i) |s| { v.push(s.to_owned()); true }; @@ -1440,7 +1471,8 @@ mod tests { #[test] fn test_groups_long_to_short() { - let short = ~[reqopt("b"), reqopt("banana")]; + let mut short = reqopt("banana"); + short.aliases = ~[reqopt("b")]; let verbose = groups::reqopt("b", "banana", "some bananas", "VAL"); assert_eq!(groups::long_to_short(&verbose), short); @@ -1448,10 +1480,16 @@ mod tests { #[test] fn test_groups_getopts() { + let mut banana = reqopt("banana"); + banana.aliases = ~[reqopt("b")]; + let mut apple = optopt("apple"); + apple.aliases = ~[optopt("a")]; + let mut kiwi = optflag("kiwi"); + kiwi.aliases = ~[optflag("k")]; let short = ~[ - reqopt("b"), reqopt("banana"), - optopt("a"), optopt("apple"), - optflag("k"), optflagopt("kiwi"), + banana, + apple, + kiwi, optflagopt("p"), optmulti("l") ]; @@ -1464,7 +1502,7 @@ mod tests { groups::optmulti("l", "", "Desc", "VAL"), ]; - let sample_args = ~[~"-k", ~"15", ~"--apple", ~"1", ~"k", + let sample_args = ~[~"--kiwi", ~"15", ~"--apple", ~"1", ~"k", ~"-p", ~"16", ~"l", ~"35"]; // FIXME #4681: sort options here? @@ -1473,6 +1511,19 @@ mod tests { } #[test] + fn test_groups_aliases_long_and_short() { + let opts = ~[ + groups::optflagmulti("a", "apple", "Desc"), + ]; + + let args = ~[~"-a", ~"--apple", ~"-a"]; + + let matches = groups::getopts(args, opts).unwrap(); + assert_eq!(3, opt_count(&matches, "a")); + assert_eq!(3, opt_count(&matches, "apple")); + } + + #[test] fn test_groups_usage() { let optgroups = ~[ groups::reqopt("b", "banana", "Desc", "VAL"), diff --git a/src/libextra/json.rs b/src/libextra/json.rs index ec9cb902d3d..2287384b53a 100644 --- a/src/libextra/json.rs +++ b/src/libextra/json.rs @@ -948,7 +948,7 @@ impl serialize::Decoder for Decoder { let name = match self.stack.pop() { String(s) => s, List(list) => { - for v in list.consume_rev_iter() { + for v in list.move_rev_iter() { self.stack.push(v); } match self.stack.pop() { @@ -1066,7 +1066,7 @@ impl serialize::Decoder for Decoder { let len = match self.stack.pop() { List(list) => { let len = list.len(); - for v in list.consume_rev_iter() { + for v in list.move_rev_iter() { self.stack.push(v); } len @@ -1086,7 +1086,7 @@ impl serialize::Decoder for Decoder { let len = match self.stack.pop() { Object(obj) => { let len = obj.len(); - for (key, value) in obj.consume_iter() { + for (key, value) in obj.move_iter() { self.stack.push(value); self.stack.push(String(key)); } diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index c3737d44e38..27dfc090f88 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -59,13 +59,13 @@ pub mod BigDigit { pub static bits: uint = 32; pub static base: uint = 1 << bits; - priv static hi_mask: uint = (-1 as uint) << bits; - priv static lo_mask: uint = (-1 as uint) >> bits; + static hi_mask: uint = (-1 as uint) << bits; + static lo_mask: uint = (-1 as uint) >> bits; - priv fn get_hi(n: uint) -> BigDigit { (n >> bits) as BigDigit } + fn get_hi(n: uint) -> BigDigit { (n >> bits) as BigDigit } - priv fn get_lo(n: uint) -> BigDigit { (n & lo_mask) as BigDigit } + fn get_lo(n: uint) -> BigDigit { (n & lo_mask) as BigDigit } /// Split one machine sized unsigned integer into two BigDigits. @@ -287,7 +287,7 @@ impl Mul<BigUint, BigUint> for BigUint { if n == 1 { return (*a).clone(); } let mut carry = 0; - let mut prod = do a.data.iter().transform |ai| { + let mut prod = do a.data.iter().map |ai| { let (hi, lo) = BigDigit::from_uint( (*ai as uint) * (n as uint) + (carry as uint) ); @@ -613,7 +613,7 @@ impl BigUint { } - priv fn shl_unit(&self, n_unit: uint) -> BigUint { + fn shl_unit(&self, n_unit: uint) -> BigUint { if n_unit == 0 || self.is_zero() { return (*self).clone(); } return BigUint::new(vec::from_elem(n_unit, ZERO_BIG_DIGIT) @@ -621,11 +621,11 @@ impl BigUint { } - priv fn shl_bits(&self, n_bits: uint) -> BigUint { + fn shl_bits(&self, n_bits: uint) -> BigUint { if n_bits == 0 || self.is_zero() { return (*self).clone(); } let mut carry = 0; - let mut shifted = do self.data.iter().transform |elem| { + let mut shifted = do self.data.iter().map |elem| { let (hi, lo) = BigDigit::from_uint( (*elem as uint) << n_bits | (carry as uint) ); @@ -637,7 +637,7 @@ impl BigUint { } - priv fn shr_unit(&self, n_unit: uint) -> BigUint { + fn shr_unit(&self, n_unit: uint) -> BigUint { if n_unit == 0 { return (*self).clone(); } if self.data.len() < n_unit { return Zero::zero(); } return BigUint::from_slice( @@ -646,7 +646,7 @@ impl BigUint { } - priv fn shr_bits(&self, n_bits: uint) -> BigUint { + fn shr_bits(&self, n_bits: uint) -> BigUint { if n_bits == 0 || self.data.is_empty() { return (*self).clone(); } let mut borrow = 0; @@ -661,7 +661,7 @@ impl BigUint { #[cfg(target_arch = "x86_64")] -priv fn get_radix_base(radix: uint) -> (uint, uint) { +fn get_radix_base(radix: uint) -> (uint, uint) { assert!(1 < radix && radix <= 16); match radix { 2 => (4294967296, 32), @@ -687,7 +687,7 @@ priv fn get_radix_base(radix: uint) -> (uint, uint) { #[cfg(target_arch = "x86")] #[cfg(target_arch = "mips")] -priv fn get_radix_base(radix: uint) -> (uint, uint) { +fn get_radix_base(radix: uint) -> (uint, uint) { assert!(1 < radix && radix <= 16); match radix { 2 => (65536, 16), diff --git a/src/libextra/par.rs b/src/libextra/par.rs index 4069c68e71c..71dddc481ae 100644 --- a/src/libextra/par.rs +++ b/src/libextra/par.rs @@ -77,7 +77,7 @@ fn map_slices<A:Clone + Send,B:Clone + Send>( info!("num_tasks: %?", (num_tasks, futures.len())); assert_eq!(num_tasks, futures.len()); - do futures.consume_iter().transform |ys| { + do futures.move_iter().map |ys| { let mut ys = ys; ys.get() }.collect() @@ -90,7 +90,7 @@ pub fn map<A:Clone + Send,B:Clone + Send>( vec::concat(map_slices(xs, || { let f = fn_factory(); let result: ~fn(uint, &[A]) -> ~[B] = - |_, slice| slice.iter().transform(|x| f(x)).collect(); + |_, slice| slice.iter().map(|x| f(x)).collect(); result })) } @@ -102,7 +102,7 @@ pub fn mapi<A:Clone + Send,B:Clone + Send>( let slices = map_slices(xs, || { let f = fn_factory(); let result: ~fn(uint, &[A]) -> ~[B] = |base, slice| { - slice.iter().enumerate().transform(|(i, x)| { + slice.iter().enumerate().map(|(i, x)| { f(i + base, x) }).collect() }; diff --git a/src/libextra/priority_queue.rs b/src/libextra/priority_queue.rs index 696ecc881b7..4b94219b30d 100644 --- a/src/libextra/priority_queue.rs +++ b/src/libextra/priority_queue.rs @@ -367,7 +367,7 @@ mod tests { fn test_from_iter() { let xs = ~[9u, 8, 7, 6, 5, 4, 3, 2, 1]; - let mut q: PriorityQueue<uint> = xs.rev_iter().transform(|&x| x).collect(); + let mut q: PriorityQueue<uint> = xs.rev_iter().map(|&x| x).collect(); for &x in xs.iter() { assert_eq!(q.pop(), x); diff --git a/src/libextra/ringbuf.rs b/src/libextra/ringbuf.rs index da8089250b3..bb9ac74bc77 100644 --- a/src/libextra/ringbuf.rs +++ b/src/libextra/ringbuf.rs @@ -692,11 +692,11 @@ mod tests { fn test_from_iterator() { use std::iterator; let v = ~[1,2,3,4,5,6,7]; - let deq: RingBuf<int> = v.iter().transform(|&x| x).collect(); - let u: ~[int] = deq.iter().transform(|&x| x).collect(); + let deq: RingBuf<int> = v.iter().map(|&x| x).collect(); + let u: ~[int] = deq.iter().map(|&x| x).collect(); assert_eq!(u, v); - let mut seq = iterator::count(0u, 2).take_(256); + let mut seq = iterator::count(0u, 2).take(256); let deq: RingBuf<uint> = seq.collect(); for (i, &x) in deq.iter().enumerate() { assert_eq!(2*i, x); diff --git a/src/libextra/rl.rs b/src/libextra/rl.rs index 8aff8d38887..9106d4cd684 100644 --- a/src/libextra/rl.rs +++ b/src/libextra/rl.rs @@ -11,7 +11,7 @@ // FIXME #3921. This is unsafe because linenoise uses global mutable // state without mutexes. - +use std::c_str::ToCStr; use std::libc::{c_char, c_int}; use std::local_data; use std::str; @@ -32,7 +32,7 @@ pub mod rustrt { /// Add a line to history pub unsafe fn add_history(line: &str) -> bool { - do line.as_c_str |buf| { + do line.to_c_str().with_ref |buf| { rustrt::linenoiseHistoryAdd(buf) == 1 as c_int } } @@ -44,21 +44,21 @@ pub unsafe fn set_history_max_len(len: int) -> bool { /// Save line history to a file pub unsafe fn save_history(file: &str) -> bool { - do file.as_c_str |buf| { + do file.to_c_str().with_ref |buf| { rustrt::linenoiseHistorySave(buf) == 1 as c_int } } /// Load line history from a file pub unsafe fn load_history(file: &str) -> bool { - do file.as_c_str |buf| { + do file.to_c_str().with_ref |buf| { rustrt::linenoiseHistoryLoad(buf) == 1 as c_int } } /// Print out a prompt and then wait for input and return it pub unsafe fn read(prompt: &str) -> Option<~str> { - do prompt.as_c_str |buf| { + do prompt.to_c_str().with_ref |buf| { let line = rustrt::linenoise(buf); if line.is_null() { None } @@ -80,7 +80,7 @@ pub unsafe fn complete(cb: CompletionCb) { unsafe { do cb(str::raw::from_c_str(line)) |suggestion| { - do suggestion.as_c_str |buf| { + do suggestion.to_c_str().with_ref |buf| { rustrt::linenoiseAddCompletion(completions, buf); } } diff --git a/src/libextra/smallintmap.rs b/src/libextra/smallintmap.rs index e5116f19afa..ac07fd2bebf 100644 --- a/src/libextra/smallintmap.rs +++ b/src/libextra/smallintmap.rs @@ -15,8 +15,7 @@ #[allow(missing_doc)]; -use std::iterator::{Iterator, IteratorUtil, Enumerate, FilterMap, Invert}; -use std::uint; +use std::iterator::{Iterator, Enumerate, FilterMap, Invert}; use std::util::replace; use std::vec::{VecIterator, VecMutIterator}; use std::vec; @@ -29,14 +28,12 @@ pub struct SmallIntMap<T> { impl<V> Container for SmallIntMap<V> { /// Return the number of elements in the map fn len(&self) -> uint { - let mut sz = 0; - for i in range(0u, self.v.len()) { - match self.v[i] { - Some(_) => sz += 1, - None => {} - } - } - sz + self.v.iter().count(|elt| elt.is_some()) + } + + /// Return true if there are no elements in the map + fn is_empty(&self) -> bool { + self.v.iter().all(|elt| elt.is_none()) } } @@ -116,48 +113,6 @@ impl<V> SmallIntMap<V> { /// Create an empty SmallIntMap pub fn new() -> SmallIntMap<V> { SmallIntMap{v: ~[]} } - /// Visit all key-value pairs in order - pub fn each<'a>(&'a self, it: &fn(&uint, &'a V) -> bool) -> bool { - for i in range(0u, self.v.len()) { - match self.v[i] { - Some(ref elt) => if !it(&i, elt) { return false; }, - None => () - } - } - true - } - - /// Visit all keys in order - pub fn each_key(&self, blk: &fn(key: &uint) -> bool) -> bool { - self.each(|k, _| blk(k)) - } - - /// Visit all values in order - pub fn each_value<'a>(&'a self, blk: &fn(value: &'a V) -> bool) -> bool { - self.each(|_, v| blk(v)) - } - - /// Iterate over the map and mutate the contained values - pub fn mutate_values(&mut self, it: &fn(&uint, &mut V) -> bool) -> bool { - for i in range(0, self.v.len()) { - match self.v[i] { - Some(ref mut elt) => if !it(&i, elt) { return false; }, - None => () - } - } - true - } - - /// Visit all key-value pairs in reverse order - pub fn each_reverse<'a>(&'a self, it: &fn(uint, &'a V) -> bool) -> bool { - do uint::range_rev(self.v.len(), 0) |i| { - match self.v[i] { - Some(ref elt) => it(i, elt), - None => true - } - } - } - pub fn get<'a>(&'a self, key: &uint) -> &'a V { self.find(key).expect("key not present") } @@ -197,12 +152,12 @@ impl<V> SmallIntMap<V> { } /// Empties the hash map, moving all values into the specified closure - pub fn consume(&mut self) + pub fn move_iter(&mut self) -> FilterMap<(uint, Option<V>), (uint, V), - Enumerate<vec::ConsumeIterator<Option<V>>>> + Enumerate<vec::MoveIterator<Option<V>>>> { let values = replace(&mut self.v, ~[]); - values.consume_iter().enumerate().filter_map(|(i, v)| { + values.move_iter().enumerate().filter_map(|(i, v)| { v.map_move(|v| (i, v)) }) } @@ -497,11 +452,11 @@ mod test_map { } #[test] - fn test_consume() { + fn test_move_iter() { let mut m = SmallIntMap::new(); m.insert(1, ~2); let mut called = false; - for (k, v) in m.consume() { + for (k, v) in m.move_iter() { assert!(!called); called = true; assert_eq!(k, 1); diff --git a/src/libextra/sort.rs b/src/libextra/sort.rs index 8090dd26ef2..c7920e72708 100644 --- a/src/libextra/sort.rs +++ b/src/libextra/sort.rs @@ -469,10 +469,7 @@ impl<T:Clone + Ord> MergeState<T> { base2: uint, len2: uint) { assert!(len1 != 0 && len2 != 0 && base1+len1 == base2); - let mut tmp = ~[]; - for i in range(base1, base1+len1) { - tmp.push(array[i].clone()); - } + let mut tmp = array.slice(base1, base1 + len1).to_owned(); let mut c1 = 0; let mut c2 = base2; @@ -579,10 +576,7 @@ impl<T:Clone + Ord> MergeState<T> { base2: uint, len2: uint) { assert!(len1 != 1 && len2 != 0 && base1 + len1 == base2); - let mut tmp = ~[]; - for i in range(base2, base2+len2) { - tmp.push(array[i].clone()); - } + let mut tmp = array.slice(base2, base2 + len2).to_owned(); let mut c1 = base1 + len1 - 1; let mut c2 = len2 - 1; @@ -899,7 +893,7 @@ mod tests { fn ile(x: &(&'static str), y: &(&'static str)) -> bool { // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use - // to_ascii_consume and to_str_consume to not do a unnecessary clone. + // to_ascii_move and to_str_move to not do a unnecessary clone. // (Actually, could just remove the to_str_* call, but needs an deriving(Ord) on // Ascii) let x = x.to_ascii().to_lower().to_str_ascii(); diff --git a/src/libextra/stats.rs b/src/libextra/stats.rs index 9238034cba3..881d931fe0a 100644 --- a/src/libextra/stats.rs +++ b/src/libextra/stats.rs @@ -223,7 +223,7 @@ impl<'self> Stats for &'self [f64] { // Helper function: extract a value representing the `pct` percentile of a sorted sample-set, using // linear interpolation. If samples are not sorted, return nonsensical value. -priv fn percentile_of_sorted(sorted_samples: &[f64], +fn percentile_of_sorted(sorted_samples: &[f64], pct: f64) -> f64 { assert!(sorted_samples.len() != 0); if sorted_samples.len() == 1 { diff --git a/src/libextra/sync.rs b/src/libextra/sync.rs index 4172c715adb..756a5c7da00 100644 --- a/src/libextra/sync.rs +++ b/src/libextra/sync.rs @@ -19,6 +19,7 @@ use std::borrow; use std::comm; use std::comm::SendDeferred; +use std::comm::{GenericPort, Peekable}; use std::task; use std::unstable::sync::{Exclusive, UnsafeAtomicRcBox}; use std::unstable::atomics; @@ -71,6 +72,12 @@ impl WaitQueue { } count } + + fn wait_end(&self) -> WaitEnd { + let (wait_end, signal_end) = comm::oneshot(); + self.tail.send_deferred(signal_end); + wait_end + } } // The building-block used to make semaphores, mutexes, and rwlocks. @@ -99,19 +106,16 @@ impl<Q:Send> Sem<Q> { do (**self).with |state| { state.count -= 1; if state.count < 0 { - // Create waiter nobe. - let (WaitEnd, SignalEnd) = comm::oneshot(); - // Tell outer scope we need to block. - waiter_nobe = Some(WaitEnd); - // Enqueue ourself. - state.waiters.tail.send_deferred(SignalEnd); + // Create waiter nobe, enqueue ourself, and tell + // outer scope we need to block. + waiter_nobe = Some(state.waiters.wait_end()); } } // Uncomment if you wish to test for sem races. Not valgrind-friendly. /* do 1000.times { task::yield(); } */ // Need to wait outside the exclusive. if waiter_nobe.is_some() { - let _ = comm::recv_one(waiter_nobe.unwrap()); + let _ = waiter_nobe.unwrap().recv(); } } } @@ -200,10 +204,7 @@ impl<'self> Condvar<'self> { * wait() is equivalent to wait_on(0). */ pub fn wait_on(&self, condvar_id: uint) { - // Create waiter nobe. - let (WaitEnd, SignalEnd) = comm::oneshot(); - let mut WaitEnd = Some(WaitEnd); - let mut SignalEnd = Some(SignalEnd); + let mut WaitEnd = None; let mut out_of_bounds = None; do task::unkillable { // Release lock, 'atomically' enqueuing ourselves in so doing. @@ -215,9 +216,9 @@ impl<'self> Condvar<'self> { if state.count <= 0 { state.waiters.signal(); } - // Enqueue ourself to be woken up by a signaller. - let SignalEnd = SignalEnd.take_unwrap(); - state.blocked[condvar_id].tail.send_deferred(SignalEnd); + // Create waiter nobe, and enqueue ourself to + // be woken up by a signaller. + WaitEnd = Some(state.blocked[condvar_id].wait_end()); } else { out_of_bounds = Some(state.blocked.len()); } @@ -235,7 +236,7 @@ impl<'self> Condvar<'self> { do (|| { unsafe { do task::rekillable { - let _ = comm::recv_one(WaitEnd.take_unwrap()); + let _ = WaitEnd.take_unwrap().recv(); } } }).finally { diff --git a/src/libextra/task_pool.rs b/src/libextra/task_pool.rs index 17588b93ec4..f1bf9e81c72 100644 --- a/src/libextra/task_pool.rs +++ b/src/libextra/task_pool.rs @@ -14,7 +14,7 @@ /// parallelism. -use std::comm::Chan; +use std::comm::{Chan, GenericChan, GenericPort}; use std::comm; use std::task::SchedMode; use std::task; diff --git a/src/libextra/term.rs b/src/libextra/term.rs index 2173eb838e5..d0412b8954d 100644 --- a/src/libextra/term.rs +++ b/src/libextra/term.rs @@ -75,7 +75,7 @@ pub mod attr { } #[cfg(not(target_os = "win32"))] -priv fn cap_for_attr(attr: attr::Attr) -> &'static str { +fn cap_for_attr(attr: attr::Attr) -> &'static str { match attr { attr::Bold => "bold", attr::Dim => "dim", @@ -234,7 +234,7 @@ impl Terminal { } } - priv fn dim_if_necessary(&self, color: color::Color) -> color::Color { + fn dim_if_necessary(&self, color: color::Color) -> color::Color { if color >= self.num_colors && color >= 8 && color < 16 { color-8 } else { color } diff --git a/src/libextra/terminfo/parm.rs b/src/libextra/terminfo/parm.rs index b619e0f33b6..bb59e34f98a 100644 --- a/src/libextra/terminfo/parm.rs +++ b/src/libextra/terminfo/parm.rs @@ -12,7 +12,6 @@ use std::{char, vec, util}; use std::num::strconv::{SignNone,SignNeg,SignAll,int_to_str_bytes_common}; -use std::iterator::IteratorUtil; #[deriving(Eq)] enum States { @@ -106,7 +105,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) *dst = (*src).clone(); } - for c in cap.iter().transform(|&x| x) { + for c in cap.iter().map(|&x| x) { let cur = c as char; let mut old_state = state; match state { @@ -430,7 +429,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) } #[deriving(Eq)] -priv struct Flags { +struct Flags { width: uint, precision: uint, alternate: bool, @@ -440,13 +439,13 @@ priv struct Flags { } impl Flags { - priv fn new() -> Flags { + fn new() -> Flags { Flags{ width: 0, precision: 0, alternate: false, left: false, sign: false, space: false } } } -priv enum FormatOp { +enum FormatOp { FormatDigit, FormatOctal, FormatHex, @@ -455,7 +454,7 @@ priv enum FormatOp { } impl FormatOp { - priv fn from_char(c: char) -> FormatOp { + fn from_char(c: char) -> FormatOp { match c { 'd' => FormatDigit, 'o' => FormatOctal, @@ -465,7 +464,7 @@ impl FormatOp { _ => fail!("bad FormatOp char") } } - priv fn to_char(self) -> char { + fn to_char(self) -> char { match self { FormatDigit => 'd', FormatOctal => 'o', @@ -476,7 +475,8 @@ impl FormatOp { } } -priv fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> { +#[cfg(stage0)] +fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> { let mut s = match val { Number(d) => { match op { @@ -545,8 +545,103 @@ priv fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> { String(s) => { match op { FormatString => { - let mut s = s.to_bytes_with_null(); - s.pop(); // remove the null + let mut s = s.as_bytes().to_owned(); + if flags.precision > 0 && flags.precision < s.len() { + s.truncate(flags.precision); + } + s + } + _ => { + return Err(fmt!("non-string on stack with %%%c", op.to_char())) + } + } + } + }; + if flags.width > s.len() { + let n = flags.width - s.len(); + if flags.left { + s.grow(n, &(' ' as u8)); + } else { + let mut s_ = vec::with_capacity(flags.width); + s_.grow(n, &(' ' as u8)); + s_.push_all_move(s); + s = s_; + } + } + Ok(s) +} + +#[cfg(not(stage0))] +fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> { + let mut s = match val { + Number(d) => { + match op { + FormatString => { + return Err(~"non-number on stack with %s") + } + _ => { + let radix = match op { + FormatDigit => 10, + FormatOctal => 8, + FormatHex|FormatHEX => 16, + FormatString => util::unreachable() + }; + let mut s = ~[]; + match op { + FormatDigit => { + let sign = if flags.sign { SignAll } else { SignNeg }; + do int_to_str_bytes_common(d, radix, sign) |c| { + s.push(c); + } + } + _ => { + do int_to_str_bytes_common(d as uint, radix, SignNone) |c| { + s.push(c); + } + } + }; + if flags.precision > s.len() { + let mut s_ = vec::with_capacity(flags.precision); + let n = flags.precision - s.len(); + s_.grow(n, &('0' as u8)); + s_.push_all_move(s); + s = s_; + } + assert!(!s.is_empty(), "string conversion produced empty result"); + match op { + FormatDigit => { + if flags.space && !(s[0] == '-' as u8 || s[0] == '+' as u8) { + s.unshift(' ' as u8); + } + } + FormatOctal => { + if flags.alternate && s[0] != '0' as u8 { + s.unshift('0' as u8); + } + } + FormatHex => { + if flags.alternate { + let s_ = util::replace(&mut s, ~['0' as u8, 'x' as u8]); + s.push_all_move(s_); + } + } + FormatHEX => { + s = s.into_ascii().to_upper().into_bytes(); + if flags.alternate { + let s_ = util::replace(&mut s, ~['0' as u8, 'X' as u8]); + s.push_all_move(s_); + } + } + FormatString => util::unreachable() + } + s + } + } + } + String(s) => { + match op { + FormatString => { + let mut s = s.as_bytes().to_owned(); if flags.precision > 0 && flags.precision < s.len() { s.truncate(flags.precision); } diff --git a/src/libextra/terminfo/parser/compiled.rs b/src/libextra/terminfo/parser/compiled.rs index 426cacb62fa..0d2badff492 100644 --- a/src/libextra/terminfo/parser/compiled.rs +++ b/src/libextra/terminfo/parser/compiled.rs @@ -214,7 +214,7 @@ pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> { } let names_str = str::from_bytes(file.read_bytes(names_bytes as uint - 1)); // don't read NUL - let term_names: ~[~str] = names_str.split_iter('|').transform(|s| s.to_owned()).collect(); + let term_names: ~[~str] = names_str.split_iter('|').map(|s| s.to_owned()).collect(); file.read_byte(); // consume NUL diff --git a/src/libextra/test.rs b/src/libextra/test.rs index 761cb1bd76f..8b7332ff545 100644 --- a/src/libextra/test.rs +++ b/src/libextra/test.rs @@ -29,7 +29,7 @@ use time::precise_time_ns; use treemap::TreeMap; use std::clone::Clone; -use std::comm::{stream, SharedChan}; +use std::comm::{stream, SharedChan, GenericPort, GenericChan}; use std::libc; use std::either; use std::io; @@ -525,12 +525,11 @@ impl ConsoleTestState { } pub fn fmt_metrics(mm: &MetricMap) -> ~str { - use std::iterator::IteratorUtil; let v : ~[~str] = mm.iter() - .transform(|(k,v)| fmt!("%s: %f (+/- %f)", - *k, - v.value as float, - v.noise as float)) + .map(|(k,v)| fmt!("%s: %f (+/- %f)", + *k, + v.value as float, + v.noise as float)) .collect(); v.connect(", ") } @@ -698,7 +697,7 @@ fn run_tests(opts: &TestOpts, // All benchmarks run at the end, in serial. // (this includes metric fns) - for b in filtered_benchs_and_metrics.consume_iter() { + for b in filtered_benchs_and_metrics.move_iter() { callback(TeWait(b.desc.clone())); run_test(!opts.run_benchmarks, b, ch.clone()); let (test, result) = p.recv(); @@ -744,7 +743,7 @@ pub fn filter_tests( } } - filtered.consume_iter().filter_map(|x| filter_fn(x, filter_str)).collect() + filtered.move_iter().filter_map(|x| filter_fn(x, filter_str)).collect() }; // Maybe pull out the ignored test and unignore them @@ -762,7 +761,7 @@ pub fn filter_tests( None } }; - filtered.consume_iter().filter_map(|x| filter(x)).collect() + filtered.move_iter().filter_map(|x| filter(x)).collect() }; // Sort the tests alphabetically diff --git a/src/libextra/time.rs b/src/libextra/time.rs index efc3dc87adc..f79e01b6f28 100644 --- a/src/libextra/time.rs +++ b/src/libextra/time.rs @@ -57,9 +57,6 @@ impl Ord for Timespec { self.sec < other.sec || (self.sec == other.sec && self.nsec < other.nsec) } - fn le(&self, other: &Timespec) -> bool { !other.lt(self) } - fn ge(&self, other: &Timespec) -> bool { !self.lt(other) } - fn gt(&self, other: &Timespec) -> bool { !self.le(other) } } /** @@ -254,7 +251,7 @@ impl Tm { } } -priv fn do_strptime(s: &str, format: &str) -> Result<Tm, ~str> { +fn do_strptime(s: &str, format: &str) -> Result<Tm, ~str> { fn match_str(s: &str, pos: uint, needle: &str) -> bool { let mut i = pos; for ch in needle.byte_iter() { @@ -287,10 +284,14 @@ priv fn do_strptime(s: &str, format: &str) -> Result<Tm, ~str> { fn match_digits(ss: &str, pos: uint, digits: uint, ws: bool) -> Option<(i32, uint)> { let mut pos = pos; + let len = ss.len(); let mut value = 0_i32; let mut i = 0u; while i < digits { + if pos >= len { + return None; + } let range = ss.char_range_at(pos); pos = range.next; @@ -687,7 +688,7 @@ priv fn do_strptime(s: &str, format: &str) -> Result<Tm, ~str> { } } -priv fn do_strftime(format: &str, tm: &Tm) -> ~str { +fn do_strftime(format: &str, tm: &Tm) -> ~str { fn parse_type(ch: char, tm: &Tm) -> ~str { //FIXME (#2350): Implement missing types. let die = || fmt!("strftime: can't understand this format %c ", ch); @@ -856,7 +857,7 @@ priv fn do_strftime(format: &str, tm: &Tm) -> ~str { #[cfg(test)] mod tests { - use time::*; + use super::*; use std::float; use std::os; @@ -904,7 +905,7 @@ mod tests { os::setenv("TZ", "America/Los_Angeles"); tzset(); - let time = ::time::Timespec::new(1234567890, 54321); + let time = Timespec::new(1234567890, 54321); let utc = at_utc(time); assert!(utc.tm_sec == 30_i32); @@ -925,7 +926,7 @@ mod tests { os::setenv("TZ", "America/Los_Angeles"); tzset(); - let time = ::time::Timespec::new(1234567890, 54321); + let time = Timespec::new(1234567890, 54321); let local = at(time); error!("time_at: %?", local); @@ -953,7 +954,7 @@ mod tests { os::setenv("TZ", "America/Los_Angeles"); tzset(); - let time = ::time::Timespec::new(1234567890, 54321); + let time = Timespec::new(1234567890, 54321); let utc = at_utc(time); assert_eq!(utc.to_timespec(), time); @@ -964,7 +965,7 @@ mod tests { os::setenv("TZ", "America/Los_Angeles"); tzset(); - let time = ::time::Timespec::new(1234567890, 54321); + let time = Timespec::new(1234567890, 54321); let utc = at_utc(time); let local = at(time); @@ -1145,7 +1146,7 @@ mod tests { os::setenv("TZ", "America/Los_Angeles"); tzset(); - let time = ::time::Timespec::new(1234567890, 54321); + let time = Timespec::new(1234567890, 54321); let utc = at_utc(time); let local = at(time); @@ -1159,7 +1160,7 @@ mod tests { os::setenv("TZ", "America/Los_Angeles"); tzset(); - let time = ::time::Timespec::new(1234567890, 54321); + let time = Timespec::new(1234567890, 54321); let utc = at_utc(time); let local = at(time); diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index ab7d47255da..424492a3cfe 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -13,7 +13,6 @@ //! `TotalOrd`. -use std::num; use std::util::{swap, replace}; use std::iterator::{FromIterator, Extendable}; @@ -42,39 +41,23 @@ pub struct TreeMap<K, V> { impl<K: Eq + TotalOrd, V: Eq> Eq for TreeMap<K, V> { fn eq(&self, other: &TreeMap<K, V>) -> bool { - if self.len() != other.len() { - false - } else { - let mut x = self.iter(); - let mut y = other.iter(); - for _ in range(0u, self.len()) { - if x.next().unwrap() != y.next().unwrap() { - return false - } - } - true - } + self.len() == other.len() && + self.iter().zip(other.iter()).all(|(a, b)| a == b) } - fn ne(&self, other: &TreeMap<K, V>) -> bool { !self.eq(other) } } // Lexicographical comparison fn lt<K: Ord + TotalOrd, V: Ord>(a: &TreeMap<K, V>, b: &TreeMap<K, V>) -> bool { - let mut x = a.iter(); - let mut y = b.iter(); - - let (a_len, b_len) = (a.len(), b.len()); - for _ in range(0u, num::min(a_len, b_len)) { - let (key_a, value_a) = x.next().unwrap(); - let (key_b, value_b) = y.next().unwrap(); + // the Zip iterator is as long as the shortest of a and b. + for ((key_a, value_a), (key_b, value_b)) in a.iter().zip(b.iter()) { if *key_a < *key_b { return true; } if *key_a > *key_b { return false; } if *value_a < *value_b { return true; } if *value_a > *value_b { return false; } } - a_len < b_len + a.len() < b.len() } impl<K: Ord + TotalOrd, V: Ord> Ord for TreeMap<K, V> { @@ -151,36 +134,11 @@ impl<K: TotalOrd, V> TreeMap<K, V> { /// Create an empty TreeMap pub fn new() -> TreeMap<K, V> { TreeMap{root: None, length: 0} } - /// Visit all keys in order - pub fn each_key(&self, f: &fn(&K) -> bool) -> bool { - self.iter().advance(|(k, _)| f(k)) - } - - /// Visit all values in order - pub fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool) -> bool { - self.iter().advance(|(_, v)| f(v)) - } - /// Iterate over the map and mutate the contained values pub fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool) -> bool { mutate_values(&mut self.root, f) } - /// Visit all key-value pairs in reverse order - pub fn each_reverse<'a>(&'a self, f: &fn(&'a K, &'a V) -> bool) -> bool { - each_reverse(&self.root, f) - } - - /// Visit all keys in reverse order - pub fn each_key_reverse(&self, f: &fn(&K) -> bool) -> bool { - self.each_reverse(|k, _| f(k)) - } - - /// Visit all values in reverse order - pub fn each_value_reverse(&self, f: &fn(&V) -> bool) -> bool { - self.each_reverse(|_, v| f(v)) - } - /// Get a lazy iterator over the key-value pairs in the map. /// Requires that it be frozen (immutable). pub fn iter<'a>(&'a self) -> TreeMapIterator<'a, K, V> { @@ -192,6 +150,12 @@ impl<K: TotalOrd, V> TreeMap<K, V> { } } + /// Get a lazy reverse iterator over the key-value pairs in the map. + /// Requires that it be frozen (immutable). + pub fn rev_iter<'a>(&'a self) -> TreeMapRevIterator<'a, K, V> { + TreeMapRevIterator{iter: self.iter()} + } + /// Get a lazy iterator that should be initialized using /// `iter_traverse_left`/`iter_traverse_right`/`iter_traverse_complete`. fn iter_for_traversal<'a>(&'a self) -> TreeMapIterator<'a, K, V> { @@ -249,13 +213,13 @@ impl<K: TotalOrd, V> TreeMap<K, V> { } /// Get a lazy iterator that consumes the treemap. - pub fn consume_iter(self) -> TreeMapConsumeIterator<K, V> { + pub fn move_iter(self) -> TreeMapMoveIterator<K, V> { let TreeMap { root: root, length: length } = self; let stk = match root { None => ~[], Some(~tn) => ~[tn] }; - TreeMapConsumeIterator { + TreeMapMoveIterator { stack: stk, remaining: length } @@ -270,20 +234,18 @@ pub struct TreeMapIterator<'self, K, V> { priv remaining_max: uint } -impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V> { - /// Advance the iterator to the next node (in order) and return a - /// tuple with a reference to the key and value. If there are no - /// more nodes, return `None`. - fn next(&mut self) -> Option<(&'self K, &'self V)> { +impl<'self, K, V> TreeMapIterator<'self, K, V> { + #[inline(always)] + fn next_(&mut self, forward: bool) -> Option<(&'self K, &'self V)> { while !self.stack.is_empty() || self.node.is_some() { match *self.node { Some(ref x) => { self.stack.push(x); - self.node = &x.left; + self.node = if forward { &x.left } else { &x.right }; } None => { let res = self.stack.pop(); - self.node = &res.right; + self.node = if forward { &res.right } else { &res.left }; self.remaining_max -= 1; if self.remaining_min > 0 { self.remaining_min -= 1; @@ -294,6 +256,15 @@ impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V } None } +} + +impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V> { + /// Advance the iterator to the next node (in order) and return a + /// tuple with a reference to the key and value. If there are no + /// more nodes, return `None`. + fn next(&mut self) -> Option<(&'self K, &'self V)> { + self.next_(true) + } #[inline] fn size_hint(&self) -> (uint, Option<uint>) { @@ -301,6 +272,25 @@ impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V } } +/// Lazy backward iterator over a map +pub struct TreeMapRevIterator<'self, K, V> { + priv iter: TreeMapIterator<'self, K, V>, +} + +impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapRevIterator<'self, K, V> { + /// Advance the iterator to the next node (in order) and return a + /// tuple with a reference to the key and value. If there are no + /// more nodes, return `None`. + fn next(&mut self) -> Option<(&'self K, &'self V)> { + self.iter.next_(false) + } + + #[inline] + fn size_hint(&self) -> (uint, Option<uint>) { + self.iter.size_hint() + } +} + /// iter_traverse_left, iter_traverse_right and iter_traverse_complete are used to /// initialize TreeMapIterator pointing to element inside tree structure. /// @@ -341,12 +331,12 @@ fn iter_traverse_complete<'a, K, V>(it: &mut TreeMapIterator<'a, K, V>) { } /// Lazy forward iterator over a map that consumes the map while iterating -pub struct TreeMapConsumeIterator<K, V> { +pub struct TreeMapMoveIterator<K, V> { priv stack: ~[TreeNode<K, V>], priv remaining: uint } -impl<K, V> Iterator<(K, V)> for TreeMapConsumeIterator<K,V> { +impl<K, V> Iterator<(K, V)> for TreeMapMoveIterator<K,V> { #[inline] fn next(&mut self) -> Option<(K, V)> { while !self.stack.is_empty() { @@ -398,6 +388,14 @@ impl<'self, T> Iterator<&'self T> for TreeSetIterator<'self, T> { } } +impl<'self, T> Iterator<&'self T> for TreeSetRevIterator<'self, T> { + /// Advance the iterator to the next node (in order). If there are no more nodes, return `None`. + #[inline] + fn next(&mut self) -> Option<&'self T> { + do self.iter.next().map |&(value, _)| { value } + } +} + /// A implementation of the `Set` trait on top of the `TreeMap` container. The /// only requirement is that the type of the elements contained ascribes to the /// `TotalOrd` trait. @@ -449,20 +447,7 @@ impl<T: TotalOrd> Set<T> for TreeSet<T> { /// Return true if the set has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. fn is_disjoint(&self, other: &TreeSet<T>) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); - let mut a = x.next(); - let mut b = y.next(); - while a.is_some() && b.is_some() { - let a1 = a.unwrap(); - let b1 = b.unwrap(); - match a1.cmp(b1) { - Less => a = x.next(), - Greater => b = y.next(), - Equal => return false - } - } - true + self.intersection(other).next().is_none() } /// Return true if the set is a subset of another @@ -521,6 +506,13 @@ impl<T: TotalOrd> TreeSet<T> { TreeSetIterator{iter: self.map.iter()} } + /// Get a lazy iterator over the values in the set. + /// Requires that it be frozen (immutable). + #[inline] + pub fn rev_iter<'a>(&'a self) -> TreeSetRevIterator<'a, T> { + TreeSetRevIterator{iter: self.map.rev_iter()} + } + /// Get a lazy iterator pointing to the first value not less than `v` (greater or equal). /// If all elements in the set are less than `v` empty iterator is returned. #[inline] @@ -535,138 +527,170 @@ impl<T: TotalOrd> TreeSet<T> { TreeSetIterator{iter: self.map.upper_bound_iter(v)} } - /// Visit all values in reverse order - #[inline] - pub fn each_reverse(&self, f: &fn(&T) -> bool) -> bool { - self.map.each_key_reverse(f) + /// Visit the values (in-order) representing the difference + pub fn difference<'a>(&'a self, other: &'a TreeSet<T>) -> Difference<'a, T> { + Difference{a: Focus::new(self.iter()), b: Focus::new(other.iter())} } - /// Visit the values (in-order) representing the difference - pub fn difference(&self, other: &TreeSet<T>, f: &fn(&T) -> bool) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); + /// Visit the values (in-order) representing the symmetric difference + pub fn symmetric_difference<'a>(&'a self, other: &'a TreeSet<T>) + -> SymDifference<'a, T> { + SymDifference{a: Focus::new(self.iter()), b: Focus::new(other.iter())} + } - let mut a = x.next(); - let mut b = y.next(); + /// Visit the values (in-order) representing the intersection + pub fn intersection<'a>(&'a self, other: &'a TreeSet<T>) + -> Intersection<'a, T> { + Intersection{a: Focus::new(self.iter()), b: Focus::new(other.iter())} + } - while a.is_some() { - if b.is_none() { - return f(a.unwrap()) && x.advance(f); - } + /// Visit the values (in-order) representing the union + pub fn union<'a>(&'a self, other: &'a TreeSet<T>) -> Union<'a, T> { + Union{a: Focus::new(self.iter()), b: Focus::new(other.iter())} + } +} - let a1 = a.unwrap(); - let b1 = b.unwrap(); +/// Lazy forward iterator over a set +pub struct TreeSetIterator<'self, T> { + priv iter: TreeMapIterator<'self, T, ()> +} - let cmp = a1.cmp(b1); +/// Lazy backward iterator over a set +pub struct TreeSetRevIterator<'self, T> { + priv iter: TreeMapRevIterator<'self, T, ()> +} - if cmp == Less { - if !f(a1) { return false; } - a = x.next(); - } else { - if cmp == Equal { a = x.next() } - b = y.next(); - } - } - return true; - } +// Encapsulate an iterator and hold its latest value until stepped forward +struct Focus<A, T> { + priv iter: T, + priv focus: Option<A>, +} - /// Visit the values (in-order) representing the symmetric difference - pub fn symmetric_difference(&self, other: &TreeSet<T>, - f: &fn(&T) -> bool) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); +impl<A, T: Iterator<A>> Focus<A, T> { + fn new(mut it: T) -> Focus<A, T> { + Focus{focus: it.next(), iter: it} + } + fn step(&mut self) { + self.focus = self.iter.next() + } +} - let mut a = x.next(); - let mut b = y.next(); +/// Lazy iterator producing elements in the set difference (in-order) +pub struct Difference<'self, T> { + priv a: Focus<&'self T, TreeSetIterator<'self, T>>, + priv b: Focus<&'self T, TreeSetIterator<'self, T>>, +} - while a.is_some() { - if b.is_none() { - return f(a.unwrap()) && x.advance(f); - } +/// Lazy iterator producing elements in the set symmetric difference (in-order) +pub struct SymDifference<'self, T> { + priv a: Focus<&'self T, TreeSetIterator<'self, T>>, + priv b: Focus<&'self T, TreeSetIterator<'self, T>>, +} - let a1 = a.unwrap(); - let b1 = b.unwrap(); +/// Lazy iterator producing elements in the set intersection (in-order) +pub struct Intersection<'self, T> { + priv a: Focus<&'self T, TreeSetIterator<'self, T>>, + priv b: Focus<&'self T, TreeSetIterator<'self, T>>, +} - let cmp = a1.cmp(b1); +/// Lazy iterator producing elements in the set intersection (in-order) +pub struct Union<'self, T> { + priv a: Focus<&'self T, TreeSetIterator<'self, T>>, + priv b: Focus<&'self T, TreeSetIterator<'self, T>>, +} - if cmp == Less { - if !f(a1) { return false; } - a = x.next(); - } else { - if cmp == Greater { - if !f(b1) { return false; } - } else { - a = x.next(); +impl<'self, T: TotalOrd> Iterator<&'self T> for Difference<'self, T> { + fn next(&mut self) -> Option<&'self T> { + loop { + match (self.a.focus, self.b.focus) { + (None , _ ) => return None, + (ret , None ) => { self.a.step(); return ret }, + (Some(a1), Some(b1)) => { + let cmp = a1.cmp(b1); + if cmp == Less { + self.a.step(); + return Some(a1); + } else { + if cmp == Equal { self.a.step() } + self.b.step(); + } } - b = y.next(); } } - b.iter().advance(|&x| f(x)) && y.advance(f) } +} - /// Visit the values (in-order) representing the intersection - pub fn intersection(&self, other: &TreeSet<T>, f: &fn(&T) -> bool) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); - - let mut a = x.next(); - let mut b = y.next(); - - while a.is_some() && b.is_some() { - let a1 = a.unwrap(); - let b1 = b.unwrap(); - - let cmp = a1.cmp(b1); - - if cmp == Less { - a = x.next(); - } else { - if cmp == Equal { - if !f(a1) { return false } +impl<'self, T: TotalOrd> Iterator<&'self T> for SymDifference<'self, T> { + fn next(&mut self) -> Option<&'self T> { + loop { + match (self.a.focus, self.b.focus) { + (ret , None ) => { self.a.step(); return ret }, + (None , ret ) => { self.b.step(); return ret }, + (Some(a1), Some(b1)) => { + let cmp = a1.cmp(b1); + if cmp == Less { + self.a.step(); + return Some(a1); + } else { + self.b.step(); + if cmp == Greater { + return Some(b1); + } else { + self.a.step(); + } + } } - b = y.next(); } } - return true; } +} - /// Visit the values (in-order) representing the union - pub fn union(&self, other: &TreeSet<T>, f: &fn(&T) -> bool) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); - - let mut a = x.next(); - let mut b = y.next(); - - while a.is_some() { - if b.is_none() { - return f(a.unwrap()) && x.advance(f); +impl<'self, T: TotalOrd> Iterator<&'self T> for Intersection<'self, T> { + fn next(&mut self) -> Option<&'self T> { + loop { + match (self.a.focus, self.b.focus) { + (None , _ ) => return None, + (_ , None ) => return None, + (Some(a1), Some(b1)) => { + let cmp = a1.cmp(b1); + if cmp == Less { + self.a.step(); + } else { + self.b.step(); + if cmp == Equal { + return Some(a1); + } + } + }, } + } + } +} - let a1 = a.unwrap(); - let b1 = b.unwrap(); - - let cmp = a1.cmp(b1); - - if cmp == Greater { - if !f(b1) { return false; } - b = y.next(); - } else { - if !f(a1) { return false; } - if cmp == Equal { - b = y.next(); +impl<'self, T: TotalOrd> Iterator<&'self T> for Union<'self, T> { + fn next(&mut self) -> Option<&'self T> { + loop { + match (self.a.focus, self.b.focus) { + (ret , None) => { self.a.step(); return ret }, + (None , ret ) => { self.b.step(); return ret }, + (Some(a1), Some(b1)) => { + let cmp = a1.cmp(b1); + if cmp == Greater { + self.b.step(); + return Some(b1); + } else { + self.a.step(); + if cmp == Equal { + self.b.step(); + } + return Some(a1); + } } - a = x.next(); } } - b.iter().advance(|&x| f(x)) && y.advance(f) } } -/// Lazy forward iterator over a set -pub struct TreeSetIterator<'self, T> { - priv iter: TreeMapIterator<'self, T, ()> -} // Nodes keep track of their level in the tree, starting at 1 in the // leaves and with a red child sharing the level of the parent. @@ -687,18 +711,6 @@ impl<K: TotalOrd, V> TreeNode<K, V> { } } -fn each<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode<K, V>>, - f: &fn(&'r K, &'r V) -> bool) -> bool { - node.iter().advance(|x| each(&x.left, |k,v| f(k,v)) && f(&x.key, &x.value) && - each(&x.right, |k,v| f(k,v))) -} - -fn each_reverse<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode<K, V>>, - f: &fn(&'r K, &'r V) -> bool) -> bool { - node.iter().advance(|x| each_reverse(&x.right, |k,v| f(k,v)) && f(&x.key, &x.value) && - each_reverse(&x.left, |k,v| f(k,v))) -} - fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode<K, V>>, f: &fn(&'r K, &'r mut V) -> bool) -> bool { @@ -1129,7 +1141,7 @@ mod test_treemap { } #[test] - fn test_each_reverse() { + fn test_rev_iter() { let mut m = TreeMap::new(); assert!(m.insert(3, 6)); @@ -1139,12 +1151,11 @@ mod test_treemap { assert!(m.insert(1, 2)); let mut n = 4; - do m.each_reverse |k, v| { + for (k, v) in m.rev_iter() { assert_eq!(*k, n); assert_eq!(*v, n * 2); n -= 1; - true - }; + } } #[test] @@ -1248,7 +1259,7 @@ mod test_treemap { fn test_from_iter() { let xs = ~[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - let map: TreeMap<int, int> = xs.iter().transform(|&x| x).collect(); + let map: TreeMap<int, int> = xs.iter().map(|&x| x).collect(); for &(k, v) in xs.iter() { assert_eq!(map.find(&k), Some(&v)); @@ -1405,7 +1416,7 @@ mod test_set { } #[test] - fn test_each_reverse() { + fn test_rev_iter() { let mut m = TreeSet::new(); assert!(m.insert(3)); @@ -1415,11 +1426,10 @@ mod test_set { assert!(m.insert(1)); let mut n = 4; - do m.each_reverse |x| { + for x in m.rev_iter() { assert_eq!(*x, n); n -= 1; - true - }; + } } fn check(a: &[int], b: &[int], expected: &[int], @@ -1442,7 +1452,7 @@ mod test_set { #[test] fn test_intersection() { fn check_intersection(a: &[int], b: &[int], expected: &[int]) { - check(a, b, expected, |x, y, z| x.intersection(y, z)) + check(a, b, expected, |x, y, f| x.intersection(y).advance(f)) } check_intersection([], [], []); @@ -1458,7 +1468,7 @@ mod test_set { #[test] fn test_difference() { fn check_difference(a: &[int], b: &[int], expected: &[int]) { - check(a, b, expected, |x, y, z| x.difference(y, z)) + check(a, b, expected, |x, y, f| x.difference(y).advance(f)) } check_difference([], [], []); @@ -1476,7 +1486,7 @@ mod test_set { fn test_symmetric_difference() { fn check_symmetric_difference(a: &[int], b: &[int], expected: &[int]) { - check(a, b, expected, |x, y, z| x.symmetric_difference(y, z)) + check(a, b, expected, |x, y, f| x.symmetric_difference(y).advance(f)) } check_symmetric_difference([], [], []); @@ -1491,7 +1501,7 @@ mod test_set { fn test_union() { fn check_union(a: &[int], b: &[int], expected: &[int]) { - check(a, b, expected, |x, y, z| x.union(y, z)) + check(a, b, expected, |x, y, f| x.union(y).advance(f)) } check_union([], [], []); @@ -1548,7 +1558,7 @@ mod test_set { fn test_from_iter() { let xs = ~[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let set: TreeSet<int> = xs.iter().transform(|&x| x).collect(); + let set: TreeSet<int> = xs.iter().map(|&x| x).collect(); for x in xs.iter() { assert!(set.contains(x)); diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index b4ba8acae47..61af5cd7839 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -18,7 +18,7 @@ use arc::{Arc,RWArc}; use treemap::TreeMap; use std::cell::Cell; -use std::comm::{PortOne, oneshot, send_one, recv_one}; +use std::comm::{PortOne, oneshot}; use std::either::{Either, Left, Right}; use std::io; use std::run; @@ -331,7 +331,7 @@ impl<'self> Prep<'self> { }; let chan = chan.take(); let v = blk(&exe); - send_one(chan, (exe, v)); + chan.send((exe, v)); } Right(port) } @@ -355,7 +355,7 @@ impl<'self, T:Send + None => fail!(), Some(Left(v)) => v, Some(Right(port)) => { - let (exe, v) = recv_one(port); + let (exe, v) = port.recv(); let s = json_encode(&v); do prep.ctxt.db.write |db| { db.cache(prep.fn_name, diff --git a/src/librust/rust.rs b/src/librust/rust.rs index 010486cdf85..b8f81a44759 100644 --- a/src/librust/rust.rs +++ b/src/librust/rust.rs @@ -128,7 +128,7 @@ fn rustc_help() { } fn find_cmd(command_string: &str) -> Option<Command> { - do COMMANDS.iter().find_ |command| { + do COMMANDS.iter().find |command| { command.cmd == command_string }.map_move(|x| *x) } diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 637ea159d79..5da769a60d7 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -16,12 +16,13 @@ use lib::llvm::llvm; use lib::llvm::ModuleRef; use lib; use metadata::common::LinkMeta; -use metadata::{encoder, csearch, cstore}; +use metadata::{encoder, csearch, cstore, filesearch}; use middle::trans::context::CrateContext; use middle::trans::common::gensym_name; use middle::ty; use util::ppaux; +use std::c_str::ToCStr; use std::char; use std::hash::Streaming; use std::hash; @@ -76,9 +77,9 @@ pub fn WriteOutputFile(sess: Session, OptLevel: c_int, EnableSegmentedStacks: bool) { unsafe { - do Triple.as_c_str |Triple| { - do Feature.as_c_str |Feature| { - do Output.as_c_str |Output| { + do Triple.to_c_str().with_ref |Triple| { + do Feature.to_c_str().with_ref |Feature| { + do Output.to_c_str().with_ref |Output| { let result = llvm::LLVMRustWriteOutputFile( PM, M, @@ -105,6 +106,7 @@ pub mod jit { use lib::llvm::{ModuleRef, ContextRef, ExecutionEngineRef}; use metadata::cstore; + use std::c_str::ToCStr; use std::cast; use std::local_data; use std::unstable::intrinsics; @@ -146,7 +148,7 @@ pub mod jit { debug!("linking: %s", path); - do path.as_c_str |buf_t| { + do path.to_c_str().with_ref |buf_t| { if !llvm::LLVMRustLoadCrate(manager, buf_t) { llvm_err(sess, ~"Could not link"); } @@ -165,7 +167,7 @@ pub mod jit { // Next, we need to get a handle on the _rust_main function by // looking up it's corresponding ValueRef and then requesting that // the execution engine compiles the function. - let fun = do "_rust_main".as_c_str |entry| { + let fun = do "_rust_main".to_c_str().with_ref |entry| { llvm::LLVMGetNamedFunction(m, entry) }; if fun.is_null() { @@ -230,6 +232,7 @@ pub mod write { use back::passes; + use std::c_str::ToCStr; use std::libc::{c_int, c_uint}; use std::path::Path; use std::run; @@ -263,14 +266,14 @@ pub mod write { output_type_bitcode => { if opts.optimize != session::No { let filename = output.with_filetype("no-opt.bc"); - do filename.to_str().as_c_str |buf| { + do filename.to_c_str().with_ref |buf| { llvm::LLVMWriteBitcodeToFile(llmod, buf); } } } _ => { let filename = output.with_filetype("bc"); - do filename.to_str().as_c_str |buf| { + do filename.to_c_str().with_ref |buf| { llvm::LLVMWriteBitcodeToFile(llmod, buf); } } @@ -333,7 +336,7 @@ pub mod write { // Always output the bitcode file with --save-temps let filename = output.with_filetype("opt.bc"); - do filename.to_str().as_c_str |buf| { + do filename.to_c_str().with_ref |buf| { llvm::LLVMWriteBitcodeToFile(llmod, buf) }; // Save the assembly file if -S is used @@ -391,13 +394,13 @@ pub mod write { if output_type == output_type_llvm_assembly { // Given options "-S --emit-llvm": output LLVM assembly - do output.to_str().as_c_str |buf_o| { + do output.to_c_str().with_ref |buf_o| { llvm::LLVMRustAddPrintModulePass(pm.llpm, llmod, buf_o); } } else { // If only a bitcode file is asked for by using the // '--emit-llvm' flag, then output it here - do output.to_str().as_c_str |buf| { + do output.to_c_str().with_ref |buf| { llvm::LLVMWriteBitcodeToFile(llmod, buf); } } @@ -497,6 +500,7 @@ pub fn build_link_meta(sess: Session, struct ProvidedMetas { name: Option<@str>, vers: Option<@str>, + pkg_id: Option<@str>, cmh_items: ~[@ast::MetaItem] } @@ -504,6 +508,7 @@ pub fn build_link_meta(sess: Session, ProvidedMetas { let mut name = None; let mut vers = None; + let mut pkg_id = None; let mut cmh_items = ~[]; let linkage_metas = attr::find_linkage_metas(c.attrs); attr::require_unique_names(sess.diagnostic(), linkage_metas); @@ -511,6 +516,7 @@ pub fn build_link_meta(sess: Session, match meta.name_str_pair() { Some((n, value)) if "name" == n => name = Some(value), Some((n, value)) if "vers" == n => vers = Some(value), + Some((n, value)) if "package_id" == n => pkg_id = Some(value), _ => cmh_items.push(*meta) } } @@ -518,6 +524,7 @@ pub fn build_link_meta(sess: Session, ProvidedMetas { name: name, vers: vers, + pkg_id: pkg_id, cmh_items: cmh_items } } @@ -525,7 +532,8 @@ pub fn build_link_meta(sess: Session, // This calculates CMH as defined above fn crate_meta_extras_hash(symbol_hasher: &mut hash::State, cmh_items: ~[@ast::MetaItem], - dep_hashes: ~[@str]) -> @str { + dep_hashes: ~[@str], + pkg_id: Option<@str>) -> @str { fn len_and_str(s: &str) -> ~str { fmt!("%u_%s", s.len(), s) } @@ -563,7 +571,10 @@ pub fn build_link_meta(sess: Session, write_string(symbol_hasher, len_and_str(*dh)); } - // tjc: allocation is unfortunate; need to change std::hash + for p in pkg_id.iter() { + write_string(symbol_hasher, len_and_str(*p)); + } + return truncated_hash_result(symbol_hasher).to_managed(); } @@ -605,6 +616,7 @@ pub fn build_link_meta(sess: Session, let ProvidedMetas { name: opt_name, vers: opt_vers, + pkg_id: opt_pkg_id, cmh_items: cmh_items } = provided_link_metas(sess, c); let name = crate_meta_name(sess, output, opt_name); @@ -612,11 +624,12 @@ pub fn build_link_meta(sess: Session, let dep_hashes = cstore::get_dep_hashes(sess.cstore); let extras_hash = crate_meta_extras_hash(symbol_hasher, cmh_items, - dep_hashes); + dep_hashes, opt_pkg_id); LinkMeta { name: name, vers: vers, + package_id: opt_pkg_id, extras_hash: extras_hash } } @@ -922,7 +935,7 @@ pub fn link_args(sess: Session, // Add all the link args for external crates. do cstore::iter_crate_data(cstore) |crate_num, _| { let link_args = csearch::get_link_args_for_crate(cstore, crate_num); - for link_arg in link_args.consume_iter() { + for link_arg in link_args.move_iter() { args.push(link_arg); } } @@ -939,6 +952,11 @@ pub fn link_args(sess: Session, args.push(~"-L" + path.to_str()); } + let rustpath = filesearch::rust_path(); + for path in rustpath.iter() { + args.push(~"-L" + path.to_str()); + } + // The names of the extern libraries let used_libs = cstore::get_used_libraries(cstore); for l in used_libs.iter() { args.push(~"-l" + *l); } diff --git a/src/librustc/back/passes.rs b/src/librustc/back/passes.rs index 35d070baa9b..854d11fd350 100644 --- a/src/librustc/back/passes.rs +++ b/src/librustc/back/passes.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::c_str::ToCStr; use std::io; use driver::session::{OptLevel, No, Less, Aggressive}; @@ -172,7 +173,7 @@ pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~s } pub fn create_pass(name:&str) -> Option<PassRef> { - do name.as_c_str |s| { + do name.to_c_str().with_ref |s| { unsafe { let p = llvm::LLVMCreatePass(s); if p.is_null() { diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs index 571721ed40c..e7706815ff5 100644 --- a/src/librustc/back/rpath.rs +++ b/src/librustc/back/rpath.rs @@ -14,10 +14,7 @@ use metadata::cstore; use metadata::filesearch; use std::hashmap::HashSet; -use std::num; -use std::os; -use std::util; -use std::vec; +use std::{os, util, vec}; fn not_win32(os: session::os) -> bool { os != session::os_win32 @@ -52,7 +49,7 @@ fn get_sysroot_absolute_rt_lib(sess: session::Session) -> Path { } pub fn rpaths_to_flags(rpaths: &[Path]) -> ~[~str] { - rpaths.iter().transform(|rpath| fmt!("-Wl,-rpath,%s",rpath.to_str())).collect() + rpaths.iter().map(|rpath| fmt!("-Wl,-rpath,%s",rpath.to_str())).collect() } fn get_rpaths(os: session::os, @@ -103,7 +100,7 @@ fn get_rpaths(os: session::os, fn get_rpaths_relative_to_output(os: session::os, output: &Path, libs: &[Path]) -> ~[Path] { - libs.iter().transform(|a| get_rpath_relative_to_output(os, output, a)).collect() + libs.iter().map(|a| get_rpath_relative_to_output(os, output, a)).collect() } pub fn get_rpath_relative_to_output(os: session::os, @@ -122,52 +119,18 @@ pub fn get_rpath_relative_to_output(os: session::os, session::os_win32 => util::unreachable() }; - Path(prefix).push_rel(&get_relative_to(&os::make_absolute(output), - &os::make_absolute(lib))) -} - -// Find the relative path from one file to another -pub fn get_relative_to(abs1: &Path, abs2: &Path) -> Path { - assert!(abs1.is_absolute); - assert!(abs2.is_absolute); - let abs1 = abs1.normalize(); - let abs2 = abs2.normalize(); - debug!("finding relative path from %s to %s", - abs1.to_str(), abs2.to_str()); - let split1: &[~str] = abs1.components; - let split2: &[~str] = abs2.components; - let len1 = split1.len(); - let len2 = split2.len(); - assert!(len1 > 0); - assert!(len2 > 0); - - let max_common_path = num::min(len1, len2) - 1; - let mut start_idx = 0; - while start_idx < max_common_path - && split1[start_idx] == split2[start_idx] { - start_idx += 1; - } - - let mut path = ~[]; - for _ in range(start_idx, len1 - 1) { path.push(~".."); }; - - path.push_all(split2.slice(start_idx, len2 - 1)); - - return if !path.is_empty() { - Path("").push_many(path) - } else { - Path(".") - } + Path(prefix).push_rel(&os::make_absolute(output).get_relative_to(&os::make_absolute(lib))) } fn get_absolute_rpaths(libs: &[Path]) -> ~[Path] { - libs.iter().transform(|a| get_absolute_rpath(a)).collect() + libs.iter().map(|a| get_absolute_rpath(a)).collect() } pub fn get_absolute_rpath(lib: &Path) -> Path { os::make_absolute(lib).dir_path() } +#[cfg(stage0)] pub fn get_install_prefix_rpath(target_triple: &str) -> Path { let install_prefix = env!("CFG_PREFIX"); @@ -179,6 +142,14 @@ pub fn get_install_prefix_rpath(target_triple: &str) -> Path { os::make_absolute(&Path(install_prefix).push_rel(&tlib)) } +#[cfg(not(stage0))] +pub fn get_install_prefix_rpath(target_triple: &str) -> Path { + let install_prefix = env!("CFG_PREFIX"); + + let tlib = filesearch::relative_target_lib_path(target_triple); + os::make_absolute(&Path(install_prefix).push_rel(&tlib)) +} + pub fn minimize_rpaths(rpaths: &[Path]) -> ~[Path] { let mut set = HashSet::new(); let mut minimized = ~[]; @@ -199,8 +170,7 @@ mod test { #[cfg(test)] #[cfg(test)] use back::rpath::{get_absolute_rpath, get_install_prefix_rpath}; - use back::rpath::{get_relative_to, get_rpath_relative_to_output}; - use back::rpath::{minimize_rpaths, rpaths_to_flags}; + use back::rpath::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output}; use driver::session; #[test] @@ -245,77 +215,8 @@ mod test { } #[test] - fn test_relative_to1() { - let p1 = Path("/usr/bin/rustc"); - let p2 = Path("/usr/lib/mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../lib")); - } - - #[test] - fn test_relative_to2() { - let p1 = Path("/usr/bin/rustc"); - let p2 = Path("/usr/bin/../lib/mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../lib")); - } - - #[test] - fn test_relative_to3() { - let p1 = Path("/usr/bin/whatever/rustc"); - let p2 = Path("/usr/lib/whatever/mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../../lib/whatever")); - } - - #[test] - fn test_relative_to4() { - let p1 = Path("/usr/bin/whatever/../rustc"); - let p2 = Path("/usr/lib/whatever/mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../lib/whatever")); - } - - #[test] - fn test_relative_to5() { - let p1 = Path("/usr/bin/whatever/../rustc"); - let p2 = Path("/usr/lib/whatever/../mylib"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("../lib")); - } - - #[test] - fn test_relative_to6() { - let p1 = Path("/1"); - let p2 = Path("/2/3"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("2")); - } - - #[test] - fn test_relative_to7() { - let p1 = Path("/1/2"); - let p2 = Path("/3"); - let res = get_relative_to(&p1, &p2); - assert_eq!(res, Path("..")); - } - - #[test] - fn test_relative_to8() { - let p1 = Path("/home/brian/Dev/rust/build/").push_rel( - &Path("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so")); - let p2 = Path("/home/brian/Dev/rust/build/stage2/bin/..").push_rel( - &Path("lib/rustc/i686-unknown-linux-gnu/lib/libstd.so")); - let res = get_relative_to(&p1, &p2); - debug!("test_relative_tu8: %s vs. %s", - res.to_str(), - Path(".").to_str()); - assert_eq!(res, Path(".")); - } - - #[test] #[cfg(target_os = "linux")] - #[cfg(target_os = "andorid")] + #[cfg(target_os = "android")] fn test_rpath_relative() { let o = session::os_linux; let res = get_rpath_relative_to_output(o, @@ -335,7 +236,6 @@ mod test { #[test] #[cfg(target_os = "macos")] fn test_rpath_relative() { - // this is why refinements would be nice let o = session::os_macos; let res = get_rpath_relative_to_output(o, &Path("bin/rustc"), diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 61ab826e9ee..fdf88757469 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.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. // @@ -120,7 +120,7 @@ pub fn build_configuration(sess: Session, argv0: @str, input: &input) -> // Convert strings provided as --cfg [cfgspec] into a crate_cfg fn parse_cfgspecs(cfgspecs: ~[~str], demitter: diagnostic::Emitter) -> ast::CrateConfig { - do cfgspecs.consume_iter().transform |s| { + do cfgspecs.move_iter().map |s| { let sess = parse::new_parse_sess(Some(demitter)); parse::parse_meta_from_source_str(@"cfgspec", s.to_managed(), ~[], sess) }.collect::<ast::CrateConfig>() @@ -578,6 +578,7 @@ pub fn build_target_config(sopts: @session::options, return target_cfg; } +#[cfg(stage0)] pub fn host_triple() -> ~str { // Get the host triple out of the build environment. This ensures that our // idea of the host triple is the same as for the set of libraries we've @@ -595,6 +596,19 @@ pub fn host_triple() -> ~str { }; } +#[cfg(not(stage0))] +pub fn host_triple() -> ~str { + // Get the host triple out of the build environment. This ensures that our + // idea of the host triple is the same as for the set of libraries we've + // actually built. We can't just take LLVM's host triple because they + // normalize all ix86 architectures to i386. + // + // Instead of grabbing the host triple (for the current host), we grab (at + // compile time) the target triple that this rustc is built with and + // calling that (at runtime) the host triple. + (env!("CFG_COMPILER_TRIPLE")).to_owned() +} + pub fn build_session_options(binary: @str, matches: &getopts::Matches, demitter: diagnostic::Emitter) @@ -617,7 +631,7 @@ pub fn build_session_options(binary: @str, let level_name = lint::level_to_str(*level); // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use - // to_ascii_consume and to_str_consume to not do a unnecessary copy. + // to_ascii_move and to_str_move to not do a unnecessary copy. let level_short = level_name.slice_chars(0, 1); let level_short = level_short.to_ascii().to_upper().to_str_ascii(); let flags = vec::append(getopts::opt_strs(matches, level_short), @@ -712,7 +726,7 @@ pub fn build_session_options(binary: @str, let addl_lib_search_paths = getopts::opt_strs(matches, "L").map(|s| Path(*s)); let linker = getopts::opt_maybe_str(matches, "linker"); let linker_args = getopts::opt_strs(matches, "link-args").flat_map( |a| { - a.split_iter(' ').transform(|arg| arg.to_owned()).collect() + a.split_iter(' ').map(|arg| arg.to_owned()).collect() }); let cfg = parse_cfgspecs(getopts::opt_strs(matches, "cfg"), demitter); @@ -723,7 +737,7 @@ pub fn build_session_options(binary: @str, let custom_passes = match getopts::opt_maybe_str(matches, "passes") { None => ~[], Some(s) => { - s.split_iter(|c: char| c == ' ' || c == ',').transform(|s| { + s.split_iter(|c: char| c == ' ' || c == ',').map(|s| { s.trim().to_owned() }).collect() } @@ -821,7 +835,8 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] { optmulti("", "cfg", "Configure the compilation environment", "SPEC"), optflag("", "emit-llvm", - "Produce an LLVM bitcode file"), + "Produce an LLVM assembly file if used with -S option; + produce an LLVM bitcode file otherwise"), optflag("h", "help","Display this message"), optmulti("L", "", "Add a directory to the library search path", "PATH"), @@ -931,7 +946,7 @@ pub fn build_output_filenames(input: &input, let linkage_metas = attr::find_linkage_metas(attrs); if !linkage_metas.is_empty() { // But if a linkage meta is present, that overrides - let maybe_name = linkage_metas.iter().find_(|m| "name" == m.name()); + let maybe_name = linkage_metas.iter().find(|m| "name" == m.name()); match maybe_name.chain(|m| m.value_str()) { Some(s) => stem = s, _ => () diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs index d6584846655..026532c89c3 100644 --- a/src/librustc/front/config.rs +++ b/src/librustc/front/config.rs @@ -102,12 +102,12 @@ fn fold_item_underscore(cx: @Context, item: &ast::item_, let item = match *item { ast::item_impl(ref a, ref b, ref c, ref methods) => { let methods = methods.iter().filter(|m| method_in_cfg(cx, **m)) - .transform(|x| *x).collect(); + .map(|x| *x).collect(); ast::item_impl((*a).clone(), (*b).clone(), (*c).clone(), methods) } ast::item_trait(ref a, ref b, ref methods) => { let methods = methods.iter().filter(|m| trait_method_in_cfg(cx, *m) ) - .transform(|x| (*x).clone()).collect(); + .map(|x| (*x).clone()).collect(); ast::item_trait((*a).clone(), (*b).clone(), methods) } ref item => (*item).clone(), @@ -180,5 +180,5 @@ fn trait_method_in_cfg(cx: @Context, meth: &ast::trait_method) -> bool { // Determine if an item should be translated in the current crate // configuration based on the item's attributes fn in_cfg(cfg: &[@ast::MetaItem], attrs: &[ast::Attribute]) -> bool { - attr::test_cfg(cfg, attrs.iter().transform(|x| *x)) + attr::test_cfg(cfg, attrs.iter().map(|x| *x)) } diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index 3a1129b1dd9..2a61ea28e0c 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -47,7 +47,7 @@ fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate { let n1 = sess.next_node_id(); let vi1 = ast::view_item { node: ast::view_item_extern_mod( - sess.ident_of("std"), ~[], n1), + sess.ident_of("std"), None, ~[], n1), attrs: ~[ attr::mk_attr( attr::mk_name_value_item_str(@"vers", STD_VERSION.to_managed())) diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index d2d2a8b4be9..597de440ae1 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -126,7 +126,7 @@ fn fold_mod(cx: @mut TestCtxt, let mod_nomain = ast::_mod { view_items: m.view_items.clone(), - items: m.items.iter().transform(|i| nomain(cx, *i)).collect(), + items: m.items.iter().map(|i| nomain(cx, *i)).collect(), }; fold::noop_fold_mod(&mod_nomain, fld) @@ -236,7 +236,7 @@ fn is_ignored(cx: @mut TestCtxt, i: @ast::item) -> bool { do i.attrs.iter().any |attr| { // check ignore(cfg(foo, bar)) "ignore" == attr.name() && match attr.meta_item_list() { - Some(ref cfgs) => attr::test_cfg(cx.crate.config, cfgs.iter().transform(|x| *x)), + Some(ref cfgs) => attr::test_cfg(cx.crate.config, cfgs.iter().map(|x| *x)), None => true } } @@ -282,7 +282,7 @@ fn mk_std(cx: &TestCtxt) -> ast::view_item { cx.sess.next_node_id()))]) } else { let mi = attr::mk_name_value_item_str(@"vers", @"0.8-pre"); - ast::view_item_extern_mod(id_extra, ~[mi], cx.sess.next_node_id()) + ast::view_item_extern_mod(id_extra, None, ~[mi], cx.sess.next_node_id()) }; ast::view_item { node: vi, diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 90db3f8edb0..5801e43a54c 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - +use std::c_str::ToCStr; use std::hashmap::HashMap; use std::libc::{c_uint, c_ushort}; use std::option; @@ -1553,6 +1553,8 @@ pub mod llvm { /* Selected entries from the downcasts. */ #[fast_ffi] pub fn LLVMIsATerminatorInst(Inst: ValueRef) -> ValueRef; + #[fast_ffi] + pub fn LLVMIsAStoreInst(Inst: ValueRef) -> ValueRef; /** Writes a module to the specified path. Returns 0 on success. */ #[fast_ffi] @@ -2259,7 +2261,7 @@ pub struct TargetData { } pub fn mk_target_data(string_rep: &str) -> TargetData { - let lltd = do string_rep.as_c_str |buf| { + let lltd = do string_rep.to_c_str().with_ref |buf| { unsafe { llvm::LLVMCreateTargetData(buf) } }; diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 1c5d202d4d9..f2d8b68faa6 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -185,5 +185,7 @@ pub static tag_item_impl_vtables: uint = 0x82; pub struct LinkMeta { name: @str, vers: @str, + // Optional package ID + package_id: Option<@str>, // non-None if this was a URL-like package ID extras_hash: @str } diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index d8f14228824..82f5c4f8843 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -18,6 +18,7 @@ use metadata::loader; use std::hashmap::HashMap; use syntax::ast; +use std::vec; use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::codemap::{span, dummy_sp}; @@ -82,7 +83,7 @@ fn warn_if_multiple_versions(e: @mut Env, *crate_cache[crate_cache.len() - 1].metas ); - let vec: ~[Either<cache_entry, cache_entry>] = crate_cache.iter().transform(|&entry| { + let vec: ~[Either<cache_entry, cache_entry>] = crate_cache.iter().map(|&entry| { let othername = loader::crate_name_from_metas(*entry.metas); if name == othername { Left(entry) @@ -137,18 +138,33 @@ fn visit_crate(e: &Env, c: &ast::Crate) { fn visit_view_item(e: @mut Env, i: &ast::view_item) { match i.node { - ast::view_item_extern_mod(ident, ref meta_items, id) => { - debug!("resolving extern mod stmt. ident: %?, meta: %?", - ident, *meta_items); - let cnum = resolve_crate(e, - ident, - (*meta_items).clone(), - @"", - i.span); - cstore::add_extern_mod_stmt_cnum(e.cstore, id, cnum); + ast::view_item_extern_mod(ident, path_opt, ref meta_items, id) => { + let ident = token::ident_to_str(&ident); + let meta_items = match path_opt { + None => meta_items.clone(), + Some(p) => { + let p_path = Path(p); + match p_path.filestem() { + Some(s) => + vec::append( + ~[attr::mk_name_value_item_str(@"package_id", p), + attr::mk_name_value_item_str(@"name", s.to_managed())], + *meta_items), + None => e.diag.span_bug(i.span, "Bad package path in `extern mod` item") + } + } + }; + debug!("resolving extern mod stmt. ident: %?, meta: %?", + ident, meta_items); + let cnum = resolve_crate(e, + ident, + meta_items, + @"", + i.span); + cstore::add_extern_mod_stmt_cnum(e.cstore, id, cnum); } _ => () - } + } } fn visit_item(e: &Env, i: @ast::item) { @@ -167,7 +183,7 @@ fn visit_item(e: &Env, i: @ast::item) { match fm.sort { ast::named => { let link_name = i.attrs.iter() - .find_(|at| "link_name" == at.name()) + .find(|at| "link_name" == at.name()) .chain(|at| at.value_str()); let foreign_name = match link_name { @@ -233,12 +249,12 @@ fn existing_match(e: &Env, metas: &[@ast::MetaItem], hash: &str) } fn resolve_crate(e: @mut Env, - ident: ast::ident, + ident: @str, metas: ~[@ast::MetaItem], hash: @str, span: span) -> ast::CrateNum { - let metas = metas_with_ident(token::ident_to_str(&ident), metas); + let metas = metas_with_ident(ident, metas); match existing_match(e, metas, hash) { None => { @@ -279,7 +295,7 @@ fn resolve_crate(e: @mut Env, match attr::last_meta_item_value_str_by_name(load_ctxt.metas, "name") { Some(v) => v, - None => token::ident_to_str(&ident), + None => ident }; let cmeta = @cstore::crate_metadata { name: cname, @@ -308,7 +324,6 @@ fn resolve_crate_deps(e: @mut Env, cdata: @~[u8]) -> cstore::cnum_map { let r = decoder::get_crate_deps(cdata); for dep in r.iter() { let extrn_cnum = dep.cnum; - let cname = dep.name; let cname_str = token::ident_to_str(&dep.name); let cmetas = metas_with(dep.vers, @"vers", ~[]); debug!("resolving dep crate %s ver: %s hash: %s", @@ -327,7 +342,7 @@ fn resolve_crate_deps(e: @mut Env, cdata: @~[u8]) -> cstore::cnum_map { // FIXME (#2404): Need better error reporting than just a bogus // span. let fake_span = dummy_sp(); - let local_cnum = resolve_crate(e, cname, cmetas, dep.hash, + let local_cnum = resolve_crate(e, cname_str, cmetas, dep.hash, fake_span); cnum_map.insert(extrn_cnum, local_cnum); } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 8d357126018..81a2e863bde 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -51,20 +51,20 @@ type cmd = @crate_metadata; // what crate that's in and give us a def_id that makes sense for the current // build. -fn lookup_hash(d: ebml::Doc, eq_fn: &fn(x:&[u8]) -> bool, hash: uint) -> +fn lookup_hash(d: ebml::Doc, eq_fn: &fn(x:&[u8]) -> bool, hash: u64) -> Option<ebml::Doc> { let index = reader::get_doc(d, tag_index); let table = reader::get_doc(index, tag_index_table); - let hash_pos = table.start + hash % 256u * 4u; - let pos = io::u64_from_be_bytes(*d.data, hash_pos, 4u) as uint; + let hash_pos = table.start + (hash % 256 * 4) as uint; + let pos = io::u64_from_be_bytes(*d.data, hash_pos, 4) as uint; let tagged_doc = reader::doc_at(d.data, pos); let belt = tag_index_buckets_bucket_elt; let mut ret = None; do reader::tagged_docs(tagged_doc.doc, belt) |elt| { - let pos = io::u64_from_be_bytes(*elt.data, elt.start, 4u) as uint; - if eq_fn(elt.data.slice(elt.start + 4u, elt.end)) { + let pos = io::u64_from_be_bytes(*elt.data, elt.start, 4) as uint; + if eq_fn(elt.data.slice(elt.start + 4, elt.end)) { ret = Some(reader::doc_at(d.data, pos).doc); false } else { @@ -84,7 +84,7 @@ pub fn maybe_find_item(item_id: int, items: ebml::Doc) -> Option<ebml::Doc> { } lookup_hash(items, |a| eq_item(a, item_id), - item_id.hash() as uint) + (item_id as i64).hash()) } fn find_item(item_id: int, items: ebml::Doc) -> ebml::Doc { diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index d847d851126..c4919e7f263 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -319,7 +319,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext, id: NodeId, variants: &[variant], path: &[ast_map::path_elt], - index: @mut ~[entry<int>], + index: @mut ~[entry<i64>], generics: &ast::Generics) { debug!("encode_enum_variant_info(id=%?)", id); @@ -329,7 +329,8 @@ fn encode_enum_variant_info(ecx: &EncodeContext, ast::def_id { crate: LOCAL_CRATE, node: id }); for variant in variants.iter() { let def_id = local_def(variant.node.id); - index.push(entry {val: variant.node.id, pos: ebml_w.writer.tell()}); + index.push(entry {val: variant.node.id as i64, + pos: ebml_w.writer.tell()}); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, def_id); encode_family(ebml_w, 'v'); @@ -677,8 +678,8 @@ fn encode_info_for_struct(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, path: &[ast_map::path_elt], fields: &[@struct_field], - global_index: @mut ~[entry<int>]) - -> ~[entry<int>] { + global_index: @mut ~[entry<i64>]) + -> ~[entry<i64>] { /* Each class has its own index, since different classes may have fields with the same name */ let mut index = ~[]; @@ -692,8 +693,8 @@ fn encode_info_for_struct(ecx: &EncodeContext, }; let id = field.node.id; - index.push(entry {val: id, pos: ebml_w.writer.tell()}); - global_index.push(entry {val: id, pos: ebml_w.writer.tell()}); + index.push(entry {val: id as i64, pos: ebml_w.writer.tell()}); + global_index.push(entry {val: id as i64, pos: ebml_w.writer.tell()}); ebml_w.start_tag(tag_items_data_item); debug!("encode_info_for_struct: doing %s %d", tcx.sess.str_of(nm), id); @@ -712,8 +713,8 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext, path: &[ast_map::path_elt], name: ast::ident, ctor_id: NodeId, - index: @mut ~[entry<int>]) { - index.push(entry { val: ctor_id, pos: ebml_w.writer.tell() }); + index: @mut ~[entry<i64>]) { + index.push(entry { val: ctor_id as i64, pos: ebml_w.writer.tell() }); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(ctor_id)); @@ -815,13 +816,13 @@ fn should_inline(attrs: &[Attribute]) -> bool { fn encode_info_for_item(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, item: @item, - index: @mut ~[entry<int>], + index: @mut ~[entry<i64>], path: &[ast_map::path_elt]) { let tcx = ecx.tcx; fn add_to_index_(item: @item, ebml_w: &writer::Encoder, - index: @mut ~[entry<int>]) { - index.push(entry { val: item.id, pos: ebml_w.writer.tell() }); + index: @mut ~[entry<i64>]) { + index.push(entry { val: item.id as i64, pos: ebml_w.writer.tell() }); } let add_to_index: &fn() = || add_to_index_(item, ebml_w, index); @@ -969,7 +970,7 @@ fn encode_info_for_item(ecx: &EncodeContext, /* Each class has its own index -- encode it */ let bkts = create_index(idx); - encode_index(ebml_w, bkts, write_int); + encode_index(ebml_w, bkts, write_i64); ebml_w.end_tag(); // If this is a tuple- or enum-like struct, encode the type of the @@ -1040,7 +1041,8 @@ fn encode_info_for_item(ecx: &EncodeContext, Some(ast_methods[i]) } else { None }; - index.push(entry {val: m.def_id.node, pos: ebml_w.writer.tell()}); + index.push(entry {val: m.def_id.node as i64, + pos: ebml_w.writer.tell()}); encode_info_for_method(ecx, ebml_w, *m, @@ -1086,7 +1088,8 @@ fn encode_info_for_item(ecx: &EncodeContext, let method_ty = ty::method(tcx, method_def_id); - index.push(entry {val: method_def_id.node, pos: ebml_w.writer.tell()}); + index.push(entry {val: method_def_id.node as i64, + pos: ebml_w.writer.tell()}); ebml_w.start_tag(tag_items_data_item); @@ -1145,10 +1148,10 @@ fn encode_info_for_item(ecx: &EncodeContext, fn encode_info_for_foreign_item(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, nitem: @foreign_item, - index: @mut ~[entry<int>], + index: @mut ~[entry<i64>], path: &ast_map::path, abi: AbiSet) { - index.push(entry { val: nitem.id, pos: ebml_w.writer.tell() }); + index.push(entry { val: nitem.id as i64, pos: ebml_w.writer.tell() }); ebml_w.start_tag(tag_items_data_item); match nitem.node { @@ -1184,10 +1187,10 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, fn encode_info_for_items(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, crate: &Crate) - -> ~[entry<int>] { + -> ~[entry<i64>] { let index = @mut ~[]; ebml_w.start_tag(tag_items_data); - index.push(entry { val: CRATE_NODE_ID, pos: ebml_w.writer.tell() }); + index.push(entry { val: CRATE_NODE_ID as i64, pos: ebml_w.writer.tell() }); encode_info_for_mod(ecx, ebml_w, &crate.module, @@ -1304,7 +1307,7 @@ fn write_str(writer: @io::Writer, s: ~str) { writer.write_str(s); } -fn write_int(writer: @io::Writer, &n: &int) { +fn write_i64(writer: @io::Writer, &n: &i64) { assert!(n < 0x7fff_ffff); writer.write_be_u32(n as u32); } @@ -1623,7 +1626,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] { i = *wr.pos; let items_buckets = create_index(items_index); - encode_index(&mut ebml_w, items_buckets, write_int); + encode_index(&mut ebml_w, items_buckets, write_i64); ecx.stats.index_bytes = *wr.pos - i; ebml_w.end_tag(); diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 2422be3960b..56200a221be 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.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,12 +11,14 @@ use std::option; use std::os; -use std::result; +use std::hashmap::HashSet; // A module for searching for libraries // FIXME (#2658): I'm not happy how this module turned out. Should // probably just be folded into cstore. +/// Functions with type `pick` take a parent directory as well as +/// a file found in that directory. pub type pick<'self, T> = &'self fn(path: &Path) -> Option<T>; pub fn pick_file(file: Path, path: &Path) -> Option<Path> { @@ -46,28 +48,33 @@ pub fn mk_filesearch(maybe_sysroot: &Option<@Path>, impl FileSearch for FileSearchImpl { fn sysroot(&self) -> @Path { self.sysroot } fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool { + let mut visited_dirs = HashSet::new(); + debug!("filesearch: searching additional lib search paths [%?]", self.addl_lib_search_paths.len()); - // a little weird - self.addl_lib_search_paths.iter().advance(|path| f(path)); + for path in self.addl_lib_search_paths.iter() { + f(path); + visited_dirs.insert(path.to_str()); + } debug!("filesearch: searching target lib path"); - if !f(&make_target_lib_path(self.sysroot, - self.target_triple)) { - return false; - } - debug!("filesearch: searching rustpkg lib path nearest"); - if match get_rustpkg_lib_path_nearest() { - result::Ok(ref p) => f(p), - result::Err(_) => true - } { - return true; + let tlib_path = make_target_lib_path(self.sysroot, + self.target_triple); + if !visited_dirs.contains(&tlib_path.to_str()) { + if !f(&tlib_path) { + return false; } - debug!("filesearch: searching rustpkg lib path"); - match get_rustpkg_lib_path() { - result::Ok(ref p) => f(p), - result::Err(_) => true - } + } + visited_dirs.insert(tlib_path.to_str()); + // Try RUST_PATH + let rustpath = rust_path(); + for path in rustpath.iter() { + if !visited_dirs.contains(&path.push("lib").to_str()) { + f(&path.push("lib")); + visited_dirs.insert(path.push("lib").to_str()); + } + } + true } fn get_target_lib_path(&self) -> Path { make_target_lib_path(self.sysroot, self.target_triple) @@ -94,12 +101,15 @@ pub fn search<T>(filesearch: @FileSearch, pick: pick<T>) -> Option<T> { for path in r.iter() { debug!("testing %s", path.to_str()); let maybe_picked = pick(path); - if maybe_picked.is_some() { - debug!("picked %s", path.to_str()); - rslt = maybe_picked; - break; - } else { - debug!("rejected %s", path.to_str()); + match maybe_picked { + Some(_) => { + debug!("picked %s", path.to_str()); + rslt = maybe_picked; + break; + } + None => { + debug!("rejected %s", path.to_str()); + } } } rslt.is_none() @@ -132,60 +142,65 @@ fn get_sysroot(maybe_sysroot: &Option<@Path>) -> @Path { } } -pub fn get_rustpkg_sysroot() -> Result<Path, ~str> { - result::Ok(get_or_default_sysroot().push_many([libdir(), ~"rustpkg"])) +#[cfg(windows)] +static PATH_ENTRY_SEPARATOR: &'static str = ";"; +#[cfg(not(windows))] +static PATH_ENTRY_SEPARATOR: &'static str = ":"; + +/// Returns RUST_PATH as a string, without default paths added +pub fn get_rust_path() -> Option<~str> { + os::getenv("RUST_PATH") } -pub fn get_rustpkg_root() -> Result<Path, ~str> { - match os::getenv("RUSTPKG_ROOT") { - Some(ref _p) => result::Ok(Path((*_p))), - None => match os::homedir() { - Some(ref _q) => result::Ok((*_q).push(".rustpkg")), - None => result::Err(~"no RUSTPKG_ROOT or home directory") +/// Returns the value of RUST_PATH, as a list +/// of Paths. Includes default entries for, if they exist: +/// $HOME/.rust +/// DIR/.rust for any DIR that's the current working directory +/// or an ancestor of it +pub fn rust_path() -> ~[Path] { + let mut env_rust_path: ~[Path] = match get_rust_path() { + Some(env_path) => { + let env_path_components: ~[&str] = + env_path.split_str_iter(PATH_ENTRY_SEPARATOR).collect(); + env_path_components.map(|&s| Path(s)) } + None => ~[] + }; + let cwd = os::getcwd(); + // now add in default entries + let cwd_dot_rust = cwd.push(".rust"); + if !env_rust_path.contains(&cwd_dot_rust) { + env_rust_path.push(cwd_dot_rust); } -} - -pub fn get_rustpkg_root_nearest() -> Result<Path, ~str> { - do get_rustpkg_root().chain |p| { - let cwd = os::getcwd(); - let cwd_rustpkg = cwd.push(".rustpkg"); - let rustpkg_is_non_root_file = - !os::path_is_dir(&cwd_rustpkg) && cwd_rustpkg != p; - let mut par_rustpkg = cwd.pop().push(".rustpkg"); - let mut rslt = result::Ok(cwd_rustpkg); - - if rustpkg_is_non_root_file { - while par_rustpkg != p { - if os::path_is_dir(&par_rustpkg) { - rslt = result::Ok(par_rustpkg); - break; - } - if par_rustpkg.components.len() == 1 { - // We just checked /.rustpkg, stop now. - break; - } - par_rustpkg = par_rustpkg.pop().pop().push(".rustpkg"); - } + if !env_rust_path.contains(&cwd) { + env_rust_path.push(cwd.clone()); + } + do cwd.each_parent() |p| { + if !env_rust_path.contains(&p.push(".rust")) { + push_if_exists(&mut env_rust_path, p); } - rslt } -} - -fn get_rustpkg_lib_path() -> Result<Path, ~str> { - do get_rustpkg_root().chain |p| { - result::Ok(p.push(libdir())) + let h = os::homedir(); + for h in h.iter() { + if !env_rust_path.contains(&h.push(".rust")) { + push_if_exists(&mut env_rust_path, h); + } } + env_rust_path } -fn get_rustpkg_lib_path_nearest() -> Result<Path, ~str> { - do get_rustpkg_root_nearest().chain |p| { - result::Ok(p.push(libdir())) + +/// Adds p/.rust into vec, only if it exists +fn push_if_exists(vec: &mut ~[Path], p: &Path) { + let maybe_dir = p.push(".rust"); + if os::path_exists(&maybe_dir) { + vec.push(maybe_dir); } } // The name of the directory rustc expects libraries to be located. // On Unix should be "lib", on windows "bin" +#[cfg(stage0)] pub fn libdir() -> ~str { let libdir = env!("CFG_LIBDIR"); if libdir.is_empty() { @@ -193,3 +208,8 @@ pub fn libdir() -> ~str { } libdir.to_owned() } + +#[cfg(not(stage0))] +pub fn libdir() -> ~str { + (env!("CFG_LIBDIR")).to_owned() +} diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 9330cfc5c88..704a22ec979 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -18,12 +18,12 @@ use metadata::filesearch::FileSearch; use metadata::filesearch; use syntax::codemap::span; use syntax::diagnostic::span_handler; -use syntax::parse::token; use syntax::parse::token::ident_interner; use syntax::print::pprust; use syntax::{ast, attr}; use syntax::attr::AttrMetaMethods; +use std::c_str::ToCStr; use std::cast; use std::io; use std::num; @@ -46,7 +46,7 @@ pub struct Context { diag: @span_handler, filesearch: @FileSearch, span: span, - ident: ast::ident, + ident: @str, metas: ~[@ast::MetaItem], hash: @str, os: os, @@ -60,7 +60,7 @@ pub fn load_library_crate(cx: &Context) -> (~str, @~[u8]) { None => { cx.diag.span_fatal(cx.span, fmt!("can't find crate for `%s`", - token::ident_to_str(&cx.ident))); + cx.ident)); } } } @@ -89,37 +89,38 @@ fn find_library_crate_aux( filesearch: @filesearch::FileSearch ) -> Option<(~str, @~[u8])> { let crate_name = crate_name_from_metas(cx.metas); - let prefix = prefix + crate_name + "-"; - + // want: crate_name.dir_part() + prefix + crate_name.file_part + "-" + let prefix = fmt!("%s%s-", prefix, crate_name); let mut matches = ~[]; filesearch::search(filesearch, |path| -> Option<()> { - debug!("inspecting file %s", path.to_str()); - match path.filename() { - Some(ref f) if f.starts_with(prefix) && f.ends_with(suffix) => { - debug!("%s is a candidate", path.to_str()); - match get_metadata_section(cx.os, path) { - Some(cvec) => - if !crate_matches(cvec, cx.metas, cx.hash) { - debug!("skipping %s, metadata doesn't match", - path.to_str()); - None - } else { - debug!("found %s with matching metadata", path.to_str()); - matches.push((path.to_str(), cvec)); - None - }, - _ => { - debug!("could not load metadata for %s", path.to_str()); - None - } - } - } - _ => { - debug!("skipping %s, doesn't look like %s*%s", path.to_str(), - prefix, suffix); - None - } - }}); + let path_str = path.filename(); + match path_str { + None => None, + Some(path_str) => + if path_str.starts_with(prefix) && path_str.ends_with(suffix) { + debug!("%s is a candidate", path.to_str()); + match get_metadata_section(cx.os, path) { + Some(cvec) => + if !crate_matches(cvec, cx.metas, cx.hash) { + debug!("skipping %s, metadata doesn't match", + path.to_str()); + None + } else { + debug!("found %s with matching metadata", path.to_str()); + matches.push((path.to_str(), cvec)); + None + }, + _ => { + debug!("could not load metadata for %s", path.to_str()); + None + } + } + } + else { + None + } + } + }); match matches.len() { 0 => None, @@ -137,8 +138,8 @@ fn find_library_crate_aux( } cx.diag.handler().abort_if_errors(); None - } } + } } pub fn crate_name_from_metas(metas: &[@ast::MetaItem]) -> @str { @@ -151,6 +152,16 @@ pub fn crate_name_from_metas(metas: &[@ast::MetaItem]) -> @str { fail!("expected to find the crate name") } +pub fn package_id_from_metas(metas: &[@ast::MetaItem]) -> Option<@str> { + for m in metas.iter() { + match m.name_str_pair() { + Some((name, s)) if "package_id" == name => { return Some(s); } + _ => {} + } + } + None +} + pub fn note_linkage_attrs(intr: @ident_interner, diag: @span_handler, attrs: ~[ast::Attribute]) { @@ -175,6 +186,8 @@ fn crate_matches(crate_data: @~[u8], pub fn metadata_matches(extern_metas: &[@ast::MetaItem], local_metas: &[@ast::MetaItem]) -> bool { +// extern_metas: metas we read from the crate +// local_metas: metas we're looking for debug!("matching %u metadata requirements against %u items", local_metas.len(), extern_metas.len()); @@ -186,7 +199,7 @@ pub fn metadata_matches(extern_metas: &[@ast::MetaItem], fn get_metadata_section(os: os, filename: &Path) -> Option<@~[u8]> { unsafe { - let mb = do filename.to_str().as_c_str |buf| { + let mb = do filename.to_c_str().with_ref |buf| { llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf) }; if mb as int == 0 { return option::None::<@~[u8]>; } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index b909f70440a..8a7894efb91 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1204,7 +1204,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, } c::tag_table_capture_map => { let cvars = - at_vec::to_managed_consume( + at_vec::to_managed_move( val_dsr.read_to_vec( |val_dsr| val_dsr.read_capture_var(xcx))); dcx.maps.capture_map.insert(id, cvars); diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index c3bb2000447..88e168db558 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -159,10 +159,10 @@ impl<'self> CheckLoanCtxt<'self> { true }; - for i in range(0u, new_loan_indices.len()) { - let old_loan = &self.all_loans[new_loan_indices[i]]; - for j in range(i+1, new_loan_indices.len()) { - let new_loan = &self.all_loans[new_loan_indices[j]]; + for (i, &x) in new_loan_indices.iter().enumerate() { + let old_loan = &self.all_loans[x]; + for &y in new_loan_indices.slice_from(i+1).iter() { + let new_loan = &self.all_loans[y]; self.report_error_if_loans_conflict(old_loan, new_loan); } } diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 767c2b4ee2e..282292a2ac0 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -112,23 +112,23 @@ impl CFGBuilder { ast::pat_enum(_, Some(ref subpats)) | ast::pat_tup(ref subpats) => { let pats_exit = - self.pats_all(subpats.iter().transform(|p| *p), pred); + self.pats_all(subpats.iter().map(|p| *p), pred); self.add_node(pat.id, [pats_exit]) } ast::pat_struct(_, ref subpats, _) => { let pats_exit = - self.pats_all(subpats.iter().transform(|f| f.pat), pred); + self.pats_all(subpats.iter().map(|f| f.pat), pred); self.add_node(pat.id, [pats_exit]) } ast::pat_vec(ref pre, ref vec, ref post) => { let pre_exit = - self.pats_all(pre.iter().transform(|p| *p), pred); + self.pats_all(pre.iter().map(|p| *p), pred); let vec_exit = - self.pats_all(vec.iter().transform(|p| *p), pre_exit); + self.pats_all(vec.iter().map(|p| *p), pre_exit); let post_exit = - self.pats_all(post.iter().transform(|p| *p), vec_exit); + self.pats_all(post.iter().map(|p| *p), vec_exit); self.add_node(pat.id, [post_exit]) } } @@ -376,7 +376,7 @@ impl CFGBuilder { ast::expr_struct(_, ref fields, base) => { let base_exit = self.opt_expr(base, pred); let field_exprs: ~[@ast::expr] = - fields.iter().transform(|f| f.expr).collect(); + fields.iter().map(|f| f.expr).collect(); self.straightline(expr, base_exit, field_exprs) } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 1b420b9c06a..37f45142a11 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -169,7 +169,7 @@ pub fn check_exhaustive(cx: &MatchCheckCtxt, sp: span, pats: ~[@pat]) { }; let variants = ty::enum_variants(cx.tcx, id); - match variants.iter().find_(|v| v.id == vid) { + match variants.iter().find(|v| v.id == vid) { Some(v) => Some(cx.tcx.sess.str_of(v.name)), None => { fail!("check_exhaustive: bad variant in ctor") @@ -222,7 +222,7 @@ pub enum ctor { pub fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@pat]) -> useful { if m.len() == 0u { return useful_; } if m[0].len() == 0u { return not_useful; } - let real_pat = match m.iter().find_(|r| r[0].id != 0) { + let real_pat = match m.iter().find(|r| r[0].id != 0) { Some(r) => r[0], None => v[0] }; let left_ty = if real_pat.id == 0 { ty::mk_nil() } @@ -255,6 +255,9 @@ pub fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@pat]) -> useful { } not_useful } + ty::ty_evec(_, ty::vstore_fixed(n)) => { + is_useful_specialized(cx, m, v, vec(n), n, left_ty) + } ty::ty_unboxed_vec(*) | ty::ty_evec(*) => { let max_len = do m.rev_iter().fold(0) |max_len, r| { match r[0].node { @@ -409,6 +412,29 @@ pub fn missing_ctor(cx: &MatchCheckCtxt, else if true_found { Some(val(const_bool(false))) } else { Some(val(const_bool(true))) } } + ty::ty_evec(_, ty::vstore_fixed(n)) => { + let mut missing = true; + let mut wrong = false; + for r in m.iter() { + match r[0].node { + pat_vec(ref before, ref slice, ref after) => { + let count = before.len() + after.len(); + if (count < n && slice.is_none()) || count > n { + wrong = true; + } + if count == n || (count < n && slice.is_some()) { + missing = false; + } + } + _ => {} + } + } + match (wrong, missing) { + (true, _) => Some(vec(n)), // should be compile-time error + (_, true) => Some(vec(n)), + _ => None + } + } ty::ty_unboxed_vec(*) | ty::ty_evec(*) => { // Find the lengths and slices of all vector patterns. @@ -470,7 +496,7 @@ pub fn ctor_arity(cx: &MatchCheckCtxt, ctor: &ctor, ty: ty::t) -> uint { ty::ty_enum(eid, _) => { let id = match *ctor { variant(id) => id, _ => fail!("impossible case") }; - match ty::enum_variants(cx.tcx, eid).iter().find_(|v| v.id == id ) { + match ty::enum_variants(cx.tcx, eid).iter().find(|v| v.id == id ) { Some(v) => v.args.len(), None => fail!("impossible case") } @@ -627,7 +653,7 @@ pub fn specialize(cx: &MatchCheckCtxt, if variant(variant_id) == *ctor_id { // FIXME #4731: Is this right? --pcw let args = flds.map(|ty_field| { - match flds.iter().find_(|f| + match flds.iter().find(|f| f.ident == ty_field.ident) { Some(f) => f.pat, _ => wild() @@ -657,8 +683,8 @@ pub fn specialize(cx: &MatchCheckCtxt, ty_to_str(cx.tcx, left_ty))); } } - let args = class_fields.iter().transform(|class_field| { - match flds.iter().find_(|f| + let args = class_fields.iter().map(|class_field| { + match flds.iter().find(|f| f.ident == class_field.ident) { Some(f) => f.pat, _ => wild() diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 3b56764f2fc..2de94cdbf4c 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -102,7 +102,7 @@ pub fn classify(e: &expr, ast::expr_tup(ref es) | ast::expr_vec(ref es, ast::m_imm) => { - join_all(es.iter().transform(|e| classify(*e, tcx))) + join_all(es.iter().map(|e| classify(*e, tcx))) } ast::expr_vstore(e, vstore) => { @@ -116,7 +116,7 @@ pub fn classify(e: &expr, } ast::expr_struct(_, ref fs, None) => { - let cs = do fs.iter().transform |f| { + let cs = do fs.iter().map |f| { classify(f.expr, tcx) }; join_all(cs) diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 008add975d4..46b6d2214ae 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -983,10 +983,10 @@ fn bitwise(out_vec: &mut [uint], op: &fn(uint, uint) -> uint) -> bool { assert_eq!(out_vec.len(), in_vec.len()); let mut changed = false; - for i in range(0u, out_vec.len()) { - let old_val = out_vec[i]; - let new_val = op(old_val, in_vec[i]); - out_vec[i] = new_val; + for (out_elt, in_elt) in out_vec.mut_iter().zip(in_vec.iter()) { + let old_val = *out_elt; + let new_val = op(old_val, *in_elt); + *out_elt = new_val; changed |= (old_val != new_val); } changed diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index 28d24b169ca..46394454d00 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc/middle/graph.rs @@ -187,12 +187,12 @@ impl<N,E> Graph<N,E> { pub fn each_node(&self, f: &fn(NodeIndex, &Node<N>) -> bool) -> bool { //! Iterates over all edges defined in the graph. - range(0u, self.nodes.len()).advance(|i| f(NodeIndex(i), &self.nodes[i])) + self.nodes.iter().enumerate().advance(|(i, node)| f(NodeIndex(i), node)) } pub fn each_edge(&self, f: &fn(EdgeIndex, &Edge<E>) -> bool) -> bool { - //! Iterates over all edges defined in the graph. - range(0u, self.nodes.len()).advance(|i| f(EdgeIndex(i), &self.edges[i])) + //! Iterates over all edges defined in the graph + self.edges.iter().enumerate().advance(|(i, edge)| f(EdgeIndex(i), edge)) } pub fn each_outgoing_edge(&self, diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index bbcb40df775..3a15cbe0f52 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -994,7 +994,7 @@ fn lint_session(cx: @mut Context) -> @visit::Visitor<()> { match cx.tcx.sess.lints.pop(&id) { None => {}, Some(l) => { - for (lint, span, msg) in l.consume_iter() { + for (lint, span, msg) in l.move_iter() { cx.span_lint(lint, span, msg) } } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 9ffeb99ac35..a4b88870b97 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -403,6 +403,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, // Ditto match ty::get(ty::type_autoderef(tcx, ty::expr_ty(tcx, base))).sty { + ty_enum(id, _) | ty_struct(id, _) if id.crate != LOCAL_CRATE || !privileged_items.iter().any(|x| x == &(id.node)) => { diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index da0ba1558c9..4d95909404e 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.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. // @@ -13,7 +13,7 @@ use driver::session::Session; use metadata::csearch::{each_path, get_trait_method_def_ids}; use metadata::csearch::get_method_name_and_explicit_self; use metadata::csearch::get_static_methods_if_impl; -use metadata::csearch::get_type_name_if_impl; +use metadata::csearch::{get_type_name_if_impl, get_struct_fields}; use metadata::cstore::find_extern_mod_stmt_cnum; use metadata::decoder::{def_like, dl_def, dl_field, dl_impl}; use middle::lang_items::LanguageItems; @@ -1487,9 +1487,10 @@ impl Resolver { } } - view_item_extern_mod(name, _, node_id) => { + view_item_extern_mod(name, _, _, node_id) => { + // n.b. we don't need to look at the path option here, because cstore already did match find_extern_mod_stmt_cnum(self.session.cstore, - node_id) { + node_id) { Some(crate_id) => { let def_id = def_id { crate: crate_id, node: 0 }; let parent_link = ModuleParentLink @@ -1700,9 +1701,12 @@ impl Resolver { } def_struct(def_id) => { debug!("(building reduced graph for external \ - crate) building type %s", + crate) building type and value for %s", final_ident); child_name_bindings.define_type(privacy, def, dummy_sp()); + if get_struct_fields(self.session.cstore, def_id).len() == 0 { + child_name_bindings.define_value(privacy, def, dummy_sp()); + } self.structs.insert(def_id); } def_method(*) => { @@ -4991,7 +4995,9 @@ impl Resolver { if self.structs.contains(&class_id) => { self.record_def(expr.id, definition); } - _ => { + result => { + debug!("(resolving expression) didn't find struct \ + def: %?", result); self.session.span_err( path.span, fmt!("`%s` does not name a structure", @@ -5360,7 +5366,7 @@ impl Resolver { if idents.len() == 0 { return ~"???"; } - return self.idents_to_str(idents.consume_rev_iter().collect::<~[ast::ident]>()); + return self.idents_to_str(idents.move_rev_iter().collect::<~[ast::ident]>()); } pub fn dump_module(@mut self, module_: @mut Module) { diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 9a0dc5f036c..c98d859337c 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -145,6 +145,51 @@ * - `store_non_ref_bindings()` * - `insert_lllocals()` * + * + * ## Notes on vector pattern matching. + * + * Vector pattern matching is surprisingly tricky. The problem is that + * the structure of the vector isn't fully known, and slice matches + * can be done on subparts of it. + * + * The way that vector pattern matches are dealt with, then, is as + * follows. First, we make the actual condition associated with a + * vector pattern simply a vector length comparison. So the pattern + * [1, .. x] gets the condition "vec len >= 1", and the pattern + * [.. x] gets the condition "vec len >= 0". The problem here is that + * having the condition "vec len >= 1" hold clearly does not mean that + * only a pattern that has exactly that condition will match. This + * means that it may well be the case that a condition holds, but none + * of the patterns matching that condition match; to deal with this, + * when doing vector length matches, we have match failures proceed to + * the next condition to check. + * + * There are a couple more subtleties to deal with. While the "actual" + * condition associated with vector length tests is simply a test on + * the vector length, the actual vec_len Opt entry contains more + * information used to restrict which matches are associated with it. + * So that all matches in a submatch are matching against the same + * values from inside the vector, they are split up by how many + * elements they match at the front and at the back of the vector. In + * order to make sure that arms are properly checked in order, even + * with the overmatching conditions, each vec_len Opt entry is + * associated with a range of matches. + * Consider the following: + * + * match &[1, 2, 3] { + * [1, 1, .. _] => 0, + * [1, 2, 2, .. _] => 1, + * [1, 2, 3, .. _] => 2, + * [1, 2, .. _] => 3, + * _ => 4 + * } + * The proper arm to match is arm 2, but arms 0 and 3 both have the + * condition "len >= 2". If arm 3 was lumped in with arm 0, then the + * wrong branch would be taken. Instead, vec_len Opts are associated + * with a contiguous range of matches that have the same "shape". + * This is sort of ugly and requires a bunch of special handling of + * vec_len options. + * */ @@ -183,23 +228,28 @@ use syntax::codemap::{span, dummy_sp}; // An option identifying a literal: either a unit-like struct or an // expression. -pub enum Lit { +enum Lit { UnitLikeStructLit(ast::NodeId), // the node ID of the pattern ExprLit(@ast::expr), ConstLit(ast::def_id), // the def ID of the constant } +#[deriving(Eq)] +pub enum VecLenOpt { + vec_len_eq, + vec_len_ge(/* length of prefix */uint) +} + // An option identifying a branch (either a literal, a enum variant or a // range) -pub enum Opt { +enum Opt { lit(Lit), var(/* disr val */ uint, @adt::Repr), range(@ast::expr, @ast::expr), - vec_len_eq(uint), - vec_len_ge(uint, /* slice */uint) + vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint)) } -pub fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool { +fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool { match (a, b) { (&lit(a), &lit(b)) => { match (a, b) { @@ -247,9 +297,9 @@ pub fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool { } } (&var(a, _), &var(b, _)) => a == b, - (&vec_len_eq(a), &vec_len_eq(b)) => a == b, - (&vec_len_ge(a, _), &vec_len_ge(b, _)) => a == b, - _ => false + (&vec_len(a1, a2, _), &vec_len(b1, b2, _)) => + a1 == b1 && a2 == b2, + _ => false } } @@ -258,7 +308,7 @@ pub enum opt_result { lower_bound(Result), range_result(Result, Result), } -pub fn trans_opt(bcx: @mut Block, o: &Opt) -> opt_result { +fn trans_opt(bcx: @mut Block, o: &Opt) -> opt_result { let _icx = push_ctxt("match::trans_opt"); let ccx = bcx.ccx(); let bcx = bcx; @@ -283,16 +333,16 @@ pub fn trans_opt(bcx: @mut Block, o: &Opt) -> opt_result { return range_result(rslt(bcx, consts::const_expr(ccx, l1)), rslt(bcx, consts::const_expr(ccx, l2))); } - vec_len_eq(n) => { + vec_len(n, vec_len_eq, _) => { return single_result(rslt(bcx, C_int(ccx, n as int))); } - vec_len_ge(n, _) => { + vec_len(n, vec_len_ge(_), _) => { return lower_bound(rslt(bcx, C_int(ccx, n as int))); } } } -pub fn variant_opt(bcx: @mut Block, pat_id: ast::NodeId) +fn variant_opt(bcx: @mut Block, pat_id: ast::NodeId) -> Opt { let ccx = bcx.ccx(); match ccx.tcx.def_map.get_copy(&pat_id) { @@ -317,7 +367,7 @@ pub fn variant_opt(bcx: @mut Block, pat_id: ast::NodeId) } #[deriving(Clone)] -pub enum TransBindingMode { +enum TransBindingMode { TrByValue(/*llbinding:*/ ValueRef), TrByRef, } @@ -331,24 +381,24 @@ pub enum TransBindingMode { * - `id` is the node id of the binding * - `ty` is the Rust type of the binding */ #[deriving(Clone)] -pub struct BindingInfo { +struct BindingInfo { llmatch: ValueRef, trmode: TransBindingMode, id: ast::NodeId, ty: ty::t, } -pub type BindingsMap = HashMap<ident, BindingInfo>; +type BindingsMap = HashMap<ident, BindingInfo>; #[deriving(Clone)] -pub struct ArmData<'self> { +struct ArmData<'self> { bodycx: @mut Block, arm: &'self ast::arm, bindings_map: @BindingsMap } #[deriving(Clone)] -pub struct Match<'self> { +struct Match<'self> { pats: ~[@ast::pat], data: ArmData<'self> } @@ -364,7 +414,7 @@ impl<'self> Repr for Match<'self> { } } -pub fn has_nested_bindings(m: &[Match], col: uint) -> bool { +fn has_nested_bindings(m: &[Match], col: uint) -> bool { for br in m.iter() { match br.pats[col].node { ast::pat_ident(_, _, Some(_)) => return true, @@ -374,7 +424,7 @@ pub fn has_nested_bindings(m: &[Match], col: uint) -> bool { return false; } -pub fn expand_nested_bindings<'r>(bcx: @mut Block, +fn expand_nested_bindings<'r>(bcx: @mut Block, m: &[Match<'r>], col: uint, val: ValueRef) @@ -409,7 +459,7 @@ pub fn expand_nested_bindings<'r>(bcx: @mut Block, } } -pub fn assert_is_binding_or_wild(bcx: @mut Block, p: @ast::pat) { +fn assert_is_binding_or_wild(bcx: @mut Block, p: @ast::pat) { if !pat_is_binding_or_wild(bcx.tcx().def_map, p) { bcx.sess().span_bug( p.span, @@ -418,9 +468,9 @@ pub fn assert_is_binding_or_wild(bcx: @mut Block, p: @ast::pat) { } } -pub type enter_pat<'self> = &'self fn(@ast::pat) -> Option<~[@ast::pat]>; +type enter_pat<'self> = &'self fn(@ast::pat) -> Option<~[@ast::pat]>; -pub fn enter_match<'r>(bcx: @mut Block, +fn enter_match<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -470,11 +520,12 @@ pub fn enter_match<'r>(bcx: @mut Block, return result; } -pub fn enter_default<'r>(bcx: @mut Block, - dm: DefMap, - m: &[Match<'r>], - col: uint, - val: ValueRef) +fn enter_default<'r>(bcx: @mut Block, + dm: DefMap, + m: &[Match<'r>], + col: uint, + val: ValueRef, + chk: Option<mk_fail>) -> ~[Match<'r>] { debug!("enter_default(bcx=%s, m=%s, col=%u, val=%s)", bcx.to_str(), @@ -483,13 +534,36 @@ pub fn enter_default<'r>(bcx: @mut Block, bcx.val_to_str(val)); let _indenter = indenter(); - do enter_match(bcx, dm, m, col, val) |p| { + // Collect all of the matches that can match against anything. + let matches = do enter_match(bcx, dm, m, col, val) |p| { match p.node { - ast::pat_wild | ast::pat_tup(_) | ast::pat_struct(*) => Some(~[]), + ast::pat_wild | ast::pat_tup(_) => Some(~[]), ast::pat_ident(_, _, None) if pat_is_binding(dm, p) => Some(~[]), _ => None } - } + }; + + // Ok, now, this is pretty subtle. A "default" match is a match + // that needs to be considered if none of the actual checks on the + // value being considered succeed. The subtlety lies in that sometimes + // identifier/wildcard matches are *not* default matches. Consider: + // "match x { _ if something => foo, true => bar, false => baz }". + // There is a wildcard match, but it is *not* a default case. The boolean + // case on the value being considered is exhaustive. If the case is + // exhaustive, then there are no defaults. + // + // We detect whether the case is exhaustive in the following + // somewhat kludgy way: if the last wildcard/binding match has a + // guard, then by non-redundancy, we know that there aren't any + // non guarded matches, and thus by exhaustiveness, we know that + // we don't need any default cases. If the check *isn't* nonexhaustive + // (because chk is Some), then we need the defaults anyways. + let is_exhaustive = match matches.last_opt() { + Some(m) if m.data.arm.guard.is_some() && chk.is_none() => true, + _ => false + }; + + if is_exhaustive { ~[] } else { matches } } // <pcwalton> nmatsakis: what does enter_opt do? @@ -516,24 +590,26 @@ pub fn enter_default<'r>(bcx: @mut Block, // <nmatsakis> so all patterns must either be records (resp. tuples) or // wildcards -pub fn enter_opt<'r>(bcx: @mut Block, +fn enter_opt<'r>(bcx: @mut Block, m: &[Match<'r>], opt: &Opt, col: uint, variant_size: uint, val: ValueRef) -> ~[Match<'r>] { - debug!("enter_opt(bcx=%s, m=%s, col=%u, val=%s)", + debug!("enter_opt(bcx=%s, m=%s, opt=%?, col=%u, val=%s)", bcx.to_str(), m.repr(bcx.tcx()), + *opt, col, bcx.val_to_str(val)); let _indenter = indenter(); let tcx = bcx.tcx(); let dummy = @ast::pat {id: 0, node: ast::pat_wild, span: dummy_sp()}; + let mut i = 0; do enter_match(bcx, tcx.def_map, m, col, val) |p| { - match p.node { + let answer = match p.node { ast::pat_enum(*) | ast::pat_ident(_, _, None) if pat_is_const(tcx.def_map, p) => { let const_def = tcx.def_map.get_copy(&p.id); @@ -588,7 +664,7 @@ pub fn enter_opt<'r>(bcx: @mut Block, let mut reordered_patterns = ~[]; let r = ty::lookup_struct_fields(tcx, struct_id); for field in r.iter() { - match field_pats.iter().find_(|p| p.ident == field.ident) { + match field_pats.iter().find(|p| p.ident == field.ident) { None => reordered_patterns.push(dummy), Some(fp) => reordered_patterns.push(fp.pat) } @@ -599,36 +675,57 @@ pub fn enter_opt<'r>(bcx: @mut Block, } } ast::pat_vec(ref before, slice, ref after) => { + let (lo, hi) = match *opt { + vec_len(_, _, (lo, hi)) => (lo, hi), + _ => tcx.sess.span_bug(p.span, + "vec pattern but not vec opt") + }; + match slice { - Some(slice) => { + Some(slice) if i >= lo && i <= hi => { let n = before.len() + after.len(); - let i = before.len(); - if opt_eq(tcx, &vec_len_ge(n, i), opt) { + let this_opt = vec_len(n, vec_len_ge(before.len()), + (lo, hi)); + if opt_eq(tcx, &this_opt, opt) { Some(vec::append_one((*before).clone(), slice) + *after) } else { None } } - None => { + None if i >= lo && i <= hi => { let n = before.len(); - if opt_eq(tcx, &vec_len_eq(n), opt) { + if opt_eq(tcx, &vec_len(n, vec_len_eq, (lo,hi)), opt) { Some((*before).clone()) } else { None } } + _ => None } } _ => { assert_is_binding_or_wild(bcx, p); - Some(vec::from_elem(variant_size, dummy)) + // In most cases, a binding/wildcard match be + // considered to match against any Opt. However, when + // doing vector pattern matching, submatches are + // considered even if the eventual match might be from + // a different submatch. Thus, when a submatch fails + // when doing a vector match, we proceed to the next + // submatch. Thus, including a default match would + // cause the default match to fire spuriously. + match *opt { + vec_len(*) => None, + _ => Some(vec::from_elem(variant_size, dummy)) + } } - } + }; + i += 1; + answer } } -pub fn enter_rec_or_struct<'r>(bcx: @mut Block, +fn enter_rec_or_struct<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -648,7 +745,7 @@ pub fn enter_rec_or_struct<'r>(bcx: @mut Block, ast::pat_struct(_, ref fpats, _) => { let mut pats = ~[]; for fname in fields.iter() { - match fpats.iter().find_(|p| p.ident == *fname) { + match fpats.iter().find(|p| p.ident == *fname) { None => pats.push(dummy), Some(pat) => pats.push(pat.pat) } @@ -663,7 +760,7 @@ pub fn enter_rec_or_struct<'r>(bcx: @mut Block, } } -pub fn enter_tup<'r>(bcx: @mut Block, +fn enter_tup<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -689,7 +786,7 @@ pub fn enter_tup<'r>(bcx: @mut Block, } } -pub fn enter_tuple_struct<'r>(bcx: @mut Block, +fn enter_tuple_struct<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -715,7 +812,7 @@ pub fn enter_tuple_struct<'r>(bcx: @mut Block, } } -pub fn enter_box<'r>(bcx: @mut Block, +fn enter_box<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -742,7 +839,7 @@ pub fn enter_box<'r>(bcx: @mut Block, } } -pub fn enter_uniq<'r>(bcx: @mut Block, +fn enter_uniq<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -769,7 +866,7 @@ pub fn enter_uniq<'r>(bcx: @mut Block, } } -pub fn enter_region<'r>(bcx: @mut Block, +fn enter_region<'r>(bcx: @mut Block, dm: DefMap, m: &[Match<'r>], col: uint, @@ -799,15 +896,31 @@ pub fn enter_region<'r>(bcx: @mut Block, // Returns the options in one column of matches. An option is something that // needs to be conditionally matched at runtime; for example, the discriminant // on a set of enum variants or a literal. -pub fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] { +fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] { let ccx = bcx.ccx(); fn add_to_set(tcx: ty::ctxt, set: &mut ~[Opt], val: Opt) { if set.iter().any(|l| opt_eq(tcx, l, &val)) {return;} set.push(val); } + // Vector comparisions are special in that since the actual + // conditions over-match, we need to be careful about them. This + // means that in order to properly handle things in order, we need + // to not always merge conditions. + fn add_veclen_to_set(set: &mut ~[Opt], i: uint, + len: uint, vlo: VecLenOpt) { + match set.last_opt() { + // If the last condition in the list matches the one we want + // to add, then extend its range. Otherwise, make a new + // vec_len with a range just covering the new entry. + Some(&vec_len(len2, vlo2, (start, end))) + if len == len2 && vlo == vlo2 => + set[set.len() - 1] = vec_len(len, vlo, (start, end+1)), + _ => set.push(vec_len(len, vlo, (i, i))) + } + } let mut found = ~[]; - for br in m.iter() { + for (i, br) in m.iter().enumerate() { let cur = br.pats[col]; match cur.node { ast::pat_lit(l) => { @@ -852,12 +965,12 @@ pub fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] { add_to_set(ccx.tcx, &mut found, range(l1, l2)); } ast::pat_vec(ref before, slice, ref after) => { - let opt = match slice { - None => vec_len_eq(before.len()), - Some(_) => vec_len_ge(before.len() + after.len(), - before.len()) + let (len, vec_opt) = match slice { + None => (before.len(), vec_len_eq), + Some(_) => (before.len() + after.len(), + vec_len_ge(before.len())) }; - add_to_set(ccx.tcx, &mut found, opt); + add_veclen_to_set(&mut found, i, len, vec_opt); } _ => {} } @@ -865,12 +978,12 @@ pub fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] { return found; } -pub struct ExtractedBlock { +struct ExtractedBlock { vals: ~[ValueRef], bcx: @mut Block } -pub fn extract_variant_args(bcx: @mut Block, +fn extract_variant_args(bcx: @mut Block, repr: &adt::Repr, disr_val: uint, val: ValueRef) @@ -893,7 +1006,7 @@ fn match_datum(bcx: @mut Block, val: ValueRef, pat_id: ast::NodeId) -> Datum { } -pub fn extract_vec_elems(bcx: @mut Block, +fn extract_vec_elems(bcx: @mut Block, pat_span: span, pat_id: ast::NodeId, elem_count: uint, @@ -947,24 +1060,37 @@ pub fn extract_vec_elems(bcx: @mut Block, ExtractedBlock { vals: elems, bcx: bcx } } -// NB: This function does not collect fields from struct-like enum variants. -pub fn collect_record_or_struct_fields(bcx: @mut Block, +/// Checks every pattern in `m` at `col` column. +/// If there are a struct pattern among them function +/// returns list of all fields that are matched in these patterns. +/// Function returns None if there is no struct pattern. +/// Function doesn't collect fields from struct-like enum variants. +/// Function can return empty list if there is only wildcard struct pattern. +fn collect_record_or_struct_fields(bcx: @mut Block, m: &[Match], col: uint) - -> ~[ast::ident] { + -> Option<~[ast::ident]> { let mut fields: ~[ast::ident] = ~[]; + let mut found = false; for br in m.iter() { match br.pats[col].node { ast::pat_struct(_, ref fs, _) => { match ty::get(node_id_type(bcx, br.pats[col].id)).sty { - ty::ty_struct(*) => extend(&mut fields, *fs), + ty::ty_struct(*) => { + extend(&mut fields, *fs); + found = true; + } _ => () } } _ => () } } - return fields; + if found { + return Some(fields); + } else { + return None; + } fn extend(idents: &mut ~[ast::ident], field_pats: &[ast::field_pat]) { for field_pat in field_pats.iter() { @@ -976,7 +1102,7 @@ pub fn collect_record_or_struct_fields(bcx: @mut Block, } } -pub fn pats_require_rooting(bcx: @mut Block, +fn pats_require_rooting(bcx: @mut Block, m: &[Match], col: uint) -> bool { @@ -987,7 +1113,7 @@ pub fn pats_require_rooting(bcx: @mut Block, } } -pub fn root_pats_as_necessary(mut bcx: @mut Block, +fn root_pats_as_necessary(mut bcx: @mut Block, m: &[Match], col: uint, val: ValueRef) @@ -1018,23 +1144,23 @@ macro_rules! any_pat ( ) ) -pub fn any_box_pat(m: &[Match], col: uint) -> bool { +fn any_box_pat(m: &[Match], col: uint) -> bool { any_pat!(m, ast::pat_box(_)) } -pub fn any_uniq_pat(m: &[Match], col: uint) -> bool { +fn any_uniq_pat(m: &[Match], col: uint) -> bool { any_pat!(m, ast::pat_uniq(_)) } -pub fn any_region_pat(m: &[Match], col: uint) -> bool { +fn any_region_pat(m: &[Match], col: uint) -> bool { any_pat!(m, ast::pat_region(_)) } -pub fn any_tup_pat(m: &[Match], col: uint) -> bool { +fn any_tup_pat(m: &[Match], col: uint) -> bool { any_pat!(m, ast::pat_tup(_)) } -pub fn any_tuple_struct_pat(bcx: @mut Block, m: &[Match], col: uint) -> bool { +fn any_tuple_struct_pat(bcx: @mut Block, m: &[Match], col: uint) -> bool { do m.iter().any |br| { let pat = br.pats[col]; match pat.node { @@ -1050,9 +1176,9 @@ pub fn any_tuple_struct_pat(bcx: @mut Block, m: &[Match], col: uint) -> bool { } } -pub type mk_fail = @fn() -> BasicBlockRef; +type mk_fail = @fn() -> BasicBlockRef; -pub fn pick_col(m: &[Match]) -> uint { +fn pick_col(m: &[Match]) -> uint { fn score(p: &ast::pat) -> uint { match p.node { ast::pat_lit(_) | ast::pat_enum(_, _) | ast::pat_range(_, _) => 1u, @@ -1062,13 +1188,13 @@ pub fn pick_col(m: &[Match]) -> uint { } let mut scores = vec::from_elem(m[0].pats.len(), 0u); for br in m.iter() { - let mut i = 0u; - for p in br.pats.iter() { scores[i] += score(*p); i += 1u; } + for (i, p) in br.pats.iter().enumerate() { + scores[i] += score(*p); + } } let mut max_score = 0u; let mut best_col = 0u; - let mut i = 0u; - for score in scores.iter() { + for (i, score) in scores.iter().enumerate() { let score = *score; // Irrefutable columns always go first, they'd only be duplicated in @@ -1077,7 +1203,6 @@ pub fn pick_col(m: &[Match]) -> uint { // If no irrefutable ones are found, we pick the one with the biggest // branching factor. if score > max_score { max_score = score; best_col = i; } - i += 1u; } return best_col; } @@ -1088,7 +1213,7 @@ pub enum branch_kind { no_branch, single, switch, compare, compare_vec_len, } // Compiles a comparison between two things. // // NB: This must produce an i1, not a Rust bool (i8). -pub fn compare_values(cx: @mut Block, +fn compare_values(cx: @mut Block, lhs: ValueRef, rhs: ValueRef, rhs_t: ty::t) @@ -1204,7 +1329,7 @@ fn insert_lllocals(bcx: @mut Block, return bcx; } -pub fn compile_guard(bcx: @mut Block, +fn compile_guard(bcx: @mut Block, guard_expr: @ast::expr, data: &ArmData, m: &[Match], @@ -1261,7 +1386,7 @@ pub fn compile_guard(bcx: @mut Block, } } -pub fn compile_submatch(bcx: @mut Block, +fn compile_submatch(bcx: @mut Block, m: &[Match], vals: &[ValueRef], chk: Option<mk_fail>) { @@ -1336,22 +1461,24 @@ fn compile_submatch_continue(mut bcx: @mut Block, // required to root any values. assert!(any_box_pat(m, col) || !pats_require_rooting(bcx, m, col)); - let rec_fields = collect_record_or_struct_fields(bcx, m, col); - if rec_fields.len() > 0 { - let pat_ty = node_id_type(bcx, pat_id); - let pat_repr = adt::represent_type(bcx.ccx(), pat_ty); - do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| { - let rec_vals = rec_fields.map(|field_name| { - let ix = ty::field_idx_strict(tcx, *field_name, field_tys); - adt::trans_field_ptr(bcx, pat_repr, val, discr, ix) - }); - compile_submatch( - bcx, - enter_rec_or_struct(bcx, dm, m, col, rec_fields, val), - vec::append(rec_vals, vals_left), - chk); + match collect_record_or_struct_fields(bcx, m, col) { + Some(ref rec_fields) => { + let pat_ty = node_id_type(bcx, pat_id); + let pat_repr = adt::represent_type(bcx.ccx(), pat_ty); + do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| { + let rec_vals = rec_fields.map(|field_name| { + let ix = ty::field_idx_strict(tcx, *field_name, field_tys); + adt::trans_field_ptr(bcx, pat_repr, val, discr, ix) + }); + compile_submatch( + bcx, + enter_rec_or_struct(bcx, dm, m, col, *rec_fields, val), + vec::append(rec_vals, vals_left), + chk); + } + return; } - return; + None => {} } if any_tup_pat(m, col) { @@ -1445,7 +1572,7 @@ fn compile_submatch_continue(mut bcx: @mut Block, test_val = Load(bcx, val); kind = compare; }, - vec_len_eq(*) | vec_len_ge(*) => { + vec_len(*) => { let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id)); let unboxed = load_if_immediate(bcx, val, vt.vec_ty); let (_, len) = tvec::get_base_and_len( @@ -1472,16 +1599,19 @@ fn compile_submatch_continue(mut bcx: @mut Block, C_int(ccx, 0) // Placeholder for when not using a switch }; - let defaults = enter_default(else_cx, dm, m, col, val); + let defaults = enter_default(else_cx, dm, m, col, val, chk); let exhaustive = chk.is_none() && defaults.len() == 0u; let len = opts.len(); - let mut i = 0u; // Compile subtrees for each option - for opt in opts.iter() { - i += 1u; + for (i, opt) in opts.iter().enumerate() { + // In some cases in vector pattern matching, we need to override + // the failure case so that instead of failing, it proceeds to + // try more matching. branch_chk, then, is the proper failure case + // for the current conditional branch. + let mut branch_chk = chk; let mut opt_cx = else_cx; - if !exhaustive || i < len { + if !exhaustive || i+1 < len { opt_cx = sub_block(bcx, "match_case"); match kind { single => Br(bcx, opt_cx.llbb), @@ -1571,6 +1701,10 @@ fn compile_submatch_continue(mut bcx: @mut Block, } }; bcx = sub_block(after_cx, "compare_vec_len_next"); + + // If none of these subcases match, move on to the + // next condition. + branch_chk = Some::<mk_fail>(|| bcx.llbb); CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb); } _ => () @@ -1589,17 +1723,13 @@ fn compile_submatch_continue(mut bcx: @mut Block, unpacked = argvals; opt_cx = new_bcx; } - vec_len_eq(n) | vec_len_ge(n, _) => { - let n = match *opt { - vec_len_ge(*) => n + 1u, - _ => n - }; - let slice = match *opt { - vec_len_ge(_, i) => Some(i), - _ => None + vec_len(n, vt, _) => { + let (n, slice) = match vt { + vec_len_ge(i) => (n + 1u, Some(i)), + vec_len_eq => (n, None) }; - let args = extract_vec_elems(opt_cx, pat_span, pat_id, n, slice, - val, test_val); + let args = extract_vec_elems(opt_cx, pat_span, pat_id, n, + slice, val, test_val); size = args.vals.len(); unpacked = args.vals.clone(); opt_cx = args.bcx; @@ -1608,7 +1738,7 @@ fn compile_submatch_continue(mut bcx: @mut Block, } let opt_ms = enter_opt(opt_cx, m, opt, col, size, val); let opt_vals = vec::append(unpacked, vals_left); - compile_submatch(opt_cx, opt_ms, opt_vals, chk); + compile_submatch(opt_cx, opt_ms, opt_vals, branch_chk); } // Compile the fall-through case, if any @@ -1670,7 +1800,7 @@ fn create_bindings_map(bcx: @mut Block, pat: @ast::pat) -> BindingsMap { return bindings_map; } -pub fn trans_match_inner(scope_cx: @mut Block, +fn trans_match_inner(scope_cx: @mut Block, discr_expr: @ast::expr, arms: &[ast::arm], dest: Dest) -> @mut Block { @@ -1752,7 +1882,7 @@ pub fn trans_match_inner(scope_cx: @mut Block, } } -pub enum IrrefutablePatternBindingMode { +enum IrrefutablePatternBindingMode { // Stores the association between node ID and LLVM value in `lllocals`. BindLocal, // Stores the association between node ID and LLVM value in `llargs`. diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 2eb9841c6c7..a00cfa29123 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -508,7 +508,7 @@ pub fn trans_const(ccx: &mut CrateContext, r: &Repr, discr: uint, } General(ref cases) => { let case = &cases[discr]; - let max_sz = cases.iter().transform(|x| x.size).max().unwrap(); + let max_sz = cases.iter().map(|x| x.size).max().unwrap(); let discr_ty = C_uint(ccx, discr); let contents = build_const_struct(ccx, case, ~[discr_ty] + vals); @@ -519,7 +519,7 @@ pub fn trans_const(ccx: &mut CrateContext, r: &Repr, discr: uint, C_struct(build_const_struct(ccx, nonnull, vals)) } else { assert_eq!(vals.len(), 0); - let vals = do nonnull.fields.iter().enumerate().transform |(i, &ty)| { + let vals = do nonnull.fields.iter().enumerate().map |(i, &ty)| { let llty = type_of::sizing_type_of(ccx, ty); if i == ptrfield { C_null(llty) } else { C_undef(llty) } }.collect::<~[ValueRef]>(); diff --git a/src/librustc/middle/trans/asm.rs b/src/librustc/middle/trans/asm.rs index e54724b02ad..b6057199a28 100644 --- a/src/librustc/middle/trans/asm.rs +++ b/src/librustc/middle/trans/asm.rs @@ -12,6 +12,7 @@ # Translation of inline assembly. */ +use std::c_str::ToCStr; use lib; use middle::trans::build::*; @@ -119,8 +120,8 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block { ast::asm_intel => lib::llvm::AD_Intel }; - let r = do ia.asm.as_c_str |a| { - do constraints.as_c_str |c| { + let r = do ia.asm.to_c_str().with_ref |a| { + do constraints.to_c_str().with_ref |c| { InlineAsmCall(bcx, a, c, inputs, output, ia.volatile, ia.alignstack, dialect) } }; diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index dcaa141cbc2..762f6953bb2 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -59,12 +59,14 @@ use middle::trans::monomorphize; use middle::trans::tvec; use middle::trans::type_of; use middle::trans::type_of::*; +use middle::trans::value::Value; use middle::ty; use util::common::indenter; use util::ppaux::{Repr, ty_to_str}; use middle::trans::type_::Type; +use std::c_str::ToCStr; use std::hash; use std::hashmap::HashMap; use std::io; @@ -179,7 +181,7 @@ impl<'self> Drop for StatRecorder<'self> { } pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type) -> ValueRef { - let llfn: ValueRef = do name.as_c_str |buf| { + let llfn: ValueRef = do name.to_c_str().with_ref |buf| { unsafe { llvm::LLVMGetOrInsertFunction(llmod, buf, ty.to_ref()) } @@ -219,7 +221,7 @@ pub fn get_extern_const(externs: &mut ExternMap, llmod: ModuleRef, None => () } unsafe { - let c = do name.as_c_str |buf| { + let c = do name.to_c_str().with_ref |buf| { llvm::LLVMAddGlobal(llmod, ty.to_ref(), buf) }; externs.insert(name, c); @@ -521,7 +523,7 @@ pub fn get_res_dtor(ccx: @mut CrateContext, // Structural comparison: a rather involved form of glue. pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) { if cx.sess.opts.save_temps { - do s.as_c_str |buf| { + do s.to_c_str().with_ref |buf| { unsafe { llvm::LLVMSetValueName(v, buf) } @@ -1135,7 +1137,7 @@ pub fn new_block(cx: @mut FunctionContext, opt_node_info: Option<NodeInfo>) -> @mut Block { unsafe { - let llbb = do name.as_c_str |buf| { + let llbb = do name.to_c_str().with_ref |buf| { llvm::LLVMAppendBasicBlockInContext(cx.ccx.llcx, cx.llfn, buf) }; let bcx = @mut Block::new(llbb, @@ -1276,7 +1278,7 @@ pub fn cleanup_and_leave(bcx: @mut Block, let mut skip = 0; let mut dest = None; { - let r = (*inf).cleanup_paths.rev_iter().find_(|cp| cp.target == leave); + let r = (*inf).cleanup_paths.rev_iter().find(|cp| cp.target == leave); for cp in r.iter() { if cp.size == inf.cleanups.len() { Br(bcx, cp.dest); @@ -1552,7 +1554,7 @@ pub struct BasicBlocks { pub fn mk_staticallocas_basic_block(llfn: ValueRef) -> BasicBlockRef { unsafe { let cx = task_llcx(); - do "static_allocas".as_c_str | buf| { + do "static_allocas".to_c_str().with_ref | buf| { llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf) } } @@ -1561,7 +1563,7 @@ pub fn mk_staticallocas_basic_block(llfn: ValueRef) -> BasicBlockRef { pub fn mk_return_basic_block(llfn: ValueRef) -> BasicBlockRef { unsafe { let cx = task_llcx(); - do "return".as_c_str |buf| { + do "return".to_c_str().with_ref |buf| { llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf) } } @@ -1742,8 +1744,7 @@ pub fn copy_args_to_allocas(fcx: @mut FunctionContext, _ => {} } - for arg_n in range(0u, arg_tys.len()) { - let arg_ty = arg_tys[arg_n]; + for (arg_n, &arg_ty) in arg_tys.iter().enumerate() { let raw_llarg = raw_llargs[arg_n]; // For certain mode/type combinations, the raw llarg values are passed @@ -1792,11 +1793,30 @@ pub fn finish_fn(fcx: @mut FunctionContext, last_bcx: @mut Block) { // Builds the return block for a function. pub fn build_return_block(fcx: &FunctionContext, ret_cx: @mut Block) { // Return the value if this function immediate; otherwise, return void. - if fcx.llretptr.is_some() && fcx.has_immediate_return_value { - Ret(ret_cx, Load(ret_cx, fcx.llretptr.unwrap())) - } else { - RetVoid(ret_cx) + if fcx.llretptr.is_none() || !fcx.has_immediate_return_value { + return RetVoid(ret_cx); } + + let retptr = Value(fcx.llretptr.unwrap()); + let retval = match retptr.get_dominating_store(ret_cx) { + // If there's only a single store to the ret slot, we can directly return + // the value that was stored and omit the store and the alloca + Some(s) => { + let retval = *s.get_operand(0).unwrap(); + s.erase_from_parent(); + + if retptr.has_no_uses() { + retptr.erase_from_parent(); + } + + retval + } + // Otherwise, load the return value from the ret slot + None => Load(ret_cx, fcx.llretptr.unwrap()) + }; + + + Ret(ret_cx, retval); } pub enum self_arg { impl_self(ty::t, ty::SelfMode), no_self, } @@ -2313,7 +2333,7 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext, }; decl_cdecl_fn(ccx.llmod, main_name, llfty) }; - let llbb = do "top".as_c_str |buf| { + let llbb = do "top".to_c_str().with_ref |buf| { unsafe { llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llfn, buf) } @@ -2323,7 +2343,7 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext, llvm::LLVMPositionBuilderAtEnd(bld, llbb); let crate_map = ccx.crate_map; - let opaque_crate_map = do "crate_map".as_c_str |buf| { + let opaque_crate_map = do "crate_map".to_c_str().with_ref |buf| { llvm::LLVMBuildPointerCast(bld, crate_map, Type::i8p().to_ref(), buf) }; @@ -2341,7 +2361,7 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext, }; let args = { - let opaque_rust_main = do "rust_main".as_c_str |buf| { + let opaque_rust_main = do "rust_main".to_c_str().with_ref |buf| { llvm::LLVMBuildPointerCast(bld, rust_main, Type::i8p().to_ref(), buf) }; @@ -2366,11 +2386,10 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext, (rust_main, args) }; - let result = llvm::LLVMBuildCall(bld, - start_fn, - &args[0], - args.len() as c_uint, - noname()); + let result = do args.as_imm_buf |buf, len| { + llvm::LLVMBuildCall(bld, start_fn, buf, len as c_uint, noname()) + }; + llvm::LLVMBuildRet(bld, result); } } @@ -2429,7 +2448,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef { unsafe { let llty = llvm::LLVMTypeOf(v); - let g = do sym.as_c_str |buf| { + let g = do sym.to_c_str().with_ref |buf| { llvm::LLVMAddGlobal(ccx.llmod, llty, buf) }; @@ -2453,7 +2472,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef { match (attr::first_attr_value_str_by_name(i.attrs, "link_section")) { Some(sect) => unsafe { - do sect.as_c_str |buf| { + do sect.to_c_str().with_ref |buf| { llvm::LLVMSetSection(v, buf); } }, @@ -2494,7 +2513,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef { } ast::foreign_item_static(*) => { let ident = token::ident_to_str(&ni.ident); - let g = do ident.as_c_str |buf| { + let g = do ident.to_c_str().with_ref |buf| { unsafe { let ty = type_of(ccx, ty); llvm::LLVMAddGlobal(ccx.llmod, ty.to_ref(), buf) @@ -2601,7 +2620,7 @@ pub fn trans_constant(ccx: &mut CrateContext, it: @ast::item) { let s = mangle_exported_name(ccx, p, ty::mk_int()).to_managed(); let disr_val = vi[i].disr_val; note_unique_llvm_symbol(ccx, s); - let discrim_gvar = do s.as_c_str |buf| { + let discrim_gvar = do s.to_c_str().with_ref |buf| { unsafe { llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf) } @@ -2742,7 +2761,7 @@ pub fn decl_gc_metadata(ccx: &mut CrateContext, llmod_id: &str) { } let gc_metadata_name = ~"_gc_module_metadata_" + llmod_id; - let gc_metadata = do gc_metadata_name.as_c_str |buf| { + let gc_metadata = do gc_metadata_name.to_c_str().with_ref |buf| { unsafe { llvm::LLVMAddGlobal(ccx.llmod, Type::i32().to_ref(), buf) } @@ -2757,7 +2776,7 @@ pub fn decl_gc_metadata(ccx: &mut CrateContext, llmod_id: &str) { pub fn create_module_map(ccx: &mut CrateContext) -> ValueRef { let elttype = Type::struct_([ccx.int_type, ccx.int_type], false); let maptype = Type::array(&elttype, (ccx.module_data.len() + 1) as u64); - let map = do "_rust_mod_map".as_c_str |buf| { + let map = do "_rust_mod_map".to_c_str().with_ref |buf| { unsafe { llvm::LLVMAddGlobal(ccx.llmod, maptype.to_ref(), buf) } @@ -2805,7 +2824,7 @@ pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta, let sym_name = ~"_rust_crate_map_" + mapname; let arrtype = Type::array(&int_type, n_subcrates as u64); let maptype = Type::struct_([Type::i32(), Type::i8p(), int_type, arrtype], false); - let map = do sym_name.as_c_str |buf| { + let map = do sym_name.to_c_str().with_ref |buf| { unsafe { llvm::LLVMAddGlobal(llmod, maptype.to_ref(), buf) } @@ -2824,7 +2843,7 @@ pub fn fill_crate_map(ccx: @mut CrateContext, map: ValueRef) { cdata.name, cstore::get_crate_vers(cstore, i), cstore::get_crate_hash(cstore, i)); - let cr = do nm.as_c_str |buf| { + let cr = do nm.to_c_str().with_ref |buf| { unsafe { llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf) } @@ -2887,21 +2906,21 @@ pub fn write_metadata(cx: &mut CrateContext, crate: &ast::Crate) { let encode_parms = crate_ctxt_to_encode_parms(cx, encode_inlined_item); let llmeta = C_bytes(encoder::encode_metadata(encode_parms, crate)); let llconst = C_struct([llmeta]); - let mut llglobal = do "rust_metadata".as_c_str |buf| { + let mut llglobal = do "rust_metadata".to_c_str().with_ref |buf| { unsafe { llvm::LLVMAddGlobal(cx.llmod, val_ty(llconst).to_ref(), buf) } }; unsafe { llvm::LLVMSetInitializer(llglobal, llconst); - do cx.sess.targ_cfg.target_strs.meta_sect_name.as_c_str |buf| { + do cx.sess.targ_cfg.target_strs.meta_sect_name.to_c_str().with_ref |buf| { llvm::LLVMSetSection(llglobal, buf) }; lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage); let t_ptr_i8 = Type::i8p(); llglobal = llvm::LLVMConstBitCast(llglobal, t_ptr_i8.to_ref()); - let llvm_used = do "llvm.used".as_c_str |buf| { + let llvm_used = do "llvm.used".to_c_str().with_ref |buf| { llvm::LLVMAddGlobal(cx.llmod, Type::array(&t_ptr_i8, 1).to_ref(), buf) }; lib::llvm::SetLinkage(llvm_used, lib::llvm::AppendingLinkage); @@ -2915,7 +2934,7 @@ fn mk_global(ccx: &CrateContext, internal: bool) -> ValueRef { unsafe { - let llglobal = do name.as_c_str |buf| { + let llglobal = do name.to_c_str().with_ref |buf| { llvm::LLVMAddGlobal(ccx.llmod, val_ty(llval).to_ref(), buf) }; llvm::LLVMSetInitializer(llglobal, llval); diff --git a/src/librustc/middle/trans/basic_block.rs b/src/librustc/middle/trans/basic_block.rs new file mode 100644 index 00000000000..8ca18d81245 --- /dev/null +++ b/src/librustc/middle/trans/basic_block.rs @@ -0,0 +1,42 @@ +// 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 lib::llvm::{llvm, BasicBlockRef}; +use middle::trans::value::{UserIterator, Value}; +use std::iterator::{Filter, Map}; + +pub struct BasicBlock(BasicBlockRef); + +pub type PredIterator<'self> = Map<'self, Value, BasicBlock, Filter<'self, Value, UserIterator>>; + +/** + * Wrapper for LLVM BasicBlockRef + */ +impl BasicBlock { + pub fn as_value(self) -> Value { + unsafe { + Value(llvm::LLVMBasicBlockAsValue(*self)) + } + } + + pub fn pred_iter(self) -> PredIterator { + self.as_value().user_iter() + .filter(|user| user.is_a_terminator_inst()) + .map(|user| user.get_parent().unwrap()) + } + + pub fn get_single_predecessor(self) -> Option<BasicBlock> { + let mut iter = self.pred_iter(); + match (iter.next(), iter.next()) { + (Some(first), None) => Some(first), + _ => None + } + } +} diff --git a/src/librustc/middle/trans/builder.rs b/src/librustc/middle/trans/builder.rs index 1d821e5af94..8f48c00b8d6 100644 --- a/src/librustc/middle/trans/builder.rs +++ b/src/librustc/middle/trans/builder.rs @@ -423,7 +423,7 @@ impl Builder { if name.is_empty() { llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname()) } else { - do name.as_c_str |c| { + do name.to_c_str().with_ref |c| { llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), c) } } @@ -521,7 +521,7 @@ impl Builder { } self.inbounds_gep(base, small_vec.slice(0, ixs.len())) } else { - let v = do ixs.iter().transform |i| { C_i32(*i as i32) }.collect::<~[ValueRef]>(); + let v = do ixs.iter().map |i| { C_i32(*i as i32) }.collect::<~[ValueRef]>(); self.count_insn("gepi"); self.inbounds_gep(base, v) } @@ -739,7 +739,7 @@ impl Builder { let sanitized = text.replace("$", ""); let comment_text = fmt!("# %s", sanitized.replace("\n", "\n\t# ")); self.count_insn("inlineasm"); - let asm = do comment_text.as_c_str |c| { + let asm = do comment_text.to_c_str().with_ref |c| { unsafe { llvm::LLVMConstInlineAsm(Type::func([], &Type::void()).to_ref(), c, noname(), False, False) @@ -895,7 +895,7 @@ impl Builder { let BB: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder); let FN: ValueRef = llvm::LLVMGetBasicBlockParent(BB); let M: ModuleRef = llvm::LLVMGetGlobalParent(FN); - let T: ValueRef = do "llvm.trap".as_c_str |buf| { + let T: ValueRef = do "llvm.trap".to_c_str().with_ref |buf| { llvm::LLVMGetNamedFunction(M, buf) }; assert!((T as int != 0)); diff --git a/src/librustc/middle/trans/cabi.rs b/src/librustc/middle/trans/cabi.rs index 895bea715c9..6a1905c451f 100644 --- a/src/librustc/middle/trans/cabi.rs +++ b/src/librustc/middle/trans/cabi.rs @@ -37,7 +37,7 @@ pub struct FnType { impl FnType { pub fn decl_fn(&self, decl: &fn(fnty: Type) -> ValueRef) -> ValueRef { - let atys = self.arg_tys.iter().transform(|t| t.ty).collect::<~[Type]>(); + let atys = self.arg_tys.iter().map(|t| t.ty).collect::<~[Type]>(); let rty = self.ret_ty.ty; let fnty = Type::func(atys, &rty); let llfn = decl(fnty); diff --git a/src/librustc/middle/trans/cabi_x86_64.rs b/src/librustc/middle/trans/cabi_x86_64.rs index 530e1ff8e5b..dd24ec3ff1a 100644 --- a/src/librustc/middle/trans/cabi_x86_64.rs +++ b/src/librustc/middle/trans/cabi_x86_64.rs @@ -145,8 +145,8 @@ fn classify_ty(ty: Type) -> ~[RegClass] { } fn all_mem(cls: &mut [RegClass]) { - for i in range(0u, cls.len()) { - cls[i] = Memory; + for elt in cls.mut_iter() { + *elt = Memory; } } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 240696ec190..40a83eb9770 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -31,6 +31,7 @@ use util::ppaux::{Repr}; use middle::trans::type_::Type; +use std::c_str::ToCStr; use std::cast::transmute; use std::cast; use std::hashmap::{HashMap}; @@ -315,7 +316,7 @@ pub struct cleanup_path { pub fn shrink_scope_clean(scope_info: &mut ScopeInfo, size: uint) { scope_info.landing_pad = None; scope_info.cleanup_paths = scope_info.cleanup_paths.iter() - .take_while(|&cu| cu.size <= size).transform(|&x|x).collect(); + .take_while(|&cu| cu.size <= size).map(|&x|x).collect(); } pub fn grow_scope_clean(scope_info: &mut ScopeInfo) { @@ -707,7 +708,7 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { pub fn C_floating(s: &str, t: Type) -> ValueRef { unsafe { - do s.as_c_str |buf| { + do s.to_c_str().with_ref |buf| { llvm::LLVMConstRealOfString(t.to_ref(), buf) } } @@ -755,12 +756,12 @@ pub fn C_cstr(cx: &mut CrateContext, s: @str) -> ValueRef { None => () } - let sc = do s.as_c_str |buf| { + let sc = do s.to_c_str().with_ref |buf| { llvm::LLVMConstStringInContext(cx.llcx, buf, s.len() as c_uint, False) }; let gsym = token::gensym("str"); - let g = do fmt!("str%u", gsym).as_c_str |buf| { + let g = do fmt!("str%u", gsym).to_c_str().with_ref |buf| { llvm::LLVMAddGlobal(cx.llmod, val_ty(sc).to_ref(), buf) }; llvm::LLVMSetInitializer(g, sc); @@ -779,7 +780,7 @@ pub fn C_estr_slice(cx: &mut CrateContext, s: @str) -> ValueRef { unsafe { let len = s.len(); let cs = llvm::LLVMConstPointerCast(C_cstr(cx, s), Type::i8p().to_ref()); - C_struct([cs, C_uint(cx, len + 1u /* +1 for null */)]) + C_struct([cs, C_uint(cx, len)]) } } @@ -999,7 +1000,7 @@ pub fn node_id_type_params(bcx: @mut Block, id: ast::NodeId) -> ~[ty::t] { match bcx.fcx.param_substs { Some(substs) => { - do params.iter().transform |t| { + do params.iter().map |t| { ty::subst_tps(tcx, substs.tys, substs.self_ty, *t) }.collect() } @@ -1024,7 +1025,7 @@ pub fn resolve_vtables_under_param_substs(tcx: ty::ctxt, param_substs: Option<@param_substs>, vts: typeck::vtable_res) -> typeck::vtable_res { - @vts.iter().transform(|ds| + @vts.iter().map(|ds| resolve_param_vtables_under_param_substs(tcx, param_substs, *ds)) @@ -1036,7 +1037,7 @@ pub fn resolve_param_vtables_under_param_substs( param_substs: Option<@param_substs>, ds: typeck::vtable_param_res) -> typeck::vtable_param_res { - @ds.iter().transform( + @ds.iter().map( |d| resolve_vtable_under_param_substs(tcx, param_substs, d)) @@ -1062,7 +1063,7 @@ pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt, typeck::vtable_static(trait_id, ref tys, sub) => { let tys = match param_substs { Some(substs) => { - do tys.iter().transform |t| { + do tys.iter().map |t| { ty::subst_tps(tcx, substs.tys, substs.self_ty, *t) }.collect() } diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 40d0d77c16e..1992d71427f 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -30,6 +30,7 @@ use util::ppaux::{Repr, ty_to_str}; use middle::trans::type_::Type; +use std::c_str::ToCStr; use std::libc::c_uint; use syntax::{ast, ast_util, ast_map}; @@ -101,7 +102,7 @@ pub fn const_vec(cx: @mut CrateContext, e: &ast::expr, es: &[@ast::expr]) fn const_addr_of(cx: &mut CrateContext, cv: ValueRef) -> ValueRef { unsafe { - let gv = do "const".as_c_str |name| { + let gv = do "const".to_c_str().with_ref |name| { llvm::LLVMAddGlobal(cx.llmod, val_ty(cv).to_ref(), name) }; llvm::LLVMSetInitializer(gv, cv); @@ -498,8 +499,8 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::expr) -> ValueRef { do expr::with_field_tys(tcx, ety, Some(e.id)) |discr, field_tys| { let cs: ~[ValueRef] = field_tys.iter().enumerate() - .transform(|(ix, &field_ty)| { - match fs.iter().find_(|f| field_ty.ident == f.ident) { + .map(|(ix, &field_ty)| { + match fs.iter().find(|f| field_ty.ident == f.ident) { Some(f) => const_expr(cx, (*f).expr), None => { match base_val { @@ -527,7 +528,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::expr) -> ValueRef { ast::expr_vec(ref es, ast::m_imm) => { let (cv, sz, llunitty) = const_vec(cx, e, *es); let llty = val_ty(cv); - let gv = do "const".as_c_str |name| { + let gv = do "const".to_c_str().with_ref |name| { llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name) }; llvm::LLVMSetInitializer(gv, cv); diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 56ba1ae1694..a644174731a 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -26,6 +26,7 @@ use middle::ty; use middle::trans::type_::Type; +use std::c_str::ToCStr; use std::hash; use std::hashmap::{HashMap, HashSet}; use std::local_data; @@ -124,11 +125,17 @@ impl CrateContext { unsafe { let llcx = llvm::LLVMContextCreate(); set_task_llcx(llcx); - let llmod = name.as_c_str(|buf| llvm::LLVMModuleCreateWithNameInContext(buf, llcx)); + let llmod = do name.to_c_str().with_ref |buf| { + llvm::LLVMModuleCreateWithNameInContext(buf, llcx) + }; let data_layout: &str = sess.targ_cfg.target_strs.data_layout; let targ_triple: &str = sess.targ_cfg.target_strs.target_triple; - data_layout.as_c_str(|buf| llvm::LLVMSetDataLayout(llmod, buf)); - targ_triple.as_c_str(|buf| llvm::LLVMSetTarget(llmod, buf)); + do data_layout.to_c_str().with_ref |buf| { + llvm::LLVMSetDataLayout(llmod, buf) + }; + do targ_triple.to_c_str().with_ref |buf| { + llvm::LLVMSetTarget(llmod, buf) + }; let targ_cfg = sess.targ_cfg; let td = mk_target_data(sess.targ_cfg.target_strs.data_layout); diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 823b1e0645c..46eb3928d59 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::c_str::ToCStr; use back::link; use lib; @@ -240,7 +241,7 @@ pub fn trans_log(log_ex: &ast::expr, ccx, modpath, "loglevel"); let global; unsafe { - global = do s.as_c_str |buf| { + global = do s.to_c_str().with_ref |buf| { llvm::LLVMAddGlobal(ccx.llmod, Type::i32().to_ref(), buf) }; llvm::LLVMSetGlobalConstant(global, False); diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 624704c2c68..1fb64d9c671 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -63,6 +63,7 @@ use middle::ty; use middle::pat_util; use util::ppaux::ty_to_str; +use std::c_str::ToCStr; use std::hashmap::HashMap; use std::libc::{c_uint, c_ulonglong, c_longlong}; use std::ptr; @@ -159,7 +160,7 @@ pub fn create_local_var_metadata(bcx: @mut Block, local: &ast::Local) { let ty = node_id_type(bcx, node_id); let type_metadata = type_metadata(cx, ty, span); - let var_metadata = do name.as_c_str |name| { + let var_metadata = do name.to_c_str().with_ref |name| { unsafe { llvm::LLVMDIBuilderCreateLocalVariable( DIB(cx), @@ -246,7 +247,7 @@ pub fn create_argument_metadata(bcx: @mut Block, argument_index as c_uint }; - let arg_metadata = do name.as_c_str |name| { + let arg_metadata = do name.to_c_str().with_ref |name| { unsafe { llvm::LLVMDIBuilderCreateLocalVariable( DIB(cx), @@ -382,8 +383,8 @@ pub fn create_function_metadata(fcx: &FunctionContext) -> DISubprogram { }; let fn_metadata = - do cx.sess.str_of(ident).as_c_str |name| { - do cx.sess.str_of(ident).as_c_str |linkage| { + do cx.sess.str_of(ident).to_c_str().with_ref |name| { + do cx.sess.str_of(ident).to_c_str().with_ref |linkage| { unsafe { llvm::LLVMDIBuilderCreateFunction( DIB(cx), @@ -430,11 +431,11 @@ fn compile_unit_metadata(cx: @mut CrateContext) { let work_dir = cx.sess.working_dir.to_str(); let producer = fmt!("rustc version %s", env!("CFG_VERSION")); - do crate_name.as_c_str |crate_name| { - do work_dir.as_c_str |work_dir| { - do producer.as_c_str |producer| { - do "".as_c_str |flags| { - do "".as_c_str |split_name| { + do crate_name.to_c_str().with_ref |crate_name| { + do work_dir.to_c_str().with_ref |work_dir| { + do producer.to_c_str().with_ref |producer| { + do "".to_c_str().with_ref |flags| { + do "".to_c_str().with_ref |split_name| { unsafe { llvm::LLVMDIBuilderCreateCompileUnit(dcx.builder, DW_LANG_RUST as c_uint, crate_name, work_dir, producer, @@ -461,8 +462,8 @@ fn file_metadata(cx: &mut CrateContext, full_path: &str) -> DIFile { }; let file_metadata = - do file_name.as_c_str |file_name| { - do work_dir.as_c_str |work_dir| { + do file_name.to_c_str().with_ref |file_name| { + do work_dir.to_c_str().with_ref |work_dir| { unsafe { llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name, work_dir) } @@ -550,7 +551,7 @@ fn basic_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType { let llvm_type = type_of::type_of(cx, t); let (size, align) = size_and_align_of(cx, llvm_type); - let ty_metadata = do name.as_c_str |name| { + let ty_metadata = do name.to_c_str().with_ref |name| { unsafe { llvm::LLVMDIBuilderCreateBasicType( DIB(cx), @@ -571,7 +572,7 @@ fn pointer_type_metadata(cx: &mut CrateContext, let pointer_llvm_type = type_of::type_of(cx, pointer_type); let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type); let name = ty_to_str(cx.tcx, pointer_type); - let ptr_metadata = do name.as_c_str |name| { + let ptr_metadata = do name.to_c_str().with_ref |name| { unsafe { llvm::LLVMDIBuilderCreatePointerType( DIB(cx), @@ -661,11 +662,11 @@ fn enum_metadata(cx: &mut CrateContext, let enumerators_metadata: ~[DIDescriptor] = variants .iter() - .transform(|v| { + .map(|v| { let name: &str = cx.sess.str_of(v.name); let discriminant_value = v.disr_val as c_ulonglong; - do name.as_c_str |name| { + do name.to_c_str().with_ref |name| { unsafe { llvm::LLVMDIBuilderCreateEnumerator( DIB(cx), @@ -679,7 +680,7 @@ fn enum_metadata(cx: &mut CrateContext, let loc = span_start(cx, span); let file_metadata = file_metadata(cx, loc.file.name); - let discriminant_type_metadata = do enum_name.as_c_str |enum_name| { + let discriminant_type_metadata = do enum_name.to_c_str().with_ref |enum_name| { unsafe { llvm::LLVMDIBuilderCreateEnumerationType( DIB(cx), @@ -708,7 +709,7 @@ fn enum_metadata(cx: &mut CrateContext, let variants_member_metadata: ~[DIDescriptor] = do struct_defs .iter() .enumerate() - .transform |(i, struct_def)| { + .map |(i, struct_def)| { let variant_type_metadata = adt_struct_metadata( cx, struct_def, @@ -716,7 +717,7 @@ fn enum_metadata(cx: &mut CrateContext, Some(discriminant_type_metadata), span); - do "".as_c_str |name| { + do "".to_c_str().with_ref |name| { unsafe { llvm::LLVMDIBuilderCreateMemberType( DIB(cx), @@ -736,7 +737,7 @@ fn enum_metadata(cx: &mut CrateContext, let enum_llvm_type = type_of::type_of(cx, enum_type); let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type); - return do enum_name.as_c_str |enum_name| { + return do enum_name.to_c_str().with_ref |enum_name| { unsafe { llvm::LLVMDIBuilderCreateUnionType( DIB(cx), @@ -765,7 +766,7 @@ fn enum_metadata(cx: &mut CrateContext, { let arg_llvm_types: ~[Type] = do struct_def.fields.map |&ty| { type_of::type_of(cx, ty) }; let arg_metadata: ~[DIType] = do struct_def.fields.iter().enumerate() - .transform |(i, &ty)| { + .map |(i, &ty)| { match discriminant_type_metadata { Some(metadata) if i == 0 => metadata, _ => type_metadata(cx, ty, span) @@ -815,12 +816,12 @@ fn composite_type_metadata(cx: &mut CrateContext, let member_metadata: ~[DIDescriptor] = member_llvm_types .iter() .enumerate() - .transform(|(i, &member_llvm_type)| { + .map(|(i, &member_llvm_type)| { let (member_size, member_align) = size_and_align_of(cx, member_llvm_type); let member_offset = machine::llelement_offset(cx, composite_llvm_type, i); let member_name: &str = member_names[i]; - do member_name.as_c_str |member_name| { + do member_name.to_c_str().with_ref |member_name| { unsafe { llvm::LLVMDIBuilderCreateMemberType( DIB(cx), @@ -838,7 +839,7 @@ fn composite_type_metadata(cx: &mut CrateContext, }) .collect(); - return do composite_type_name.as_c_str |name| { + return do composite_type_name.to_c_str().with_ref |name| { unsafe { llvm::LLVMDIBuilderCreateStructType( DIB(cx), @@ -1064,7 +1065,7 @@ fn unimplemented_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType { debug!("unimplemented_type_metadata: %?", ty::get(t)); let name = ty_to_str(cx.tcx, t); - let metadata = do fmt!("NYI<%s>", name).as_c_str |name| { + let metadata = do fmt!("NYI<%s>", name).to_c_str().with_ref |name| { unsafe { llvm::LLVMDIBuilderCreateBasicType( DIB(cx), diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index a44f9321488..5931b54342f 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -582,7 +582,7 @@ fn trans_rvalue_dps_unadjusted(bcx: @mut Block, expr: @ast::expr, ast::expr_tup(ref args) => { let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr)); let numbered_fields: ~[(uint, @ast::expr)] = - args.iter().enumerate().transform(|(i, arg)| (i, *arg)).collect(); + args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect(); return trans_adt(bcx, repr, 0, numbered_fields, None, dest); } ast::expr_lit(@codemap::spanned {node: ast::lit_str(s), _}) => { @@ -849,7 +849,6 @@ fn trans_lvalue_unadjusted(bcx: @mut Block, expr: @ast::expr) -> DatumBlock { let _icx = push_ctxt("trans_index"); let ccx = bcx.ccx(); - let base_ty = expr_ty(bcx, base); let mut bcx = bcx; let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base)); @@ -879,12 +878,6 @@ fn trans_lvalue_unadjusted(bcx: @mut Block, expr: @ast::expr) -> DatumBlock { let (bcx, base, len) = base_datum.get_vec_base_and_len(bcx, index_expr.span, index_expr.id, 0); - let mut len = len; - - if ty::type_is_str(base_ty) { - // acccount for null terminator in the case of string - len = Sub(bcx, len, C_uint(bcx.ccx(), 1u)); - } debug!("trans_index: base %s", bcx.val_to_str(base)); debug!("trans_index: len %s", bcx.val_to_str(len)); @@ -943,7 +936,7 @@ fn trans_lvalue_unadjusted(bcx: @mut Block, expr: @ast::expr) -> DatumBlock { let symbol = csearch::get_symbol( bcx.ccx().sess.cstore, did); - let llval = do symbol.as_c_str |buf| { + let llval = do symbol.to_c_str().with_ref |buf| { llvm::LLVMAddGlobal(bcx.ccx().llmod, llty.to_ref(), buf) diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 948c9ceef8e..a70b907f262 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -37,6 +37,7 @@ use util::ppaux::ty_to_short_str; use middle::trans::type_::Type; +use std::c_str::ToCStr; use std::libc::c_uint; use syntax::ast; @@ -659,7 +660,7 @@ pub fn declare_tydesc(ccx: &mut CrateContext, t: ty::t) -> @mut tydesc_info { let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc").to_managed(); note_unique_llvm_symbol(ccx, name); debug!("+++ declare_tydesc %s %s", ppaux::ty_to_str(ccx.tcx, t), name); - let gvar = do name.as_c_str |buf| { + let gvar = do name.to_c_str().with_ref |buf| { unsafe { llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type.to_ref(), buf) } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 9be01ef1db9..4cc4f8fa696 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -32,6 +32,7 @@ use util::ppaux::Repr; use middle::trans::type_::Type; +use std::c_str::ToCStr; use std::vec; use syntax::ast_map::{path, path_mod, path_name}; use syntax::ast_util; @@ -287,7 +288,7 @@ pub fn method_with_name(ccx: &mut CrateContext, let imp = ccx.tcx.impls.find(&impl_id) .expect("could not find impl while translating"); - let meth = imp.methods.iter().find_(|m| m.ident == name) + let meth = imp.methods.iter().find(|m| m.ident == name) .expect("could not find method while translating"); ccx.impl_method_cache.insert((impl_id, name), meth.def_id); @@ -604,7 +605,7 @@ pub fn make_vtable(ccx: &mut CrateContext, let tbl = C_struct(components); let vtable = ccx.sess.str_of(gensym_name("vtable")); - let vt_gvar = do vtable.as_c_str |buf| { + let vt_gvar = do vtable.to_c_str().with_ref |buf| { llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl).to_ref(), buf) }; llvm::LLVMSetInitializer(vt_gvar, tbl); diff --git a/src/librustc/middle/trans/mod.rs b/src/librustc/middle/trans/mod.rs index d47d9a4ff16..387a8ecc5ee 100644 --- a/src/librustc/middle/trans/mod.rs +++ b/src/librustc/middle/trans/mod.rs @@ -42,3 +42,5 @@ pub mod machine; pub mod adt; pub mod asm; pub mod type_; +pub mod value; +pub mod basic_block; diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 5f8837b538c..21ef9058069 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -245,7 +245,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, } ast_map::node_variant(ref v, enum_item, _) => { let tvs = ty::enum_variants(ccx.tcx, local_def(enum_item.id)); - let this_tv = *tvs.iter().find_(|tv| { tv.id.node == fn_id.node}).unwrap(); + let this_tv = *tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap(); let d = mk_lldecl(); set_inline_hint(d); match v.node.kind { @@ -366,18 +366,18 @@ pub fn make_mono_id(ccx: @mut CrateContext, param_uses: Option<@~[type_use::type_uses]>) -> mono_id { // FIXME (possibly #5801): Need a lot of type hints to get // .collect() to work. - let substs_iter = substs.self_ty.iter().chain_(substs.tys.iter()); + let substs_iter = substs.self_ty.iter().chain(substs.tys.iter()); let precise_param_ids: ~[(ty::t, Option<@~[mono_id]>)] = match substs.vtables { Some(vts) => { debug!("make_mono_id vtables=%s substs=%s", vts.repr(ccx.tcx), substs.tys.repr(ccx.tcx)); - let vts_iter = substs.self_vtables.iter().chain_(vts.iter()); - vts_iter.zip(substs_iter).transform(|(vtable, subst)| { + let vts_iter = substs.self_vtables.iter().chain(vts.iter()); + vts_iter.zip(substs_iter).map(|(vtable, subst)| { let v = vtable.map(|vt| meth::vtable_id(ccx, vt)); (*subst, if !v.is_empty() { Some(@v) } else { None }) }).collect() } - None => substs_iter.transform(|subst| (*subst, None::<@~[mono_id]>)).collect() + None => substs_iter.map(|subst| (*subst, None::<@~[mono_id]>)).collect() }; @@ -387,9 +387,9 @@ pub fn make_mono_id(ccx: @mut CrateContext, // We just say it is fully used. let self_use = substs.self_ty.map(|_| type_use::use_repr|type_use::use_tydesc); - let uses_iter = self_use.iter().chain_(uses.iter()); + let uses_iter = self_use.iter().chain(uses.iter()); - precise_param_ids.iter().zip(uses_iter).transform(|(id, uses)| { + precise_param_ids.iter().zip(uses_iter).map(|(id, uses)| { if ccx.sess.no_monomorphic_collapse() { match *id { (a, b) => mono_precise(a, b) @@ -429,7 +429,7 @@ pub fn make_mono_id(ccx: @mut CrateContext, }).collect() } None => { - precise_param_ids.iter().transform(|x| { + precise_param_ids.iter().map(|x| { let (a, b) = *x; mono_precise(a, b) }).collect() diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 609aad0bc20..e0403ac9ad7 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -58,7 +58,7 @@ impl Reflector { let str_vstore = ty::vstore_slice(ty::re_static); let str_ty = ty::mk_estr(bcx.tcx(), str_vstore); let scratch = scratch_datum(bcx, str_ty, "", false); - let len = C_uint(bcx.ccx(), s.len() + 1); + let len = C_uint(bcx.ccx(), s.len()); let c_str = PointerCast(bcx, C_cstr(bcx.ccx(), s), Type::i8p()); Store(bcx, c_str, GEPi(bcx, scratch.val, [ 0, 0 ])); Store(bcx, len, GEPi(bcx, scratch.val, [ 0, 1 ])); diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 34404e49317..5b0e2fa18f2 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -265,7 +265,7 @@ pub fn trans_lit_str(bcx: @mut Block, Ignore => bcx, SaveIn(lldest) => { unsafe { - let bytes = str_lit.len() + 1; // count null-terminator too + let bytes = str_lit.len(); // count null-terminator too let llbytes = C_uint(bcx.ccx(), bytes); let llcstr = C_cstr(bcx.ccx(), str_lit); let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p().to_ref()); @@ -363,7 +363,7 @@ pub fn write_content(bcx: @mut Block, return bcx; } SaveIn(lldest) => { - let bytes = s.len() + 1; // copy null-terminator too + let bytes = s.len(); let llbytes = C_uint(bcx.ccx(), bytes); let llcstr = C_cstr(bcx.ccx(), s); base::call_memcpy(bcx, lldest, llcstr, llbytes, 1); @@ -491,7 +491,7 @@ pub fn elements_required(bcx: @mut Block, content_expr: &ast::expr) -> uint { match content_expr.node { ast::expr_lit(@codemap::spanned { node: ast::lit_str(s), _ }) => { - s.len() + 1 + s.len() }, ast::expr_vec(ref es, _) => es.len(), ast::expr_repeat(_, count_expr, _) => { @@ -524,7 +524,6 @@ pub fn get_base_and_len(bcx: @mut Block, match vstore { ty::vstore_fixed(n) => { let base = GEPi(bcx, llval, [0u, 0u]); - let n = if ty::type_is_str(vec_ty) { n + 1u } else { n }; let len = Mul(bcx, C_uint(ccx, n), vt.llunit_size); (base, len) } diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs index 9bb7f9571f3..110febfcc9f 100644 --- a/src/librustc/middle/trans/type_.rs +++ b/src/librustc/middle/trans/type_.rs @@ -20,6 +20,7 @@ use middle::trans::base; use syntax::ast; use syntax::abi::{Architecture, X86, X86_64, Arm, Mips}; +use std::c_str::ToCStr; use std::vec; use std::cast; @@ -170,7 +171,7 @@ impl Type { pub fn named_struct(name: &str) -> Type { let ctx = base::task_llcx(); - ty!(name.as_c_str(|s| llvm::LLVMStructCreateNamed(ctx, s))) + ty!(name.to_c_str().with_ref(|s| llvm::LLVMStructCreateNamed(ctx, s))) } pub fn empty_struct() -> Type { diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index ad83286c8c1..f25bf011f5d 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -206,15 +206,8 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint) pub fn type_needs(cx: &Context, use_: uint, ty: ty::t) { // Optimization -- don't descend type if all params already have this use - let len = { - let uses = &*cx.uses; - uses.len() - }; - for i in range(0u, len) { - if cx.uses[i] & use_ != use_ { - type_needs_inner(cx, use_, ty, @Nil); - return; - } + if cx.uses.iter().any(|&elt| elt & use_ != use_) { + type_needs_inner(cx, use_, ty, @Nil); } } diff --git a/src/librustc/middle/trans/value.rs b/src/librustc/middle/trans/value.rs new file mode 100644 index 00000000000..08b2db6eff9 --- /dev/null +++ b/src/librustc/middle/trans/value.rs @@ -0,0 +1,157 @@ +// 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 lib::llvm::{llvm, UseRef, ValueRef}; +use middle::trans::basic_block::BasicBlock; +use middle::trans::common::Block; +use std::libc::c_uint; + +pub struct Value(ValueRef); + +macro_rules! opt_val ( ($e:expr) => ( + unsafe { + match $e { + p if p.is_not_null() => Some(Value(p)), + _ => None + } + } +)) + +/** + * Wrapper for LLVM ValueRef + */ +impl Value { + /// Returns the BasicBlock that contains this value + pub fn get_parent(self) -> Option<BasicBlock> { + unsafe { + match llvm::LLVMGetInstructionParent(*self) { + p if p.is_not_null() => Some(BasicBlock(p)), + _ => None + } + } + } + + /// Removes this value from its containing BasicBlock + pub fn erase_from_parent(self) { + unsafe { + llvm::LLVMInstructionEraseFromParent(*self); + } + } + + /// Returns the single dominating store to this value, if any + /// This only performs a search for a trivially dominating store. The store + /// must be the only user of this value, and there must not be any conditional + /// branches between the store and the given block. + pub fn get_dominating_store(self, bcx: @mut Block) -> Option<Value> { + match self.get_single_user().chain(|user| user.as_store_inst()) { + Some(store) => { + do store.get_parent().chain |store_bb| { + let mut bb = BasicBlock(bcx.llbb); + let mut ret = Some(store); + while *bb != *store_bb { + match bb.get_single_predecessor() { + Some(pred) => bb = pred, + None => { ret = None; break } + } + } + ret + } + } + _ => None + } + } + + /// Returns the first use of this value, if any + pub fn get_first_use(self) -> Option<Use> { + unsafe { + match llvm::LLVMGetFirstUse(*self) { + u if u.is_not_null() => Some(Use(u)), + _ => None + } + } + } + + /// Tests if there are no uses of this value + pub fn has_no_uses(self) -> bool { + self.get_first_use().is_none() + } + + /// Returns the single user of this value + /// If there are no users or multiple users, this returns None + pub fn get_single_user(self) -> Option<Value> { + let mut iter = self.user_iter(); + match (iter.next(), iter.next()) { + (Some(first), None) => Some(first), + _ => None + } + } + + /// Returns an iterator for the users of this value + pub fn user_iter(self) -> UserIterator { + UserIterator { + next: self.get_first_use() + } + } + + /// Returns the requested operand of this instruction + /// Returns None, if there's no operand at the given index + pub fn get_operand(self, i: uint) -> Option<Value> { + opt_val!(llvm::LLVMGetOperand(*self, i as c_uint)) + } + + /// Returns the Store represent by this value, if any + pub fn as_store_inst(self) -> Option<Value> { + opt_val!(llvm::LLVMIsAStoreInst(*self)) + } + + /// Tests if this value is a terminator instruction + pub fn is_a_terminator_inst(self) -> bool { + unsafe { + llvm::LLVMIsATerminatorInst(*self).is_not_null() + } + } +} + +pub struct Use(UseRef); + +/** + * Wrapper for LLVM UseRef + */ +impl Use { + pub fn get_user(self) -> Value { + unsafe { + Value(llvm::LLVMGetUser(*self)) + } + } + + pub fn get_next_use(self) -> Option<Use> { + unsafe { + match llvm::LLVMGetNextUse(*self) { + u if u.is_not_null() => Some(Use(u)), + _ => None + } + } + } +} + +/// Iterator for the users of a value +pub struct UserIterator { + priv next: Option<Use> +} + +impl Iterator<Value> for UserIterator { + fn next(&mut self) -> Option<Value> { + let current = self.next; + + self.next = do current.chain |u| { u.get_next_use() }; + + do current.map |u| { u.get_user() } + } +} diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 849c35cdd2c..bba5d85083b 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3791,9 +3791,9 @@ pub fn substd_enum_variants(cx: ctxt, id: ast::def_id, substs: &substs) -> ~[@VariantInfo] { - do enum_variants(cx, id).iter().transform |variant_info| { + do enum_variants(cx, id).iter().map |variant_info| { let substd_args = variant_info.args.iter() - .transform(|aty| subst(cx, substs, *aty)).collect(); + .map(|aty| subst(cx, substs, *aty)).collect(); let substd_ctor_ty = subst(cx, substs, variant_info.ctor_ty); @@ -3935,7 +3935,7 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[@VariantInfo] { _ }, _) => { let mut last_discriminant: Option<uint> = None; - @enum_definition.variants.iter().transform(|variant| { + @enum_definition.variants.iter().map(|variant| { let mut discriminant = match last_discriminant { Some(val) => val + 1, @@ -4117,7 +4117,7 @@ pub fn lookup_struct_field(cx: ctxt, field_id: ast::def_id) -> field_ty { let r = lookup_struct_fields(cx, parent); - match r.iter().find_( + match r.iter().find( |f| f.id.node == field_id.node) { Some(t) => *t, None => cx.sess.bug("struct ID not found in parent's fields") diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 750bd506f3e..c666e98c9c1 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -724,7 +724,7 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Clone + 'static>( in_binding_rscope(rscope, RegionParamNames(bound_lifetime_names.clone())); - let input_tys = do decl.inputs.iter().enumerate().transform |(i, a)| { + let input_tys = do decl.inputs.iter().enumerate().map |(i, a)| { let expected_arg_ty = do expected_sig.chain_ref |e| { // no guarantee that the correct number of expected args // were supplied diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index e1e7d10db0a..84e5d8f9bf7 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -759,7 +759,7 @@ impl<'self> LookupContext<'self> { -> Option<method_map_entry> { // XXX(pcwalton): Do we need to clone here? let relevant_candidates: ~[Candidate] = - candidates.iter().transform(|c| (*c).clone()). + candidates.iter().map(|c| (*c).clone()). filter(|c| self.is_relevant(rcvr_ty, c)).collect(); let relevant_candidates = self.merge_candidates(relevant_candidates); @@ -772,8 +772,8 @@ impl<'self> LookupContext<'self> { self.tcx().sess.span_err( self.expr.span, "multiple applicable methods in scope"); - for idx in range(0u, relevant_candidates.len()) { - self.report_candidate(idx, &relevant_candidates[idx].origin); + for (idx, candidate) in relevant_candidates.iter().enumerate() { + self.report_candidate(idx, &candidate.origin); } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index da0e219310f..8bc32412568 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1122,7 +1122,7 @@ pub fn lookup_field_ty(tcx: ty::ctxt, fieldname: ast::ident, substs: &ty::substs) -> Option<ty::t> { - let o_field = items.iter().find_(|f| f.ident == fieldname); + let o_field = items.iter().find(|f| f.ident == fieldname); do o_field.map() |f| { ty::lookup_field_type(tcx, class_id, f.id, substs) } @@ -1818,7 +1818,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, _ => () } - let tps : ~[ty::t] = tys.iter().transform(|ty| fcx.to_ty(ty)).collect(); + let tps : ~[ty::t] = tys.iter().map(|ty| fcx.to_ty(ty)).collect(); match method::lookup(fcx, expr, base, @@ -2644,7 +2644,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let mut bot_field = false; let mut err_field = false; - let elt_ts = do elts.iter().enumerate().transform |(i, e)| { + let elt_ts = do elts.iter().enumerate().map |(i, e)| { let opt_hint = match flds { Some(ref fs) if i < fs.len() => Some(fs[i]), _ => None diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 700d96727ea..37f4a6ba497 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -100,7 +100,7 @@ fn lookup_vtables(vcx: &VtableContext, let mut result = substs.tps.rev_iter() .zip(type_param_defs.rev_iter()) - .transform(|(ty, def)| + .map(|(ty, def)| lookup_vtables_for_param(vcx, location_info, Some(substs), &*def.bounds, *ty, is_early)) .to_owned_vec(); diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index bc8de29b78b..b93f979894d 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -182,7 +182,7 @@ impl CoherenceChecker { item_impl(_, ref opt_trait, _, _) => { let opt_trait : ~[trait_ref] = opt_trait.iter() - .transform(|x| (*x).clone()) + .map(|x| (*x).clone()) .collect(); self.check_implementation(item, opt_trait); } @@ -554,8 +554,8 @@ impl CoherenceChecker { let mut provided_names = HashSet::new(); // Implemented methods - for i in range(0u, all_methods.len()) { - provided_names.insert(all_methods[i].ident); + for elt in all_methods.iter() { + provided_names.insert(elt.ident); } let r = ty::trait_methods(tcx, trait_did); diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 907a076b1a1..b5516fcc8eb 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -675,7 +675,7 @@ pub fn check_methods_against_trait(ccx: &CrateCtxt, // we'll catch it in coherence let trait_ms = ty::trait_methods(tcx, trait_ref.def_id); for impl_m in impl_ms.iter() { - match trait_ms.iter().find_(|trait_m| trait_m.ident == impl_m.mty.ident) { + match trait_ms.iter().find(|trait_m| trait_m.ident == impl_m.mty.ident) { Some(trait_m) => { let num_impl_tps = generics.ty_params.len(); compare_impl_method( @@ -731,7 +731,7 @@ pub fn convert_methods(ccx: &CrateCtxt, -> ~[ConvertedMethod] { let tcx = ccx.tcx; - return ms.iter().transform(|m| { + return ms.iter().map(|m| { let num_rcvr_ty_params = rcvr_ty_generics.type_param_defs.len(); let m_ty_generics = ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics, diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index 63503f3e6b6..91b6a4ce3bc 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -374,8 +374,8 @@ impl RegionVarBindings { pub fn vars_created_since_snapshot(&mut self, snapshot: uint) -> ~[RegionVid] { do vec::build |push| { - for i in range(snapshot, self.undo_log.len()) { - match self.undo_log[i] { + for &elt in self.undo_log.slice_from(snapshot).iter() { + match elt { AddVar(vid) => push(vid), _ => () } diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index bbcf42b1c5d..c9e2b8dd37b 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -215,7 +215,7 @@ impl region_scope for MethodRscope { pub struct type_rscope(Option<RegionParameterization>); impl type_rscope { - priv fn replacement(&self) -> ty::Region { + fn replacement(&self) -> ty::Region { if self.is_some() { ty::re_bound(ty::br_self) } else { diff --git a/src/librustc/rustc.rs b/src/librustc/rustc.rs index 1dfca0ba0e8..4cb6d7de0d3 100644 --- a/src/librustc/rustc.rs +++ b/src/librustc/rustc.rs @@ -117,6 +117,7 @@ mod std { } */ +#[cfg(stage0)] pub fn version(argv0: &str) { let mut vers = ~"unknown version"; let env_vers = env!("CFG_VERSION"); @@ -125,6 +126,16 @@ pub fn version(argv0: &str) { printfln!("host: %s", host_triple()); } +#[cfg(not(stage0))] +pub fn version(argv0: &str) { + let vers = match option_env!("CFG_VERSION") { + Some(vers) => vers, + None => "unknown version" + }; + printfln!("%s %s", argv0, vers); + printfln!("host: %s", host_triple()); +} + pub fn usage(argv0: &str) { let message = fmt!("Usage: %s [OPTIONS] INPUT", argv0); printfln!("%s\ @@ -136,7 +147,7 @@ Additional help: pub fn describe_warnings() { use extra::sort::Sort; - printfln!(" + println(" Available lint options: -W <foo> Warn about <foo> -A <foo> Allow <foo> @@ -145,8 +156,8 @@ Available lint options: "); let lint_dict = lint::get_lint_dict(); - let mut lint_dict = lint_dict.consume() - .transform(|(k, v)| (v, k)) + let mut lint_dict = lint_dict.move_iter() + .map(|(k, v)| (v, k)) .collect::<~[(lint::LintSpec, &'static str)]>(); lint_dict.qsort(); @@ -157,12 +168,12 @@ Available lint options: fn padded(max: uint, s: &str) -> ~str { str::from_bytes(vec::from_elem(max - s.len(), ' ' as u8)) + s } - printfln!("\nAvailable lint checks:\n"); + println("\nAvailable lint checks:\n"); printfln!(" %s %7.7s %s", padded(max_key, "name"), "default", "meaning"); printfln!(" %s %7.7s %s\n", padded(max_key, "----"), "-------", "-------"); - for (spec, name) in lint_dict.consume_iter() { + for (spec, name) in lint_dict.move_iter() { let name = name.replace("_", "-"); printfln!(" %s %7.7s %s", padded(max_key, name), @@ -173,7 +184,7 @@ Available lint options: } pub fn describe_debug_flags() { - printfln!("\nAvailable debug options:\n"); + println("\nAvailable debug options:\n"); let r = session::debugging_opts_map(); for tuple in r.iter() { match *tuple { @@ -301,7 +312,7 @@ pub fn monitor(f: ~fn(diagnostic::Emitter)) { // XXX: This is a hack for newsched since it doesn't support split stacks. // rustc needs a lot of stack! - static STACK_SIZE: uint = 4000000; + static STACK_SIZE: uint = 6000000; let (p, ch) = stream(); let ch = SharedChan::new(ch); diff --git a/src/librustdoc/attr_parser.rs b/src/librustdoc/attr_parser.rs index f8eff69cc8f..ce8d1977443 100644 --- a/src/librustdoc/attr_parser.rs +++ b/src/librustdoc/attr_parser.rs @@ -27,7 +27,7 @@ pub struct CrateAttrs { fn doc_metas(attrs: ~[ast::Attribute]) -> ~[@ast::MetaItem] { attrs.iter() .filter(|at| "doc" == at.name()) - .transform(|at| at.desugar_doc().meta()) + .map(|at| at.desugar_doc().meta()) .collect() } @@ -41,7 +41,7 @@ pub fn parse_crate(attrs: ~[ast::Attribute]) -> CrateAttrs { } pub fn parse_desc(attrs: ~[ast::Attribute]) -> Option<~str> { - let doc_strs = do doc_metas(attrs).consume_iter().filter_map |meta| { + let doc_strs = do doc_metas(attrs).move_iter().filter_map |meta| { meta.value_str() }.collect::<~[@str]>(); if doc_strs.is_empty() { diff --git a/src/librustdoc/attr_pass.rs b/src/librustdoc/attr_pass.rs index a1cb81f4503..b5503cc51e1 100644 --- a/src/librustdoc/attr_pass.rs +++ b/src/librustdoc/attr_pass.rs @@ -123,7 +123,7 @@ fn fold_enum( let doc = fold::default_seq_fold_enum(fold, doc); doc::EnumDoc { - variants: do doc.variants.iter().transform |variant| { + variants: do doc.variants.iter().map |variant| { let variant = (*variant).clone(); let desc = { let variant = variant.clone(); @@ -133,7 +133,7 @@ fn fold_enum( node: ast::item_enum(ref enum_definition, _), _ }, _) => { let ast_variant = - (*enum_definition.variants.iter().find_(|v| { + (*enum_definition.variants.iter().find(|v| { to_str(v.node.name) == variant.name }).unwrap()).clone(); @@ -182,7 +182,7 @@ fn merge_method_attrs( ast_map::node_item(@ast::item { node: ast::item_trait(_, _, ref methods), _ }, _) => { - methods.iter().transform(|method| { + methods.iter().map(|method| { match (*method).clone() { ast::required(ty_m) => { (to_str(ty_m.ident), @@ -197,7 +197,7 @@ fn merge_method_attrs( ast_map::node_item(@ast::item { node: ast::item_impl(_, _, _, ref methods), _ }, _) => { - methods.iter().transform(|method| { + methods.iter().map(|method| { (to_str(method.ident), attr_parser::parse_desc(method.attrs.clone())) }).collect() @@ -206,7 +206,7 @@ fn merge_method_attrs( } }; - do docs.iter().zip(attrs.iter()).transform |(doc, attrs)| { + do docs.iter().zip(attrs.iter()).map |(doc, attrs)| { assert!(doc.name == attrs.first()); let desc = attrs.second(); diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 3598eb7c0fb..877338902cc 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -221,7 +221,7 @@ pub fn maybe_find_pandoc( } }; - let pandoc = do possible_pandocs.iter().find_ |&pandoc| { + let pandoc = do possible_pandocs.iter().find |&pandoc| { let output = process_output(*pandoc, [~"--version"]); debug!("testing pandoc cmd %s: %?", *pandoc, output); output.status == 0 diff --git a/src/librustdoc/doc.rs b/src/librustdoc/doc.rs index d24fd1f5bfe..aba7ea1f0d7 100644 --- a/src/librustdoc/doc.rs +++ b/src/librustdoc/doc.rs @@ -54,7 +54,7 @@ pub struct CrateDoc { pub enum ItemTag { ModTag(ModDoc), NmodTag(NmodDoc), - ConstTag(ConstDoc), + StaticTag(StaticDoc), FnTag(FnDoc), EnumTag(EnumDoc), TraitTag(TraitDoc), @@ -95,7 +95,7 @@ pub struct NmodDoc { index: Option<Index> } -pub type ConstDoc = SimpleItemDoc; +pub type StaticDoc = SimpleItemDoc; pub type FnDoc = SimpleItemDoc; @@ -214,8 +214,8 @@ impl ModDoc { md!(FnTag) } - pub fn consts(&self) -> ~[ConstDoc] { - md!(ConstTag) + pub fn statics(&self) -> ~[StaticDoc] { + md!(StaticTag) } pub fn enums(&self) -> ~[EnumDoc] { @@ -249,7 +249,7 @@ pub trait PageUtils { fn mods(&self) -> ~[ModDoc]; fn nmods(&self) -> ~[NmodDoc]; fn fns(&self) -> ~[FnDoc]; - fn consts(&self) -> ~[ConstDoc]; + fn statics(&self) -> ~[StaticDoc]; fn enums(&self) -> ~[EnumDoc]; fn traits(&self) -> ~[TraitDoc]; fn impls(&self) -> ~[ImplDoc]; @@ -270,8 +270,8 @@ impl PageUtils for ~[Page] { pu!(FnTag) } - fn consts(&self) -> ~[ConstDoc] { - pu!(ConstTag) + fn statics(&self) -> ~[StaticDoc] { + pu!(StaticTag) } fn enums(&self) -> ~[EnumDoc] { @@ -301,7 +301,7 @@ impl Item for ItemTag { &doc::ModTag(ref doc) => doc.item.clone(), &doc::NmodTag(ref doc) => doc.item.clone(), &doc::FnTag(ref doc) => doc.item.clone(), - &doc::ConstTag(ref doc) => doc.item.clone(), + &doc::StaticTag(ref doc) => doc.item.clone(), &doc::EnumTag(ref doc) => doc.item.clone(), &doc::TraitTag(ref doc) => doc.item.clone(), &doc::ImplTag(ref doc) => doc.item.clone(), diff --git a/src/librustdoc/extract.rs b/src/librustdoc/extract.rs index f849cfade9b..55552924d44 100644 --- a/src/librustdoc/extract.rs +++ b/src/librustdoc/extract.rs @@ -101,8 +101,8 @@ fn moddoc_from_mod( )) } ast::item_static(*) => { - Some(doc::ConstTag( - constdoc_from_const(ItemDoc) + Some(doc::StaticTag( + staticdoc_from_static(ItemDoc) )) } ast::item_enum(enum_definition, _) => { @@ -165,7 +165,7 @@ fn fndoc_from_fn(itemdoc: doc::ItemDoc) -> doc::FnDoc { } } -fn constdoc_from_const(itemdoc: doc::ItemDoc) -> doc::ConstDoc { +fn staticdoc_from_static(itemdoc: doc::ItemDoc) -> doc::StaticDoc { doc::SimpleItemDoc { item: itemdoc, sig: None @@ -185,7 +185,7 @@ fn enumdoc_from_enum( fn variantdocs_from_variants( variants: ~[ast::variant] ) -> ~[doc::VariantDoc] { - variants.iter().transform(variantdoc_from_variant).collect() + variants.iter().map(variantdoc_from_variant).collect() } fn variantdoc_from_variant(variant: &ast::variant) -> doc::VariantDoc { @@ -202,7 +202,7 @@ fn traitdoc_from_trait( ) -> doc::TraitDoc { doc::TraitDoc { item: itemdoc, - methods: do methods.iter().transform |method| { + methods: do methods.iter().map |method| { match (*method).clone() { ast::required(ty_m) => { doc::MethodDoc { @@ -238,7 +238,7 @@ fn impldoc_from_impl( bounds_str: None, trait_types: ~[], self_ty: None, - methods: do methods.iter().transform |method| { + methods: do methods.iter().map |method| { doc::MethodDoc { name: to_str(method.ident), brief: None, @@ -356,10 +356,10 @@ mod test { } #[test] - fn should_extract_const_name_and_id() { + fn should_extract_static_name_and_id() { let doc = mk_doc(@"static a: int = 0;"); - assert!(doc.cratemod().consts()[0].id() != 0); - assert!(doc.cratemod().consts()[0].name_() == ~"a"); + assert!(doc.cratemod().statics()[0].id() != 0); + assert!(doc.cratemod().statics()[0].name_() == ~"a"); } #[test] diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index ad0dabdc3a4..3e74916228f 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -21,7 +21,7 @@ pub struct Fold<T> { fold_mod: FoldMod<T>, fold_nmod: FoldNmod<T>, fold_fn: FoldFn<T>, - fold_const: FoldConst<T>, + fold_static: FoldStatic<T>, fold_enum: FoldEnum<T>, fold_trait: FoldTrait<T>, fold_impl: FoldImpl<T>, @@ -39,7 +39,7 @@ impl<T:Clone> Clone for Fold<T> { fold_mod: self.fold_mod, fold_nmod: self.fold_nmod, fold_fn: self.fold_fn, - fold_const: self.fold_const, + fold_static: self.fold_static, fold_enum: self.fold_enum, fold_trait: self.fold_trait, fold_impl: self.fold_impl, @@ -55,7 +55,7 @@ type FoldItem<T> = @fn(fold: &Fold<T>, doc: doc::ItemDoc) -> doc::ItemDoc; type FoldMod<T> = @fn(fold: &Fold<T>, doc: doc::ModDoc) -> doc::ModDoc; type FoldNmod<T> = @fn(fold: &Fold<T>, doc: doc::NmodDoc) -> doc::NmodDoc; type FoldFn<T> = @fn(fold: &Fold<T>, doc: doc::FnDoc) -> doc::FnDoc; -type FoldConst<T> = @fn(fold: &Fold<T>, doc: doc::ConstDoc) -> doc::ConstDoc; +type FoldStatic<T> = @fn(fold: &Fold<T>, doc: doc::StaticDoc) -> doc::StaticDoc; type FoldEnum<T> = @fn(fold: &Fold<T>, doc: doc::EnumDoc) -> doc::EnumDoc; type FoldTrait<T> = @fn(fold: &Fold<T>, doc: doc::TraitDoc) -> doc::TraitDoc; type FoldImpl<T> = @fn(fold: &Fold<T>, doc: doc::ImplDoc) -> doc::ImplDoc; @@ -73,7 +73,7 @@ fn mk_fold<T>( fold_mod: FoldMod<T>, fold_nmod: FoldNmod<T>, fold_fn: FoldFn<T>, - fold_const: FoldConst<T>, + fold_static: FoldStatic<T>, fold_enum: FoldEnum<T>, fold_trait: FoldTrait<T>, fold_impl: FoldImpl<T>, @@ -88,7 +88,7 @@ fn mk_fold<T>( fold_mod: fold_mod, fold_nmod: fold_nmod, fold_fn: fold_fn, - fold_const: fold_const, + fold_static: fold_static, fold_enum: fold_enum, fold_trait: fold_trait, fold_impl: fold_impl, @@ -106,7 +106,7 @@ pub fn default_any_fold<T:Clone>(ctxt: T) -> Fold<T> { |f, d| default_any_fold_mod(f, d), |f, d| default_any_fold_nmod(f, d), |f, d| default_seq_fold_fn(f, d), - |f, d| default_seq_fold_const(f, d), + |f, d| default_seq_fold_static(f, d), |f, d| default_seq_fold_enum(f, d), |f, d| default_seq_fold_trait(f, d), |f, d| default_seq_fold_impl(f, d), @@ -124,7 +124,7 @@ pub fn default_seq_fold<T:Clone>(ctxt: T) -> Fold<T> { |f, d| default_seq_fold_mod(f, d), |f, d| default_seq_fold_nmod(f, d), |f, d| default_seq_fold_fn(f, d), - |f, d| default_seq_fold_const(f, d), + |f, d| default_seq_fold_static(f, d), |f, d| default_seq_fold_enum(f, d), |f, d| default_seq_fold_trait(f, d), |f, d| default_seq_fold_impl(f, d), @@ -142,7 +142,7 @@ pub fn default_par_fold<T:Clone>(ctxt: T) -> Fold<T> { |f, d| default_par_fold_mod(f, d), |f, d| default_par_fold_nmod(f, d), |f, d| default_seq_fold_fn(f, d), - |f, d| default_seq_fold_const(f, d), + |f, d| default_seq_fold_static(f, d), |f, d| default_seq_fold_enum(f, d), |f, d| default_seq_fold_trait(f, d), |f, d| default_seq_fold_impl(f, d), @@ -153,7 +153,7 @@ pub fn default_par_fold<T:Clone>(ctxt: T) -> Fold<T> { pub fn default_seq_fold_doc<T>(fold: &Fold<T>, doc: doc::Doc) -> doc::Doc { doc::Doc { - pages: do doc.pages.iter().transform |page| { + pages: do doc.pages.iter().map |page| { match (*page).clone() { doc::CratePage(doc) => { doc::CratePage((fold.fold_crate)(fold, doc)) @@ -189,7 +189,7 @@ pub fn default_any_fold_mod<T:Clone>( ) -> doc::ModDoc { doc::ModDoc { item: (fold.fold_item)(fold, doc.item.clone()), - items: doc.items.iter().transform(|ItemTag| { + items: doc.items.iter().map(|ItemTag| { fold_ItemTag(fold, (*ItemTag).clone()) }).collect(), .. doc @@ -202,7 +202,7 @@ pub fn default_seq_fold_mod<T>( ) -> doc::ModDoc { doc::ModDoc { item: (fold.fold_item)(fold, doc.item.clone()), - items: doc.items.iter().transform(|ItemTag| { + items: doc.items.iter().map(|ItemTag| { fold_ItemTag(fold, (*ItemTag).clone()) }).collect(), .. doc @@ -215,7 +215,7 @@ pub fn default_par_fold_mod<T:Clone>( ) -> doc::ModDoc { doc::ModDoc { item: (fold.fold_item)(fold, doc.item.clone()), - items: doc.items.iter().transform(|ItemTag| { + items: doc.items.iter().map(|ItemTag| { fold_ItemTag(fold, (*ItemTag).clone()) }).collect(), .. doc @@ -228,7 +228,7 @@ pub fn default_any_fold_nmod<T:Clone>( ) -> doc::NmodDoc { doc::NmodDoc { item: (fold.fold_item)(fold, doc.item.clone()), - fns: doc.fns.iter().transform(|FnDoc| { + fns: doc.fns.iter().map(|FnDoc| { (fold.fold_fn)(fold, (*FnDoc).clone()) }).collect(), .. doc @@ -241,7 +241,7 @@ pub fn default_seq_fold_nmod<T>( ) -> doc::NmodDoc { doc::NmodDoc { item: (fold.fold_item)(fold, doc.item.clone()), - fns: doc.fns.iter().transform(|FnDoc| { + fns: doc.fns.iter().map(|FnDoc| { (fold.fold_fn)(fold, (*FnDoc).clone()) }).collect(), .. doc @@ -254,7 +254,7 @@ pub fn default_par_fold_nmod<T:Clone>( ) -> doc::NmodDoc { doc::NmodDoc { item: (fold.fold_item)(fold, doc.item.clone()), - fns: doc.fns.iter().transform(|FnDoc| { + fns: doc.fns.iter().map(|FnDoc| { (fold.fold_fn)(fold, (*FnDoc).clone()) }).collect(), .. doc @@ -272,8 +272,8 @@ pub fn fold_ItemTag<T>(fold: &Fold<T>, doc: doc::ItemTag) -> doc::ItemTag { doc::FnTag(FnDoc) => { doc::FnTag((fold.fold_fn)(fold, FnDoc)) } - doc::ConstTag(ConstDoc) => { - doc::ConstTag((fold.fold_const)(fold, ConstDoc)) + doc::StaticTag(StaticDoc) => { + doc::StaticTag((fold.fold_static)(fold, StaticDoc)) } doc::EnumTag(EnumDoc) => { doc::EnumTag((fold.fold_enum)(fold, EnumDoc)) @@ -303,10 +303,10 @@ pub fn default_seq_fold_fn<T>( } } -pub fn default_seq_fold_const<T>( +pub fn default_seq_fold_static<T>( fold: &Fold<T>, - doc: doc::ConstDoc -) -> doc::ConstDoc { + doc: doc::StaticDoc +) -> doc::StaticDoc { doc::SimpleItemDoc { item: (fold.fold_item)(fold, doc.item.clone()), .. doc @@ -374,7 +374,7 @@ fn default_fold_should_produce_same_doc() { } #[test] -fn default_fold_should_produce_same_consts() { +fn default_fold_should_produce_same_statics() { let source = @"static a: int = 0;"; let ast = parse::from_str(source); let doc = extract::extract(ast, ~""); diff --git a/src/librustdoc/markdown_pass.rs b/src/librustdoc/markdown_pass.rs index f05c59083f4..7d07b4864f5 100644 --- a/src/librustdoc/markdown_pass.rs +++ b/src/librustdoc/markdown_pass.rs @@ -150,8 +150,8 @@ pub fn header_kind(doc: doc::ItemTag) -> ~str { doc::FnTag(_) => { ~"Function" } - doc::ConstTag(_) => { - ~"Freeze" + doc::StaticTag(_) => { + ~"Static" } doc::EnumTag(_) => { ~"Enum" @@ -321,7 +321,7 @@ fn write_item_(ctxt: &Ctxt, doc: doc::ItemTag, write_header: bool) { doc::ModTag(ModDoc) => write_mod(ctxt, ModDoc), doc::NmodTag(nModDoc) => write_nmod(ctxt, nModDoc), doc::FnTag(FnDoc) => write_fn(ctxt, FnDoc), - doc::ConstTag(ConstDoc) => write_const(ctxt, ConstDoc), + doc::StaticTag(StaticDoc) => write_static(ctxt, StaticDoc), doc::EnumTag(EnumDoc) => write_enum(ctxt, EnumDoc), doc::TraitTag(TraitDoc) => write_trait(ctxt, TraitDoc), doc::ImplTag(ImplDoc) => write_impl(ctxt, ImplDoc), @@ -409,9 +409,9 @@ fn code_block(s: ~str) -> ~str { ~~~", s) } -fn write_const( +fn write_static( ctxt: &Ctxt, - doc: doc::ConstDoc + doc: doc::StaticDoc ) { write_sig(ctxt, doc.sig.clone()); write_common(ctxt, doc.desc(), doc.sections()); @@ -775,13 +775,13 @@ mod test { } #[test] - fn should_write_const_header() { + fn should_write_static_header() { let markdown = render(~"static a: bool = true;"); - assert!(markdown.contains("## Freeze `a`\n\n")); + assert!(markdown.contains("## Static `a`\n\n")); } #[test] - fn should_write_const_description() { + fn should_write_static_description() { let markdown = render( ~"#[doc = \"b\"]\ static a: bool = true;"); diff --git a/src/librustdoc/page_pass.rs b/src/librustdoc/page_pass.rs index 82a4724496d..342c949e3fc 100644 --- a/src/librustdoc/page_pass.rs +++ b/src/librustdoc/page_pass.rs @@ -123,7 +123,7 @@ fn strip_mod(doc: doc::ModDoc) -> doc::ModDoc { doc::ModTag(_) | doc::NmodTag(_) => false, _ => true } - }.transform(|x| (*x).clone()).collect::<~[doc::ItemTag]>(), + }.map(|x| (*x).clone()).collect::<~[doc::ItemTag]>(), .. doc.clone() } } diff --git a/src/librustdoc/prune_hidden_pass.rs b/src/librustdoc/prune_hidden_pass.rs index 04cb0e3f710..9dc2f43f7ac 100644 --- a/src/librustdoc/prune_hidden_pass.rs +++ b/src/librustdoc/prune_hidden_pass.rs @@ -43,7 +43,7 @@ fn fold_mod( doc::ModDoc { items: do doc.items.iter().filter |item_tag| { !is_hidden(fold.ctxt.clone(), item_tag.item()) - }.transform(|x| (*x).clone()).collect(), + }.map(|x| (*x).clone()).collect(), .. doc } } diff --git a/src/librustdoc/prune_private_pass.rs b/src/librustdoc/prune_private_pass.rs index 6f3f91f3c65..e1bc059e20f 100644 --- a/src/librustdoc/prune_private_pass.rs +++ b/src/librustdoc/prune_private_pass.rs @@ -81,7 +81,7 @@ fn strip_priv_methods( item_vis: ast::visibility ) -> doc::ImplDoc { let methods = do doc.methods.iter().filter |method| { - let ast_method = do methods.iter().find_ |m| { + let ast_method = do methods.iter().find |m| { extract::to_str(m.ident) == method.name }; assert!(ast_method.is_some()); @@ -91,7 +91,7 @@ fn strip_priv_methods( ast::private => false, ast::inherited => item_vis == ast::public } - }.transform(|x| (*x).clone()).collect(); + }.map(|x| (*x).clone()).collect(); doc::ImplDoc { methods: methods, @@ -126,7 +126,7 @@ fn fold_mod( is_visible(fold.ctxt.clone(), item_tag.item()) } } - }).transform(|x| (*x).clone()).collect(), + }).map(|x| (*x).clone()).collect(), .. doc } } @@ -202,7 +202,7 @@ mod test { let doc = mk_doc( ~"impl Foo {\ pub fn bar() { }\ - priv fn baz() { }\ + fn baz() { }\ }"); assert_eq!(doc.cratemod().impls()[0].methods.len(), 1); } @@ -212,7 +212,7 @@ mod test { let doc = mk_doc( ~"impl Foo {\ pub fn bar() { }\ - priv fn baz() { }\ + fn baz() { }\ }"); assert_eq!(doc.cratemod().impls()[0].methods.len(), 1); } @@ -232,7 +232,7 @@ mod test { let doc = mk_doc( ~"impl Foo {\ pub fn bar() { }\ - priv fn baz() { }\ + fn baz() { }\ }"); assert_eq!(doc.cratemod().impls()[0].methods.len(), 1); } diff --git a/src/librustdoc/sort_item_type_pass.rs b/src/librustdoc/sort_item_type_pass.rs index 366cc83df27..ba8f37601fd 100644 --- a/src/librustdoc/sort_item_type_pass.rs +++ b/src/librustdoc/sort_item_type_pass.rs @@ -18,7 +18,7 @@ pub fn mk_pass() -> Pass { fn by_score(item1: &doc::ItemTag, item2: &doc::ItemTag) -> bool { fn score(item: &doc::ItemTag) -> int { match *item { - doc::ConstTag(_) => 0, + doc::StaticTag(_) => 0, doc::TyTag(_) => 1, doc::EnumTag(_) => 2, doc::StructTag(_) => 3, @@ -43,7 +43,7 @@ fn test() { let source = ~"mod imod { } \ - static iconst: int = 0; \ + static istatic: int = 0; \ fn ifn() { } \ enum ienum { ivar } \ trait itrait { fn a(); } \ @@ -54,7 +54,7 @@ fn test() { let doc = extract::from_srv(srv.clone(), ~""); let doc = (mk_pass().f)(srv.clone(), doc); // hidden __std_macros module at the start. - assert_eq!(doc.cratemod().items[0].name_(), ~"iconst"); + assert_eq!(doc.cratemod().items[0].name_(), ~"istatic"); assert_eq!(doc.cratemod().items[1].name_(), ~"itype"); assert_eq!(doc.cratemod().items[2].name_(), ~"ienum"); assert_eq!(doc.cratemod().items[3].name_(), ~"istruct"); diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs index 0d7ec34243d..aa4407af76d 100644 --- a/src/librustdoc/tystr_pass.rs +++ b/src/librustdoc/tystr_pass.rs @@ -39,7 +39,7 @@ pub fn run( let fold = Fold { ctxt: srv.clone(), fold_fn: fold_fn, - fold_const: fold_const, + fold_static: fold_static, fold_enum: fold_enum, fold_trait: fold_trait, fold_impl: fold_impl, @@ -93,10 +93,10 @@ fn get_fn_sig(srv: astsrv::Srv, fn_id: doc::AstId) -> Option<~str> { } } -fn fold_const( +fn fold_static( fold: &fold::Fold<astsrv::Srv>, - doc: doc::ConstDoc -) -> doc::ConstDoc { + doc: doc::StaticDoc +) -> doc::StaticDoc { let srv = fold.ctxt.clone(); doc::SimpleItemDoc { @@ -109,7 +109,7 @@ fn fold_const( }, _) => { pprust::ty_to_str(ty, extract::interner()) } - _ => fail!("fold_const: id not bound to a const item") + _ => fail!("fold_static: id not bound to a static item") } }}), .. doc @@ -124,7 +124,7 @@ fn fold_enum( let srv = fold.ctxt.clone(); doc::EnumDoc { - variants: do doc.variants.iter().transform |variant| { + variants: do doc.variants.iter().map |variant| { let sig = { let variant = (*variant).clone(); do astsrv::exec(srv.clone()) |ctxt| { @@ -133,7 +133,7 @@ fn fold_enum( node: ast::item_enum(ref enum_definition, _), _ }, _) => { let ast_variant = - (*do enum_definition.variants.iter().find_ |v| { + (*do enum_definition.variants.iter().find |v| { to_str(v.node.name) == variant.name }.unwrap()).clone(); @@ -169,7 +169,7 @@ fn merge_methods( item_id: doc::AstId, docs: ~[doc::MethodDoc] ) -> ~[doc::MethodDoc] { - do docs.iter().transform |doc| { + do docs.iter().map |doc| { doc::MethodDoc { sig: get_method_sig(srv.clone(), item_id, doc.name.clone()), .. (*doc).clone() @@ -187,7 +187,7 @@ fn get_method_sig( ast_map::node_item(@ast::item { node: ast::item_trait(_, _, ref methods), _ }, _) => { - match methods.iter().find_(|&method| { + match methods.iter().find(|&method| { match (*method).clone() { ast::required(ty_m) => to_str(ty_m.ident) == method_name, ast::provided(m) => to_str(m.ident) == method_name, @@ -223,7 +223,7 @@ fn get_method_sig( ast_map::node_item(@ast::item { node: ast::item_impl(_, _, _, ref methods), _ }, _) => { - match methods.iter().find_(|method| { + match methods.iter().find(|method| { to_str(method.ident) == method_name }) { Some(method) => { @@ -384,9 +384,9 @@ mod test { } #[test] - fn should_add_const_types() { + fn should_add_static_types() { let doc = mk_doc(~"static a: bool = true;"); - assert!(doc.cratemod().consts()[0].sig == Some(~"bool")); + assert!(doc.cratemod().statics()[0].sig == Some(~"bool")); } #[test] diff --git a/src/librusti/program.rs b/src/librusti/program.rs index d8a640bc19c..07af3012601 100644 --- a/src/librusti/program.rs +++ b/src/librusti/program.rs @@ -167,7 +167,7 @@ impl Program { } let newvars = util::replace(&mut self.newvars, HashMap::new()); - for (name, var) in newvars.consume() { + for (name, var) in newvars.move_iter() { self.local_vars.insert(name, var); } @@ -233,7 +233,7 @@ impl Program { pub fn consume_cache(&mut self) { let map = local_data::pop(tls_key).expect("tls is empty"); let cons_map = util::replace(map, HashMap::new()); - for (name, value) in cons_map.consume() { + for (name, value) in cons_map.move_iter() { match self.local_vars.find_mut(&name) { Some(v) => { v.data = (*value).clone(); } None => { fail!("unknown variable %s", name) } @@ -345,7 +345,7 @@ impl Program { // I'm not an @ pointer, so this has to be done outside. let cons_newvars = util::replace(newvars, HashMap::new()); - for (k, v) in cons_newvars.consume() { + for (k, v) in cons_newvars.move_iter() { self.newvars.insert(k, v); } diff --git a/src/librusti/rusti.rs b/src/librusti/rusti.rs index bb863df3348..29ad9eb49a3 100644 --- a/src/librusti/rusti.rs +++ b/src/librusti/rusti.rs @@ -315,7 +315,7 @@ fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> { // file, skip compilation and return None. let mut should_compile = true; let dir = os::list_dir_path(&Path(outputs.out_filename.dirname())); - let maybe_lib_path = do dir.iter().find_ |file| { + let maybe_lib_path = do dir.iter().find |file| { // The actual file's name has a hash value and version // number in it which is unknown at this time, so looking // for a file that matches out_filename won't work, @@ -453,7 +453,7 @@ pub fn run_line(repl: &mut Repl, input: @io::Reader, out: @io::Writer, line: ~st if line.starts_with(":") { // drop the : and the \n (one byte each) let full = line.slice(1, line.len()); - let split: ~[~str] = full.word_iter().transform(|s| s.to_owned()).collect(); + let split: ~[~str] = full.word_iter().map(|s| s.to_owned()).collect(); let len = split.len(); if len > 0 { diff --git a/src/librustpkg/api.rs b/src/librustpkg/api.rs index bcda135cbb6..2da66baa412 100644 --- a/src/librustpkg/api.rs +++ b/src/librustpkg/api.rs @@ -23,33 +23,30 @@ fn default_ctxt(p: @Path) -> Ctx { Ctx { sysroot_opt: Some(p), json: false, dep_cache: @mut HashMap::new() } } -pub fn build_lib(sysroot: @Path, root: Path, dest: Path, name: ~str, version: Version, +pub fn build_lib(sysroot: @Path, root: Path, name: ~str, version: Version, lib: Path) { let pkg_src = PkgSrc { root: root, - dst_dir: dest.clone(), - id: PkgId{ version: version, ..PkgId::new(name, &dest.pop())}, + id: PkgId{ version: version, ..PkgId::new(name)}, libs: ~[mk_crate(lib)], mains: ~[], tests: ~[], benchs: ~[] }; - pkg_src.build(&default_ctxt(sysroot), pkg_src.dst_dir, ~[]); + pkg_src.build(&default_ctxt(sysroot), ~[]); } -pub fn build_exe(sysroot: @Path, root: Path, dest: Path, name: ~str, version: Version, - main: Path) { +pub fn build_exe(sysroot: @Path, root: Path, name: ~str, version: Version, main: Path) { let pkg_src = PkgSrc { root: root, - dst_dir: dest.clone(), - id: PkgId{ version: version, ..PkgId::new(name, &dest.pop())}, + id: PkgId{ version: version, ..PkgId::new(name)}, libs: ~[], mains: ~[mk_crate(main)], tests: ~[], benchs: ~[] }; - pkg_src.build(&default_ctxt(sysroot), pkg_src.dst_dir, ~[]); + pkg_src.build(&default_ctxt(sysroot), ~[]); } @@ -62,12 +59,9 @@ pub fn install_lib(sysroot: @Path, debug!("sysroot = %s", sysroot.to_str()); debug!("workspace = %s", workspace.to_str()); // make a PkgSrc - let pkg_id = PkgId{ version: version, ..PkgId::new(name, &workspace)}; - let build_dir = workspace.push("build"); - let dst_dir = build_dir.push_rel(&*pkg_id.local_path); + let pkg_id = PkgId{ version: version, ..PkgId::new(name)}; let pkg_src = PkgSrc { root: workspace.clone(), - dst_dir: dst_dir.clone(), id: pkg_id.clone(), libs: ~[mk_crate(lib_path)], mains: ~[], @@ -75,13 +69,13 @@ pub fn install_lib(sysroot: @Path, benchs: ~[] }; let cx = default_ctxt(sysroot); - pkg_src.build(&cx, dst_dir, ~[]); + pkg_src.build(&cx, ~[]); cx.install_no_build(&workspace, &pkg_id); } pub fn install_exe(sysroot: @Path, workspace: Path, name: ~str, version: Version) { default_ctxt(sysroot).install(&workspace, &PkgId{ version: version, - ..PkgId::new(name, &workspace)}); + ..PkgId::new(name)}); } diff --git a/src/librustpkg/context.rs b/src/librustpkg/context.rs index 230a0f915ac..f051be25f26 100644 --- a/src/librustpkg/context.rs +++ b/src/librustpkg/context.rs @@ -12,6 +12,7 @@ use std::hashmap::HashMap; +use std::os; pub struct Ctx { // Sysroot -- if this is None, uses rustc filesearch's @@ -23,3 +24,26 @@ pub struct Ctx { // though I'm not sure why the value is a bool dep_cache: @mut HashMap<~str, bool>, } + +impl Ctx { + /// Debugging + pub fn sysroot_opt_str(&self) -> ~str { + match self.sysroot_opt { + None => ~"[none]", + Some(p) => p.to_str() + } + } +} + +/// We assume that if ../../rustc exists, then we're running +/// rustpkg from a Rust target directory. This is part of a +/// kludgy hack used to adjust the sysroot. +pub fn in_target(sysroot_opt: Option<@Path>) -> bool { + match sysroot_opt { + None => false, + Some(p) => { + debug!("Checking whether %s is in target", p.to_str()); + os::path_is_dir(&p.pop().pop().push("rustc")) + } + } +} diff --git a/src/librustpkg/installed_packages.rs b/src/librustpkg/installed_packages.rs index cec64f36947..7c3cde65517 100644 --- a/src/librustpkg/installed_packages.rs +++ b/src/librustpkg/installed_packages.rs @@ -10,6 +10,7 @@ // Listing installed packages +use rustc::metadata::filesearch::rust_path; use path_util::*; use std::os; @@ -20,21 +21,46 @@ pub fn list_installed_packages(f: &fn(&PkgId) -> bool) -> bool { for exec in binfiles.iter() { let exec_path = Path(*exec).filestem(); do exec_path.iter().advance |s| { - f(&PkgId::new(*s, p)) + f(&PkgId::new(*s)) }; } let libfiles = os::list_dir(&p.push("lib")); for lib in libfiles.iter() { - debug!("Full name: %s", *lib); - let lib_path = Path(*lib).filestem(); - do lib_path.iter().advance |s| { - f(&PkgId::new(*s, p)) - }; - } + let lib = Path(*lib); + debug!("Full name: %s", lib.to_str()); + match has_library(&lib) { + Some(basename) => { + debug!("parent = %s, child = %s", + p.push("lib").to_str(), lib.to_str()); + let rel_p = p.push("lib/").get_relative_to(&lib); + debug!("Rel: %s", rel_p.to_str()); + let rel_path = rel_p.push(basename).to_str(); + debug!("Rel name: %s", rel_path); + f(&PkgId::new(rel_path)); + } + None => () + } + }; } true } +pub fn has_library(p: &Path) -> Option<~str> { + let files = os::list_dir(p); + for q in files.iter() { + let as_path = Path(*q); + if as_path.filetype() == Some(os::consts::DLL_SUFFIX.to_owned()) { + let stuff : ~str = as_path.filestem().expect("has_library: weird path"); + let mut stuff2 = stuff.split_str_iter(&"-"); + let stuff3: ~[&str] = stuff2.collect(); + // argh + let chars_to_drop = os::consts::DLL_PREFIX.len(); + return Some(stuff3[0].slice(chars_to_drop, stuff3[0].len()).to_owned()); + } + } + None +} + pub fn package_is_installed(p: &PkgId) -> bool { let mut is_installed = false; do list_installed_packages() |installed| { @@ -44,4 +70,4 @@ pub fn package_is_installed(p: &PkgId) -> bool { false }; is_installed -} \ No newline at end of file +} diff --git a/src/librustpkg/package_id.rs b/src/librustpkg/package_id.rs index e1cf5b1fd35..e3b3252587a 100644 --- a/src/librustpkg/package_id.rs +++ b/src/librustpkg/package_id.rs @@ -8,33 +8,37 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use package_path::{RemotePath, LocalPath, normalize, hash}; use version::{try_getting_version, try_getting_local_version, Version, NoVersion, split_version}; +use std::rt::io::Writer; +use std::hash::Streaming; +use std::hash; /// 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 PkgId { - /// Remote path: for example, github.com/mozilla/quux-whatever - remote_path: RemotePath, - /// Local path: for example, /home/quux/github.com/mozilla/quux_whatever - /// Note that '-' normalizes to '_' when mapping a remote path - /// onto a local path - /// Also, this will change when we implement #6407, though we'll still - /// need to keep track of separate local and remote paths - local_path: LocalPath, - /// Short name. This is the local path's filestem, but we store it + /// 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 PkgId { fn eq(&self, p: &PkgId) -> bool { - *p.local_path == *self.local_path && p.version == self.version + p.path == self.path && p.version == self.version } fn ne(&self, p: &PkgId) -> bool { !(self.eq(p)) @@ -42,10 +46,7 @@ impl Eq for PkgId { } impl PkgId { - // The PkgId constructor takes a Path argument so as - // to be able to infer the version if the path refers - // to a local git repository - pub fn new(s: &str, work_dir: &Path) -> PkgId { + pub fn new(s: &str) -> PkgId { use conditions::bad_pkg_id::cond; let mut given_version = None; @@ -63,51 +64,64 @@ impl PkgId { } }; - let p = Path(s); - if p.is_absolute { - return cond.raise((p, ~"absolute pkgid")); + let path = Path(s); + if path.is_absolute { + return cond.raise((path, ~"absolute pkgid")); } - if p.components.len() < 1 { - return cond.raise((p, ~"0-length pkgid")); + if path.components.len() < 1 { + return cond.raise((path, ~"0-length pkgid")); } - let remote_path = RemotePath(p); - let local_path = normalize(remote_path.clone()); - let short_name = local_path.clone().filestem().expect(fmt!("Strange path! %s", s)); + let short_name = path.clone().filestem().expect(fmt!("Strange path! %s", s)); let version = match given_version { Some(v) => v, - None => match try_getting_local_version(&work_dir.push_rel(&*local_path)) { + None => match try_getting_local_version(&path) { Some(v) => v, - None => match try_getting_version(&remote_path) { + None => match try_getting_version(&path) { Some(v) => v, None => NoVersion } } }; - debug!("local_path = %s, remote_path = %s", local_path.to_str(), remote_path.to_str()); + debug!("path = %s", path.to_str()); PkgId { - local_path: local_path, - remote_path: remote_path, + path: path, short_name: short_name, version: version } } pub fn hash(&self) -> ~str { - fmt!("%s-%s-%s", self.remote_path.to_str(), - hash(self.remote_path.to_str() + self.version.to_str()), + fmt!("%s-%s-%s", self.path.to_str(), + hash(self.path.to_str() + self.version.to_str()), self.version.to_str()) } pub fn short_name_with_version(&self) -> ~str { fmt!("%s%s", self.short_name, self.version.to_str()) } + + /// True if the ID has multiple components + pub fn is_complex(&self) -> bool { + self.short_name != self.path.to_str() + } } impl ToStr for PkgId { fn to_str(&self) -> ~str { // should probably use the filestem and not the whole path - fmt!("%s-%s", self.local_path.to_str(), self.version.to_str()) + fmt!("%s-%s", self.path.to_str(), 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/package_path.rs b/src/librustpkg/package_path.rs deleted file mode 100644 index 4ba9c8066e4..00000000000 --- a/src/librustpkg/package_path.rs +++ /dev/null @@ -1,68 +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. - -// rustpkg utilities having to do with local and remote paths - -use std::clone::Clone; -use std::hash::Streaming; -use std::hash; -use std::option::Some; -use std::path::Path; -use std::rt::io::Writer; - -/// Wrappers to prevent local and remote paths from getting confused -/// (These will go away after #6407) -pub struct RemotePath (Path); - -impl Clone for RemotePath { - fn clone(&self) -> RemotePath { - RemotePath((**self).clone()) - } -} - -pub struct LocalPath (Path); - -impl Clone for LocalPath { - fn clone(&self) -> LocalPath { - LocalPath((**self).clone()) - } -} - - -// normalize should be the only way to construct a LocalPath -// (though this isn't enforced) -/// Replace all occurrences of '-' in the stem part of path with '_' -/// This is because we treat rust-foo-bar-quux and rust_foo_bar_quux -/// as the same name -pub fn normalize(p_: RemotePath) -> LocalPath { - let RemotePath(p) = p_; - match p.filestem() { - None => LocalPath(p), - Some(st) => { - let replaced = st.replace("-", "_"); - if replaced != st { - LocalPath(p.with_filestem(replaced)) - } - else { - LocalPath(p) - } - } - } -} - -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/package_source.rs b/src/librustpkg/package_source.rs index bbe35ee5004..ff485342fbe 100644 --- a/src/librustpkg/package_source.rs +++ b/src/librustpkg/package_source.rs @@ -11,7 +11,7 @@ use target::*; use package_id::PkgId; use std::path::Path; -use std::{os, str}; +use std::os; use context::*; use crate::Crate; use messages::*; @@ -23,7 +23,6 @@ use util::compile_crate; // This contains a list of files found in the source workspace. pub struct PkgSrc { root: Path, // root of where the package source code lives - dst_dir: Path, // directory where we will put the compiled output id: PkgId, libs: ~[Crate], mains: ~[Crate], @@ -37,11 +36,9 @@ condition! { impl PkgSrc { - pub fn new(src_dir: &Path, dst_dir: &Path, - id: &PkgId) -> PkgSrc { + pub fn new(src_dir: &Path, id: &PkgId) -> PkgSrc { PkgSrc { root: (*src_dir).clone(), - dst_dir: (*dst_dir).clone(), id: (*id).clone(), libs: ~[], mains: ~[], @@ -54,12 +51,11 @@ impl PkgSrc { fn check_dir(&self) -> Path { use conditions::nonexistent_package::cond; - debug!("Pushing onto root: %s | %s", self.id.remote_path.to_str(), - self.root.to_str()); + debug!("Pushing onto root: %s | %s", self.id.path.to_str(), self.root.to_str()); let dir; let dirs = pkgid_src_in_workspace(&self.id, &self.root); debug!("Checking dirs: %?", dirs); - let path = dirs.iter().find_(|&d| os::path_exists(d)); + let path = dirs.iter().find(|&d| os::path_exists(d)); match path { Some(d) => dir = (*d).clone(), None => dir = match self.fetch_git() { @@ -89,18 +85,18 @@ impl PkgSrc { os::remove_dir_recursive(&local); debug!("Checking whether %s exists locally. Cwd = %s, does it? %?", - self.id.local_path.to_str(), + self.id.path.to_str(), os::getcwd().to_str(), - os::path_exists(&*self.id.local_path)); + os::path_exists(&self.id.path)); - if os::path_exists(&*self.id.local_path) { + if os::path_exists(&self.id.path) { debug!("%s exists locally! Cloning it into %s", - self.id.local_path.to_str(), local.to_str()); - git_clone(&*self.id.local_path, &local, &self.id.version); + self.id.path.to_str(), local.to_str()); + git_clone(&self.id.path, &local, &self.id.version); return Some(local); } - let url = fmt!("https://%s", self.id.remote_path.to_str()); + let url = fmt!("https://%s", self.id.path.to_str()); note(fmt!("Fetching package: git clone %s %s [version=%s]", url, local.to_str(), self.id.version.to_str())); if git_clone_general(url, &local, &self.id.version) { @@ -125,25 +121,8 @@ impl PkgSrc { } /// True if the given path's stem is self's pkg ID's stem - /// or if the pkg ID's stem is <rust-foo> and the given path's - /// stem is foo - /// Requires that dashes in p have already been normalized to - /// underscores fn stem_matches(&self, p: &Path) -> bool { - let self_id = self.id.local_path.filestem(); - if self_id == p.filestem() { - return true; - } - else { - for pth in self_id.iter() { - if pth.starts_with("rust_") // because p is already normalized - && match p.filestem() { - Some(s) => str::eq_slice(s, pth.slice(5, pth.len())), - None => false - } { return true; } - } - } - false + p.filestem().map_default(false, |p| { p == &self.id.short_name }) } fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) { @@ -164,7 +143,7 @@ impl PkgSrc { let dir = self.check_dir(); debug!("Called check_dir, I'm in %s", dir.to_str()); let prefix = dir.components.len(); - debug!("Matching against %?", self.id.local_path.filestem()); + debug!("Matching against %?", self.id.short_name); do os::walk_dir(&dir) |pth| { match pth.filename() { Some(~"lib.rs") => PkgSrc::push_crate(&mut self.libs, @@ -202,7 +181,6 @@ impl PkgSrc { fn build_crates(&self, ctx: &Ctx, - dst_dir: &Path, src_dir: &Path, crates: &[Crate], cfgs: &[~str], @@ -210,12 +188,13 @@ impl PkgSrc { for crate in crates.iter() { let path = &src_dir.push_rel(&crate.file).normalize(); note(fmt!("build_crates: compiling %s", path.to_str())); - note(fmt!("build_crates: destination dir is %s", dst_dir.to_str())); + note(fmt!("build_crates: using as workspace %s", self.root.to_str())); let result = compile_crate(ctx, &self.id, path, - dst_dir, + // compile_crate wants the workspace + &self.root, crate.flags, crate.cfgs + cfgs, false, @@ -229,15 +208,15 @@ impl PkgSrc { } } - pub fn build(&self, ctx: &Ctx, dst_dir: Path, cfgs: ~[~str]) { + pub fn build(&self, ctx: &Ctx, cfgs: ~[~str]) { let dir = self.check_dir(); debug!("Building libs in %s", dir.to_str()); - self.build_crates(ctx, &dst_dir, &dir, self.libs, cfgs, Lib); + self.build_crates(ctx, &dir, self.libs, cfgs, Lib); debug!("Building mains"); - self.build_crates(ctx, &dst_dir, &dir, self.mains, cfgs, Main); + self.build_crates(ctx, &dir, self.mains, cfgs, Main); debug!("Building tests"); - self.build_crates(ctx, &dst_dir, &dir, self.tests, cfgs, Test); + self.build_crates(ctx, &dir, self.tests, cfgs, Test); debug!("Building benches"); - self.build_crates(ctx, &dst_dir, &dir, self.benchs, cfgs, Bench); + self.build_crates(ctx, &dir, self.benchs, cfgs, Bench); } } diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index fdfa29b2f83..bbe84b2ecac 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -10,65 +10,17 @@ // rustpkg utilities having to do with paths and directories -pub use package_path::{RemotePath, LocalPath, normalize}; pub use package_id::PkgId; pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install}; pub use version::{Version, NoVersion, split_version_general}; +pub use rustc::metadata::filesearch::rust_path; + use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use std::os::mkdir_recursive; use std::os; -use std::iterator::IteratorUtil; use messages::*; use package_id::*; -fn push_if_exists(vec: &mut ~[Path], p: &Path) { - let maybe_dir = p.push(".rust"); - if os::path_exists(&maybe_dir) { - vec.push(maybe_dir); - } -} - -#[cfg(windows)] -static PATH_ENTRY_SEPARATOR: &'static str = ";"; -#[cfg(not(windows))] -static PATH_ENTRY_SEPARATOR: &'static str = ":"; - -/// Returns RUST_PATH as a string, without default paths added -pub fn get_rust_path() -> Option<~str> { - os::getenv("RUST_PATH") -} - -/// Returns the value of RUST_PATH, as a list -/// of Paths. Includes default entries for, if they exist: -/// $HOME/.rust -/// DIR/.rust for any DIR that's the current working directory -/// or an ancestor of it -pub fn rust_path() -> ~[Path] { - let mut env_rust_path: ~[Path] = match get_rust_path() { - Some(env_path) => { - let env_path_components: ~[&str] = - env_path.split_str_iter(PATH_ENTRY_SEPARATOR).collect(); - env_path_components.map(|&s| Path(s)) - } - None => ~[] - }; - debug!("RUST_PATH entries from environment: %?", env_rust_path); - let cwd = os::getcwd(); - // now add in default entries - env_rust_path.push(cwd.clone()); - do cwd.each_parent() |p| { push_if_exists(&mut env_rust_path, p) }; - let h = os::homedir(); - // Avoid adding duplicates - // could still add dups if someone puts one of these in the RUST_PATH - // manually, though... - for hdir in h.iter() { - if !(cwd.is_ancestor_of(hdir) || hdir.is_ancestor_of(&cwd)) { - push_if_exists(&mut env_rust_path, hdir); - } - } - env_rust_path -} - pub fn default_workspace() -> Path { let p = rust_path(); if p.is_empty() { @@ -99,39 +51,39 @@ pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, U_RWX) } /// pkgid's short name pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { let src_dir = workspace.push("src"); - let dirs = os::list_dir(&src_dir); - for p in dirs.iter() { - let p = Path((*p).clone()); + let mut found = false; + do os::walk_dir(&src_dir) |p| { debug!("=> p = %s", p.to_str()); - if !os::path_is_dir(&src_dir.push_rel(&p)) { - loop; - } - debug!("p = %s, remote_path = %s", p.to_str(), pkgid.remote_path.to_str()); + if os::path_is_dir(p) { + debug!("p = %s, path = %s [%s]", p.to_str(), pkgid.path.to_str(), + src_dir.push_rel(&pkgid.path).to_str()); - if p == *pkgid.remote_path { - return true; - } - else { - let pf = p.filename(); - for pf in pf.iter() { - let f_ = (*pf).clone(); - let g = f_.to_str(); - match split_version_general(g, '-') { - Some((ref might_match, ref vers)) => { - debug!("might_match = %s, vers = %s", *might_match, + if *p == src_dir.push_rel(&pkgid.path) { + found = true; + } + else { + let pf = p.filename(); + for pf in pf.iter() { + let f_ = (*pf).clone(); + let g = f_.to_str(); + match split_version_general(g, '-') { + Some((ref might_match, ref vers)) => { + debug!("might_match = %s, vers = %s", *might_match, vers.to_str()); - if *might_match == pkgid.short_name - && (*vers == pkgid.version || pkgid.version == NoVersion) - { - return true; + if *might_match == pkgid.short_name + && (*vers == pkgid.version || pkgid.version == NoVersion) + { + found = true; + } } - } - None => () + None => () + } } } } - } - false + true + }; + found } /// Returns a list of possible directories @@ -141,9 +93,9 @@ pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { pub fn pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> ~[Path] { let mut results = ~[]; let result = workspace.push("src").push(fmt!("%s-%s", - pkgid.local_path.to_str(), pkgid.version.to_str())); + pkgid.path.to_str(), pkgid.version.to_str())); results.push(result); - results.push(workspace.push("src").push_rel(&*pkgid.remote_path)); + results.push(workspace.push("src").push_rel(&pkgid.path)); results } @@ -163,7 +115,7 @@ pub fn first_pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<P pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> { let mut result = workspace.push("build"); // should use a target-specific subdirectory - result = mk_output_path(Main, Build, pkgid, &result); + result = mk_output_path(Main, Build, pkgid, result); debug!("built_executable_in_workspace: checking whether %s exists", result.to_str()); if os::path_exists(&result) { @@ -191,7 +143,7 @@ pub fn built_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Option<Path> { let mut result = workspace.push("build"); // should use a target-specific subdirectory - result = mk_output_path(what, Build, pkgid, &result); + result = mk_output_path(what, Build, pkgid, result); debug!("output_in_workspace: checking whether %s exists", result.to_str()); if os::path_exists(&result) { @@ -206,14 +158,12 @@ fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Opt /// Figure out what the library name for <pkgid> in <workspace>'s build /// directory is, and if the file exists, return it. pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> { - library_in_workspace(&pkgid.local_path, pkgid.short_name, - Build, workspace, "build") + library_in_workspace(&pkgid.path, pkgid.short_name, Build, workspace, "build") } /// Does the actual searching stuff pub fn installed_library_in_workspace(short_name: &str, workspace: &Path) -> Option<Path> { - library_in_workspace(&normalize(RemotePath(Path(short_name))), - short_name, Install, workspace, "lib") + library_in_workspace(&Path(short_name), short_name, Install, workspace, "lib") } @@ -221,7 +171,7 @@ pub fn installed_library_in_workspace(short_name: &str, workspace: &Path) -> Opt /// don't know the entire package ID. /// `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: &LocalPath, short_name: &str, where: Target, +pub fn library_in_workspace(path: &Path, short_name: &str, where: Target, workspace: &Path, prefix: &str) -> Option<Path> { debug!("library_in_workspace: checking whether a library named %s exists", short_name); @@ -233,7 +183,7 @@ pub fn library_in_workspace(path: &LocalPath, short_name: &str, where: Target, prefix = %s", short_name, where, workspace.to_str(), prefix); let dir_to_search = match where { - Build => workspace.push(prefix).push_rel(&**path), + Build => workspace.push(prefix).push_rel(path), Install => workspace.push(prefix) }; debug!("Listing directory %s", dir_to_search.to_str()); @@ -349,7 +299,7 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, // Artifacts in the build directory live in a package-ID-specific subdirectory, // but installed ones don't. let result = match where { - Build => workspace.push(subdir).push_rel(&*pkgid.local_path), + Build => workspace.push(subdir).push_rel(&pkgid.path), _ => workspace.push(subdir) }; if !os::path_exists(&result) && !mkdir_recursive(&result, U_RWX) { @@ -357,7 +307,7 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, create the %s dir (pkgid=%s, workspace=%s, what=%?, where=%?", subdir, pkgid.to_str(), workspace.to_str(), what, where))); } - mk_output_path(what, where, pkgid, &result) + mk_output_path(what, where, pkgid, result) } /// Return the directory for <pkgid>'s build artifacts in <workspace>. @@ -368,7 +318,7 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { let mut result = workspace.push("build"); // n.b. Should actually use a target-specific // subdirectory of build/ - result = result.push_rel(&*pkgid.local_path); + result = result.push_rel(&pkgid.path); if os::path_exists(&result) || os::mkdir_recursive(&result, U_RWX) { result } @@ -380,19 +330,16 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, 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: &PkgId, workspace: &Path) -> Path { + pkg_id: &PkgId, workspace: Path) -> Path { let short_name_with_version = fmt!("%s-%s", pkg_id.short_name, pkg_id.version.to_str()); // 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 => { - // bad copy, but I just couldn't make the borrow checker happy - (*workspace).clone() - } + Install => workspace, // and if we're just building, it goes in a package-specific subdir - Build => workspace.push_rel(&*pkg_id.local_path) + Build => workspace.push_rel(&pkg_id.path) }; debug!("[%?:%?] mk_output_path: short_name = %s, path = %s", what, where, if what == Lib { short_name_with_version.clone() } else { pkg_id.short_name.clone() }, diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs index fa03a5bbfc2..3ae2ad3751f 100644 --- a/src/librustpkg/rustpkg.rs +++ b/src/librustpkg/rustpkg.rs @@ -33,12 +33,13 @@ use std::hashmap::HashMap; use rustc::driver::{driver, session}; use rustc::metadata::filesearch; +use rustc::metadata::filesearch::rust_path; use extra::{getopts}; use syntax::{ast, diagnostic}; use util::*; use messages::*; use path_util::{build_pkg_id_in_workspace, first_pkgid_src_in_workspace}; -use path_util::{U_RWX, rust_path, in_rust_path}; +use path_util::{U_RWX, in_rust_path}; use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace}; use path_util::{target_executable_in_workspace, target_library_in_workspace}; use source_control::is_git_dir; @@ -54,7 +55,6 @@ mod crate; mod installed_packages; mod messages; mod package_id; -mod package_path; mod package_source; mod path_util; mod search; @@ -138,35 +138,28 @@ impl<'self> PkgScript<'self> { let crate = util::ready_crate(sess, self.crate); debug!("Building output filenames with script name %s", driver::source_name(&self.input)); - match filesearch::get_rustpkg_sysroot() { - Ok(r) => { - let root = r.pop().pop().pop().pop(); // :-\ - debug!("Root is %s, calling compile_rest", root.to_str()); - let exe = self.build_dir.push(~"pkg" + util::exe_suffix()); - util::compile_crate_from_input(&self.input, - &self.build_dir, - sess, - crate); - debug!("Running program: %s %s %s %s", exe.to_str(), - sysroot.to_str(), root.to_str(), "install"); - // FIXME #7401 should support commands besides `install` - let status = run::process_status(exe.to_str(), [sysroot.to_str(), ~"install"]); - if status != 0 { - return (~[], status); - } - else { - debug!("Running program (configs): %s %s %s", - exe.to_str(), root.to_str(), "configs"); - let output = run::process_output(exe.to_str(), [root.to_str(), ~"configs"]); - // Run the configs() function to get the configs - let cfgs = str::from_bytes_slice(output.output).word_iter() - .transform(|w| w.to_owned()).collect(); - (cfgs, output.status) - } - } - Err(e) => { - fail!("Running package script, couldn't find rustpkg sysroot (%s)", e) - } + let root = filesearch::get_or_default_sysroot().pop().pop(); // :-\ + debug!("Root is %s, calling compile_rest", root.to_str()); + let exe = self.build_dir.push(~"pkg" + util::exe_suffix()); + util::compile_crate_from_input(&self.input, + &self.build_dir, + sess, + crate); + debug!("Running program: %s %s %s %s", exe.to_str(), + sysroot.to_str(), root.to_str(), "install"); + // FIXME #7401 should support commands besides `install` + let status = run::process_status(exe.to_str(), [sysroot.to_str(), ~"install"]); + if status != 0 { + return (~[], status); + } + else { + debug!("Running program (configs): %s %s %s", + exe.to_str(), root.to_str(), "configs"); + let output = run::process_output(exe.to_str(), [root.to_str(), ~"configs"]); + // Run the configs() function to get the configs + let cfgs = str::from_bytes_slice(output.output).word_iter() + .map(|w| w.to_owned()).collect(); + (cfgs, output.status) } } @@ -205,7 +198,7 @@ impl CtxMethods for Ctx { else { // The package id is presumed to be the first command-line // argument - let pkgid = PkgId::new(args[0].clone(), &os::getcwd()); + let pkgid = PkgId::new(args[0].clone()); do each_pkg_parent_workspace(&pkgid) |workspace| { debug!("found pkg %s in workspace %s, trying to build", pkgid.to_str(), workspace.to_str()); @@ -228,7 +221,7 @@ impl CtxMethods for Ctx { else { // The package id is presumed to be the first command-line // argument - let pkgid = PkgId::new(args[0].clone(), &os::getcwd()); + let pkgid = PkgId::new(args[0].clone()); let cwd = os::getcwd(); self.clean(&cwd, &pkgid); // tjc: should use workspace, not cwd } @@ -254,13 +247,12 @@ impl CtxMethods for Ctx { else { // The package id is presumed to be the first command-line // argument - let pkgid = PkgId::new(args[0], &os::getcwd()); + let pkgid = PkgId::new(args[0]); let workspaces = pkg_parent_workspaces(&pkgid); if workspaces.is_empty() { let rp = rust_path(); assert!(!rp.is_empty()); - let src = PkgSrc::new(&rp[0], &build_pkg_id_in_workspace(&pkgid, &rp[0]), - &pkgid); + let src = PkgSrc::new(&rp[0], &pkgid); src.fetch_git(); self.install(&rp[0], &pkgid); } @@ -275,7 +267,7 @@ impl CtxMethods for Ctx { "list" => { io::println("Installed packages:"); do installed_packages::list_installed_packages |pkg_id| { - println(pkg_id.local_path.to_str()); + println(pkg_id.path.to_str()); true }; } @@ -294,7 +286,7 @@ impl CtxMethods for Ctx { return usage::uninstall(); } - let pkgid = PkgId::new(args[0], &os::getcwd()); // ?? + let pkgid = PkgId::new(args[0]); if !installed_packages::package_is_installed(&pkgid) { warn(fmt!("Package %s doesn't seem to be installed! Doing nothing.", args[0])); return; @@ -329,20 +321,18 @@ impl CtxMethods for Ctx { fn build(&self, workspace: &Path, pkgid: &PkgId) { debug!("build: workspace = %s (in Rust path? %? is git dir? %? \ pkgid = %s", workspace.to_str(), - in_rust_path(workspace), is_git_dir(&workspace.push_rel(&*pkgid.local_path)), + in_rust_path(workspace), is_git_dir(&workspace.push_rel(&pkgid.path)), pkgid.to_str()); let src_dir = first_pkgid_src_in_workspace(pkgid, workspace); - let build_dir = build_pkg_id_in_workspace(pkgid, workspace); - debug!("Destination dir = %s", build_dir.to_str()); // 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 debug!("%? %? %s", in_rust_path(workspace), - is_git_dir(&workspace.push_rel(&*pkgid.local_path)), + is_git_dir(&workspace.push_rel(&pkgid.path)), workspace.to_str()); - if !in_rust_path(workspace) && is_git_dir(&workspace.push_rel(&*pkgid.local_path)) { - let out_dir = default_workspace().push("src").push_rel(&*pkgid.local_path); - source_control::git_clone(&workspace.push_rel(&*pkgid.local_path), + if !in_rust_path(workspace) && is_git_dir(&workspace.push_rel(&pkgid.path)) { + let out_dir = default_workspace().push("src").push_rel(&pkgid.path); + source_control::git_clone(&workspace.push_rel(&pkgid.path), &out_dir, &pkgid.version); let default_ws = default_workspace(); debug!("Calling build recursively with %? and %?", default_ws.to_str(), @@ -351,7 +341,7 @@ impl CtxMethods for Ctx { } // Create the package source - let mut src = PkgSrc::new(workspace, &build_dir, pkgid); + let mut src = PkgSrc::new(workspace, pkgid); debug!("Package src = %?", src); // Is there custom build logic? If so, use it @@ -385,7 +375,7 @@ impl CtxMethods for Ctx { // Find crates inside the workspace src.find_crates(); // Build it! - src.build(self, build_dir, cfgs); + src.build(self, cfgs); } } @@ -444,6 +434,7 @@ impl CtxMethods for Ctx { for lib in maybe_library.iter() { let target_lib = target_lib.clone().expect(fmt!("I built %s but apparently \ didn't install it!", lib.to_str())); + let target_lib = target_lib.pop().push(lib.filename().expect("weird target lib")); debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str()); if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) && os::copy_file(lib, &target_lib)) { @@ -518,9 +509,7 @@ pub fn main() { }; } - let sroot = match filesearch::get_rustpkg_sysroot() { - Ok(r) => Some(@r.pop().pop()), Err(_) => None - }; + let sroot = Some(@filesearch::get_or_default_sysroot()); debug!("Using sysroot: %?", sroot); Ctx { sysroot_opt: sroot, // Currently, only tests override this diff --git a/src/librustpkg/source_control.rs b/src/librustpkg/source_control.rs index e3b796a03bb..caa004a53b2 100644 --- a/src/librustpkg/source_control.rs +++ b/src/librustpkg/source_control.rs @@ -10,7 +10,7 @@ // Utils for working with version control repositories. Just git right now. -use std::{os, run, str}; +use std::{io, os, run, str}; use std::run::{ProcessOutput, ProcessOptions, Process}; use version::*; @@ -19,14 +19,37 @@ pub fn git_clone(source: &Path, target: &Path, v: &Version) { assert!(os::path_is_dir(source)); assert!(is_git_dir(source)); if !os::path_exists(target) { - debug!("Running: git clone %s %s", source.to_str(), - target.to_str()); - assert!(git_clone_general(source.to_str(), target, v)); + debug!("Running: git clone %s %s", source.to_str(), target.to_str()); + let outp = run::process_output("git", [~"clone", source.to_str(), target.to_str()]); + if outp.status != 0 { + io::println(str::from_bytes_owned(outp.output.clone())); + io::println(str::from_bytes_owned(outp.error)); + fail!("Couldn't `git clone` %s", source.to_str()); + } + else { + match v { + &ExactRevision(ref s) => { + debug!("`Running: git --work-tree=%s --git-dir=%s checkout %s", + *s, target.to_str(), target.push(".git").to_str()); + let outp = run::process_output("git", + [fmt!("--work-tree=%s", target.to_str()), + fmt!("--git-dir=%s", target.push(".git").to_str()), + ~"checkout", fmt!("%s", *s)]); + if outp.status != 0 { + io::println(str::from_bytes_owned(outp.output.clone())); + io::println(str::from_bytes_owned(outp.error)); + fail!("Couldn't `git checkout %s` in %s", + *s, target.to_str()); + } + } + _ => () + } + } } else { - // Pull changes - // Note that this ignores tags, which is probably wrong. There are no tests for - // it, though. + // 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); debug!("Running: git --work-tree=%s --git-dir=%s pull --no-edit %s", target.to_str(), target.push(".git").to_str(), source.to_str()); let outp = run::process_output("git", [fmt!("--work-tree=%s", target.to_str()), diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 9fea8662129..121dcf40150 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -12,11 +12,10 @@ use context::Ctx; use std::hashmap::HashMap; -use std::{io, libc, os, result, run, str}; +use std::{io, libc, os, run, str}; use extra::tempfile::mkdtemp; use std::run::ProcessOutput; use installed_packages::list_installed_packages; -use package_path::*; use package_id::{PkgId}; use version::{ExactRevision, NoVersion, Version, Tagged}; use path_util::{target_executable_in_workspace, target_library_in_workspace, @@ -24,7 +23,9 @@ use path_util::{target_executable_in_workspace, target_library_in_workspace, make_dir_rwx, U_RWX, library_in_workspace, built_bench_in_workspace, built_test_in_workspace, built_library_in_workspace, built_executable_in_workspace, - installed_library_in_workspace, rust_path}; + installed_library_in_workspace}; +use rustc::metadata::filesearch::rust_path; +use rustc::driver::driver::host_triple; use target::*; /// Returns the last-modified date as an Option @@ -42,31 +43,25 @@ fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx { fn fake_pkg() -> PkgId { let sn = ~"bogus"; - let remote = RemotePath(Path(sn)); PkgId { - local_path: normalize(remote.clone()), - remote_path: remote, + path: Path(sn), short_name: sn, version: NoVersion } } fn git_repo_pkg() -> PkgId { - let remote = RemotePath(Path("mockgithub.com/catamorphism/test-pkg")); PkgId { - local_path: normalize(remote.clone()), - remote_path: remote, - short_name: ~"test_pkg", + path: Path("mockgithub.com/catamorphism/test-pkg"), + short_name: ~"test-pkg", version: NoVersion } } fn git_repo_pkg_with_tag(a_tag: ~str) -> PkgId { - let remote = RemotePath(Path("mockgithub.com/catamorphism/test-pkg")); PkgId { - local_path: normalize(remote.clone()), - remote_path: remote, - short_name: ~"test_pkg", + path: Path("mockgithub.com/catamorphism/test-pkg"), + short_name: ~"test-pkg", version: Tagged(a_tag) } } @@ -76,13 +71,13 @@ fn writeFile(file_path: &Path, contents: &str) { out.write_line(contents); } -fn mk_empty_workspace(short_name: &LocalPath, version: &Version) -> Path { +fn mk_empty_workspace(short_name: &Path, version: &Version) -> Path { let workspace_dir = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir"); mk_workspace(&workspace_dir, short_name, version); workspace_dir } -fn mk_workspace(workspace: &Path, short_name: &LocalPath, version: &Version) -> Path { +fn mk_workspace(workspace: &Path, short_name: &Path, version: &Version) -> Path { // include version number in directory name let package_dir = workspace.push("src").push(fmt!("%s-%s", short_name.to_str(), version.to_str())); @@ -90,7 +85,7 @@ fn mk_workspace(workspace: &Path, short_name: &LocalPath, version: &Version) -> package_dir } -fn mk_temp_workspace(short_name: &LocalPath, version: &Version) -> Path { +fn mk_temp_workspace(short_name: &Path, version: &Version) -> Path { let package_dir = mk_empty_workspace(short_name, version).push("src").push(fmt!("%s-%s", short_name.to_str(), @@ -116,6 +111,22 @@ fn mk_temp_workspace(short_name: &LocalPath, version: &Version) -> Path { package_dir } +fn run_git(args: &[~str], env: Option<~[(~str, ~str)]>, cwd: &Path, err_msg: &str) { + let cwd = (*cwd).clone(); + let mut prog = run::Process::new("git", args, run::ProcessOptions { + env: env.map(|v| v.slice(0, v.len())), + dir: Some(&cwd), + in_fd: None, + out_fd: None, + err_fd: None + }); + let rslt = prog.finish_with_output(); + if rslt.status != 0 { + fail!("%s [git returned %?, output = %s, error = %s]", err_msg, + rslt.status, str::from_bytes(rslt.output), str::from_bytes(rslt.error)); + } +} + /// Should create an empty git repo in p, relative to the tmp dir, and return the new /// absolute path fn init_git_repo(p: &Path) -> Path { @@ -125,37 +136,14 @@ fn init_git_repo(p: &Path) -> Path { let work_dir_for_opts = work_dir.clone(); assert!(os::mkdir_recursive(&work_dir, U_RWX)); debug!("Running: git init in %s", work_dir.to_str()); - let opts = run::ProcessOptions { - env: None, - dir: Some(&work_dir_for_opts), - in_fd: None, - out_fd: None, - err_fd: None - }; - let mut prog = run::Process::new("git", [~"init"], opts); - let mut output = prog.finish_with_output(); - if output.status == 0 { - // Add stuff to the dir so that git tag succeeds - writeFile(&work_dir.push("README"), ""); - prog = run::Process::new("git", [~"add", ~"README"], opts); - output = prog.finish_with_output(); - if output.status == 0 { - prog = run::Process::new("git", [~"commit", ~"-m", ~"whatever"], opts); - output = prog.finish_with_output(); - if output.status == 0 { - tmp - } - else { - fail!("Couldn't commit in %s", work_dir.to_str()); - } - } - else { - fail!("Couldn't add in %s", work_dir.to_str()); - } - } - else { - fail!("Couldn't initialize git repository in %s", work_dir.to_str()) - } + let ws = work_dir.to_str(); + run_git([~"init"], None, &work_dir_for_opts, + fmt!("Couldn't initialize git repository in %s", ws)); + // Add stuff to the dir so that git tag succeeds + writeFile(&work_dir.push("README"), ""); + run_git([~"add", ~"README"], None, &work_dir_for_opts, fmt!("Couldn't add in %s", ws)); + git_commit(&work_dir_for_opts, ~"whatever"); + tmp } fn add_all_and_commit(repo: &Path) { @@ -164,51 +152,20 @@ fn add_all_and_commit(repo: &Path) { } fn git_commit(repo: &Path, msg: ~str) { - let mut prog = run::Process::new("git", [~"commit", ~"-m", msg], - run::ProcessOptions { env: None, - dir: Some(repo), - in_fd: None, - out_fd: None, - err_fd: None - }); - let output = prog.finish_with_output(); - if output.status != 0 { - fail!("Couldn't commit in %s: output was %s", repo.to_str(), - str::from_bytes(output.output + output.error)) - } - + run_git([~"commit", ~"--author=tester <test@mozilla.com>", ~"-m", msg], + None, repo, fmt!("Couldn't commit in %s", repo.to_str())); } fn git_add_all(repo: &Path) { - let mut prog = run::Process::new("git", [~"add", ~"-A"], - run::ProcessOptions { env: None, - dir: Some(repo), - in_fd: None, - out_fd: None, - err_fd: None - }); - let output = prog.finish_with_output(); - if output.status != 0 { - fail!("Couldn't add all files in %s: output was %s", - repo.to_str(), str::from_bytes(output.output + output.error)) - } + run_git([~"add", ~"-A"], None, repo, fmt!("Couldn't add all files in %s", repo.to_str())); } fn add_git_tag(repo: &Path, tag: ~str) { assert!(repo.is_absolute()); git_add_all(repo); git_commit(repo, ~"whatever"); - let mut prog = run::Process::new("git", [~"tag", tag.clone()], - run::ProcessOptions { env: None, - dir: Some(repo), - in_fd: None, - out_fd: None, - err_fd: None - }); - let output = prog.finish_with_output(); - if output.status != 0 { - fail!("Couldn't add git tag %s in %s", tag, repo.to_str()) - } + run_git([~"tag", tag.clone()], None, repo, + fmt!("Couldn't add git tag %s in %s", tag, repo.to_str())); } fn is_rwx(p: &Path) -> bool { @@ -231,6 +188,25 @@ fn test_sysroot() -> Path { self_path.pop() } +// Returns the path to rustpkg +fn rustpkg_exec() -> Path { + // Ugh + let first_try = test_sysroot().push("lib").push("rustc") + .push(host_triple()).push("bin").push("rustpkg"); + if is_executable(&first_try) { + first_try + } + else { + let second_try = test_sysroot().push("bin").push("rustpkg"); + if is_executable(&second_try) { + second_try + } + else { + fail!("in rustpkg test, can't find an installed rustpkg"); + } + } +} + fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput { command_line_test_with_env(args, cwd, None) } @@ -240,8 +216,9 @@ fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput { /// Returns the process's output. fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~str)]>) -> ProcessOutput { - let cmd = test_sysroot().push("bin").push("rustpkg").to_str(); - debug!("About to run command: %? %? in %s", cmd, args, cwd.to_str()); + let cmd = rustpkg_exec().to_str(); + debug!("cd %s; %s %s", + cwd.to_str(), cmd, args.connect(" ")); assert!(os::path_is_dir(&*cwd)); let cwd = (*cwd).clone(); let mut prog = run::Process::new(cmd, args, run::ProcessOptions { @@ -263,14 +240,15 @@ So tests that use this need to check the existence of a file to make sure the command succeeded */ if output.status != 0 { - fail!("Command %s %? failed with exit code %?", - cmd, args, output.status); + fail!("Command %s %? failed with exit code %?; its output was {{{ %s }}}", + cmd, args, output.status, + str::from_bytes(output.output) + str::from_bytes(output.error)); } output } fn create_local_package(pkgid: &PkgId) -> Path { - let parent_dir = mk_temp_workspace(&pkgid.local_path, &pkgid.version); + let parent_dir = mk_temp_workspace(&pkgid.path, &pkgid.version); debug!("Created empty package dir for %s, returning %s", pkgid.to_str(), parent_dir.to_str()); parent_dir.pop().pop() } @@ -327,26 +305,26 @@ fn create_local_package_with_custom_build_hook(pkgid: &PkgId, } -fn assert_lib_exists(repo: &Path, short_name: &str, v: Version) { +fn assert_lib_exists(repo: &Path, short_name: &str, _v: Version) { // ??? version? debug!("assert_lib_exists: repo = %s, short_name = %s", repo.to_str(), short_name); - let lib = target_library_in_workspace(&(PkgId { - version: v, ..PkgId::new(short_name, repo)} - ), repo); - debug!("assert_lib_exists: checking whether %s exists", lib.to_str()); - assert!(os::path_exists(&lib)); - assert!(is_rwx(&lib)); + let lib = installed_library_in_workspace(short_name, repo); + debug!("assert_lib_exists: checking whether %? exists", lib); + assert!(lib.is_some()); + let libname = lib.get_ref(); + assert!(os::path_exists(libname)); + assert!(is_rwx(libname)); } fn assert_executable_exists(repo: &Path, short_name: &str) { debug!("assert_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name); - let exec = target_executable_in_workspace(&PkgId::new(short_name, repo), repo); + let exec = target_executable_in_workspace(&PkgId::new(short_name), repo); assert!(os::path_exists(&exec)); assert!(is_rwx(&exec)); } fn assert_built_executable_exists(repo: &Path, short_name: &str) { debug!("assert_built_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name); - let exec = built_executable_in_workspace(&PkgId::new(short_name, repo), + let exec = built_executable_in_workspace(&PkgId::new(short_name), repo).expect("assert_built_executable_exists failed"); assert!(os::path_exists(&exec)); assert!(is_rwx(&exec)); @@ -372,11 +350,11 @@ fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~ result } -// assumes short_name and local_path are one and the same -- I should fix +// assumes short_name and path are one and the same -- I should fix fn lib_output_file_name(workspace: &Path, parent: &str, short_name: &str) -> Path { debug!("lib_output_file_name: given %s and parent %s and short name %s", workspace.to_str(), parent, short_name); - library_in_workspace(&normalize(RemotePath(Path(short_name))), + library_in_workspace(&Path(short_name), short_name, Build, workspace, @@ -451,7 +429,7 @@ fn test_install_valid() { debug!("sysroot = %s", sysroot.to_str()); let ctxt = fake_ctxt(Some(@sysroot)); let temp_pkg_id = fake_pkg(); - let temp_workspace = mk_temp_workspace(&temp_pkg_id.local_path, &NoVersion).pop().pop(); + let temp_workspace = mk_temp_workspace(&temp_pkg_id.path, &NoVersion).pop().pop(); debug!("temp_workspace = %s", temp_workspace.to_str()); // should have test, bench, lib, and main ctxt.install(&temp_workspace, &temp_pkg_id); @@ -504,7 +482,7 @@ fn test_install_git() { let sysroot = test_sysroot(); debug!("sysroot = %s", sysroot.to_str()); let temp_pkg_id = git_repo_pkg(); - let repo = init_git_repo(&Path(temp_pkg_id.local_path.to_str())); + let repo = init_git_repo(&temp_pkg_id.path); let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test_pkg"); writeFile(&repo_subdir.push("main.rs"), "fn main() { let _x = (); }"); @@ -517,9 +495,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 %s in %s", - temp_pkg_id.local_path.to_str(), repo.to_str()); + temp_pkg_id.path.to_str(), repo.to_str()); // should have test, bench, lib, and main - command_line_test([~"install", temp_pkg_id.local_path.to_str()], &repo); + command_line_test([~"install", temp_pkg_id.path.to_str()], &repo); // Check that all files exist debug!("Checking for files in %s", repo.to_str()); let exec = target_executable_in_workspace(&temp_pkg_id, &repo); @@ -563,18 +541,18 @@ fn test_package_ids_must_be_relative_path_like() { */ - let whatever = PkgId::new("foo", &os::getcwd()); + let whatever = PkgId::new("foo"); assert_eq!(~"foo-0.1", whatever.to_str()); - assert!("github.com/catamorphism/test_pkg-0.1" == - PkgId::new("github.com/catamorphism/test-pkg", &os::getcwd()).to_str()); + assert!("github.com/catamorphism/test-pkg-0.1" == + PkgId::new("github.com/catamorphism/test-pkg").to_str()); do cond.trap(|(p, e)| { assert!("" == p.to_str()); assert!("0-length pkgid" == e); whatever.clone() }).inside { - let x = PkgId::new("", &os::getcwd()); + let x = PkgId::new(""); assert_eq!(~"foo-0.1", x.to_str()); } @@ -583,8 +561,7 @@ fn test_package_ids_must_be_relative_path_like() { assert!("absolute pkgid" == e); whatever.clone() }).inside { - let z = PkgId::new(os::make_absolute(&Path("foo/bar/quux")).to_str(), - &os::getcwd()); + let z = PkgId::new(os::make_absolute(&Path("foo/bar/quux")).to_str()); assert_eq!(~"foo-0.1", z.to_str()); } @@ -607,7 +584,7 @@ fn test_package_version() { "#[bench] pub fn f() { (); }"); add_git_tag(&repo_subdir, ~"0.4"); - let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version", &repo); + let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version"); match temp_pkg_id.version { ExactRevision(~"0.4") => (), _ => fail!(fmt!("test_package_version: package version was %?, expected Some(0.4)", @@ -656,7 +633,7 @@ fn test_package_request_version() { } None => false }); - let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version#0.3", &repo); + let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version#0.3"); assert!(target_executable_in_workspace(&temp_pkg_id, &repo.push(".rust")) == repo.push(".rust").push("bin").push("test_pkg_version")); @@ -696,12 +673,12 @@ fn rustpkg_library_target() { add_git_tag(&package_dir, ~"1.0"); command_line_test([~"install", ~"foo"], &foo_repo); - assert_lib_exists(&foo_repo, "foo", ExactRevision(~"1.0")); + assert_lib_exists(&foo_repo.push(".rust"), "foo", ExactRevision(~"1.0")); } #[test] fn rustpkg_local_pkg() { - let dir = create_local_package(&PkgId::new("foo", &os::getcwd())); + let dir = create_local_package(&PkgId::new("foo")); command_line_test([~"install", ~"foo"], &dir); assert_executable_exists(&dir, "foo"); } @@ -711,7 +688,7 @@ fn rustpkg_local_pkg() { #[test] #[ignore] fn package_script_with_default_build() { - let dir = create_local_package(&PkgId::new("fancy-lib", &os::getcwd())); + let dir = create_local_package(&PkgId::new("fancy-lib")); debug!("dir = %s", dir.to_str()); let source = test_sysroot().pop().pop().pop().push("src").push("librustpkg"). push("testsuite").push("pass").push("src").push("fancy-lib").push("pkg.rs"); @@ -763,7 +740,7 @@ fn rustpkg_clean_no_arg() { command_line_test([~"build"], &package_dir); assert_built_executable_exists(&tmp, "foo"); command_line_test([~"clean"], &package_dir); - assert!(!built_executable_in_workspace(&PkgId::new("foo", &package_dir), + assert!(!built_executable_in_workspace(&PkgId::new("foo"), &tmp).map_default(false, |m| { os::path_exists(m) })); } @@ -771,14 +748,13 @@ fn rustpkg_clean_no_arg() { #[ignore (reason = "Specifying env doesn't work -- see #8028")] fn rust_path_test() { let dir_for_path = mkdtemp(&os::tmpdir(), "more_rust").expect("rust_path_test failed"); - let dir = mk_workspace(&dir_for_path, &normalize(RemotePath(Path("foo"))), &NoVersion); + let dir = mk_workspace(&dir_for_path, &Path("foo"), &NoVersion); debug!("dir = %s", dir.to_str()); writeFile(&dir.push("main.rs"), "fn main() { let _x = (); }"); let cwd = os::getcwd(); debug!("cwd = %s", cwd.to_str()); - debug!("Running command: cd %s; RUST_LOG=rustpkg RUST_PATH=%s rustpkg install foo", - cwd.to_str(), dir_for_path.to_str()); + // use command_line_test_with_env let mut prog = run::Process::new("rustpkg", [~"install", ~"foo"], run::ProcessOptions { env: Some(&[(~"RUST_LOG", @@ -830,39 +806,38 @@ fn rust_path_parse() { #[test] fn test_list() { let dir = mkdtemp(&os::tmpdir(), "test_list").expect("test_list failed"); - let foo = PkgId::new("foo", &dir); + let foo = PkgId::new("foo"); create_local_package_in(&foo, &dir); - let bar = PkgId::new("bar", &dir); + let bar = PkgId::new("bar"); create_local_package_in(&bar, &dir); - let quux = PkgId::new("quux", &dir); + let quux = PkgId::new("quux"); create_local_package_in(&quux, &dir); -// NOTE Not really great output, though... -// NOTE do any tests need to be unignored? +// list doesn't output very much right now... command_line_test([~"install", ~"foo"], &dir); let env_arg = ~[(~"RUST_PATH", dir.to_str())]; debug!("RUST_PATH = %s", dir.to_str()); let list_output = command_line_test_output_with_env([~"list"], env_arg.clone()); - assert!(list_output.iter().any(|x| x.starts_with("libfoo_"))); + assert!(list_output.iter().any(|x| x.starts_with("foo"))); command_line_test([~"install", ~"bar"], &dir); let list_output = command_line_test_output_with_env([~"list"], env_arg.clone()); - assert!(list_output.iter().any(|x| x.starts_with("libfoo_"))); - assert!(list_output.iter().any(|x| x.starts_with("libbar_"))); + assert!(list_output.iter().any(|x| x.starts_with("foo"))); + assert!(list_output.iter().any(|x| x.starts_with("bar"))); command_line_test([~"install", ~"quux"], &dir); let list_output = command_line_test_output_with_env([~"list"], env_arg); - assert!(list_output.iter().any(|x| x.starts_with("libfoo_"))); - assert!(list_output.iter().any(|x| x.starts_with("libbar_"))); - assert!(list_output.iter().any(|x| x.starts_with("libquux_"))); + assert!(list_output.iter().any(|x| x.starts_with("foo"))); + assert!(list_output.iter().any(|x| x.starts_with("bar"))); + assert!(list_output.iter().any(|x| x.starts_with("quux"))); } #[test] fn install_remove() { let dir = mkdtemp(&os::tmpdir(), "install_remove").expect("install_remove"); - let foo = PkgId::new("foo", &dir); - let bar = PkgId::new("bar", &dir); - let quux = PkgId::new("quux", &dir); + let foo = PkgId::new("foo"); + let bar = PkgId::new("bar"); + let quux = PkgId::new("quux"); create_local_package_in(&foo, &dir); create_local_package_in(&bar, &dir); create_local_package_in(&quux, &dir); @@ -887,7 +862,7 @@ fn install_check_duplicates() { // ("Is already installed -- doing nothing") // check invariant that there are no dups in the pkg database let dir = mkdtemp(&os::tmpdir(), "install_remove").expect("install_remove"); - let foo = PkgId::new("foo", &dir); + let foo = PkgId::new("foo"); create_local_package_in(&foo, &dir); command_line_test([~"install", ~"foo"], &dir); @@ -895,7 +870,7 @@ fn install_check_duplicates() { let mut contents = ~[]; let check_dups = |p: &PkgId| { if contents.contains(p) { - fail!("package %s appears in `list` output more than once", p.local_path.to_str()); + fail!("package %s appears in `list` output more than once", p.path.to_str()); } else { contents.push((*p).clone()); @@ -908,7 +883,7 @@ fn install_check_duplicates() { #[test] #[ignore(reason = "Workcache not yet implemented -- see #7075")] fn no_rebuilding() { - let p_id = PkgId::new("foo", &os::getcwd()); + let p_id = PkgId::new("foo"); let workspace = create_local_package(&p_id); command_line_test([~"build", ~"foo"], &workspace); let date = datestamp(&built_library_in_workspace(&p_id, @@ -922,8 +897,8 @@ fn no_rebuilding() { #[test] #[ignore(reason = "Workcache not yet implemented -- see #7075")] fn no_rebuilding_dep() { - let p_id = PkgId::new("foo", &os::getcwd()); - let dep_id = PkgId::new("bar", &os::getcwd()); + let p_id = PkgId::new("foo"); + let dep_id = PkgId::new("bar"); let workspace = create_local_package_with_dep(&p_id, &dep_id); command_line_test([~"build", ~"foo"], &workspace); let bar_date = datestamp(&lib_output_file_name(&workspace, @@ -935,8 +910,8 @@ fn no_rebuilding_dep() { #[test] fn do_rebuild_dep_dates_change() { - let p_id = PkgId::new("foo", &os::getcwd()); - let dep_id = PkgId::new("bar", &os::getcwd()); + let p_id = PkgId::new("foo"); + let dep_id = PkgId::new("bar"); let workspace = create_local_package_with_dep(&p_id, &dep_id); command_line_test([~"build", ~"foo"], &workspace); let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar")); @@ -948,8 +923,8 @@ fn do_rebuild_dep_dates_change() { #[test] fn do_rebuild_dep_only_contents_change() { - let p_id = PkgId::new("foo", &os::getcwd()); - let dep_id = PkgId::new("bar", &os::getcwd()); + let p_id = PkgId::new("foo"); + let dep_id = PkgId::new("bar"); let workspace = create_local_package_with_dep(&p_id, &dep_id); command_line_test([~"build", ~"foo"], &workspace); let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar")); @@ -962,8 +937,8 @@ fn do_rebuild_dep_only_contents_change() { #[test] fn test_versions() { - let workspace = create_local_package(&PkgId::new("foo#0.1", &os::getcwd())); - create_local_package(&PkgId::new("foo#0.2", &os::getcwd())); + let workspace = create_local_package(&PkgId::new("foo#0.1")); + create_local_package(&PkgId::new("foo#0.2")); command_line_test([~"install", ~"foo#0.1"], &workspace); let output = command_line_test_output([~"list"]); // make sure output includes versions @@ -973,7 +948,7 @@ fn test_versions() { #[test] #[ignore(reason = "do not yet implemented")] fn test_build_hooks() { - let workspace = create_local_package_with_custom_build_hook(&PkgId::new("foo", &os::getcwd()), + let workspace = create_local_package_with_custom_build_hook(&PkgId::new("foo"), "frob"); command_line_test([~"do", ~"foo", ~"frob"], &workspace); } @@ -983,7 +958,7 @@ 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(&PkgId::new("foo", &os::getcwd())); + let workspace = create_local_package(&PkgId::new("foo")); let output = command_line_test([~"info", ~"foo"], &workspace); assert_eq!(str::from_bytes(output.output), expected_info); } @@ -992,7 +967,7 @@ fn test_info() { #[ignore(reason = "test not yet implemented")] fn test_rustpkg_test() { let expected_results = ~"1 out of 1 tests passed"; // fill in - let workspace = create_local_package_with_test(&PkgId::new("foo", &os::getcwd())); + let workspace = create_local_package_with_test(&PkgId::new("foo")); let output = command_line_test([~"test", ~"foo"], &workspace); assert_eq!(str::from_bytes(output.output), expected_results); } @@ -1000,7 +975,7 @@ fn test_rustpkg_test() { #[test] #[ignore(reason = "test not yet implemented")] fn test_uninstall() { - let workspace = create_local_package(&PkgId::new("foo", &os::getcwd())); + let workspace = create_local_package(&PkgId::new("foo")); let _output = command_line_test([~"info", ~"foo"], &workspace); command_line_test([~"uninstall", ~"foo"], &workspace); let output = command_line_test([~"list"], &workspace); @@ -1010,8 +985,8 @@ fn test_uninstall() { #[test] fn test_non_numeric_tag() { let temp_pkg_id = git_repo_pkg(); - let repo = init_git_repo(&Path(temp_pkg_id.local_path.to_str())); - let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test_pkg"); + let repo = init_git_repo(&temp_pkg_id.path); + let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test-pkg"); writeFile(&repo_subdir.push("foo"), "foo"); writeFile(&repo_subdir.push("lib.rs"), "pub fn f() { let _x = (); }"); @@ -1021,13 +996,70 @@ fn test_non_numeric_tag() { writeFile(&repo_subdir.push("not_on_testbranch_only"), "bye bye"); add_all_and_commit(&repo_subdir); - - command_line_test([~"install", fmt!("%s#testbranch", temp_pkg_id.remote_path.to_str())], - &repo); + command_line_test([~"install", fmt!("%s#testbranch", temp_pkg_id.path.to_str())], &repo); let file1 = repo.push_many(["mockgithub.com", "catamorphism", - "test_pkg", "testbranch_only"]); - let file2 = repo.push_many(["mockgithub.com", "catamorphism", "test_pkg", + "test-pkg", "testbranch_only"]); + let file2 = repo.push_many(["mockgithub.com", "catamorphism", "test-pkg", "master_only"]); assert!(os::path_exists(&file1)); assert!(!os::path_exists(&file2)); } + +#[test] +fn test_extern_mod() { + let dir = mkdtemp(&os::tmpdir(), "test_extern_mod").expect("test_extern_mod"); + let main_file = dir.push("main.rs"); + let lib_depend_dir = mkdtemp(&os::tmpdir(), "foo").expect("test_extern_mod"); + let aux_dir = lib_depend_dir.push_many(["src", "mockgithub.com", "catamorphism", "test_pkg"]); + assert!(os::mkdir_recursive(&aux_dir, U_RWX)); + let aux_pkg_file = aux_dir.push("lib.rs"); + + writeFile(&aux_pkg_file, "pub mod bar { pub fn assert_true() { assert!(true); } }\n"); + assert!(os::path_exists(&aux_pkg_file)); + + writeFile(&main_file, + "extern mod test = \"mockgithub.com/catamorphism/test_pkg\";\nuse test::bar;\ + fn main() { bar::assert_true(); }\n"); + + command_line_test([~"install", ~"mockgithub.com/catamorphism/test_pkg"], &lib_depend_dir); + + let exec_file = dir.push("out"); + // Be sure to extend the existing environment + let env = Some([(~"RUST_PATH", lib_depend_dir.to_str())] + os::env()); + let rustpkg_exec = rustpkg_exec(); + let rustc = rustpkg_exec.with_filename("rustc"); + debug!("RUST_PATH=%s %s %s \n --sysroot %s -o %s", + lib_depend_dir.to_str(), + rustc.to_str(), + main_file.to_str(), + test_sysroot().to_str(), + exec_file.to_str()); + + let mut prog = run::Process::new(rustc.to_str(), [main_file.to_str(), + ~"--sysroot", test_sysroot().to_str(), + ~"-o", exec_file.to_str()], + run::ProcessOptions { + env: env.map(|v| v.slice(0, v.len())), + dir: Some(&dir), + in_fd: None, + out_fd: None, + err_fd: None + }); + let outp = prog.finish_with_output(); + if outp.status != 0 { + fail!("output was %s, error was %s", + str::from_bytes(outp.output), + str::from_bytes(outp.error)); + } + assert!(os::path_exists(&exec_file) && is_executable(&exec_file)); +} + +/// Returns true if p exists and is executable +fn is_executable(p: &Path) -> bool { + use std::libc::consts::os::posix88::{S_IXUSR}; + + match p.get_mode() { + None => false, + Some(mode) => mode & S_IXUSR as uint == S_IXUSR as uint + } +} diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 81b47d6a16c..afac9423fba 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{os, result}; +use std::os; use rustc::driver::{driver, session}; -use rustc::metadata::filesearch; use extra::getopts::groups::getopts; use syntax::ast_util::*; use syntax::codemap::{dummy_sp, spanned}; @@ -19,10 +18,10 @@ use syntax::{ast, attr, codemap, diagnostic, fold}; use syntax::attr::AttrMetaMethods; use rustc::back::link::output_type_exe; use rustc::driver::session::{lib_crate, bin_crate}; -use context::Ctx; +use context::{Ctx, in_target}; use package_id::PkgId; use search::find_library_in_search_path; -use path_util::target_library_in_workspace; +use path_util::{target_library_in_workspace, U_RWX}; pub use target::{OutputType, Main, Lib, Bench, Test}; // It would be nice to have the list of commands in just one place -- for example, @@ -47,13 +46,6 @@ impl ToStr for Pkg { } } -pub fn root() -> Path { - match filesearch::get_rustpkg_root() { - result::Ok(path) => path, - result::Err(err) => fail!(err) - } -} - pub fn is_cmd(cmd: &str) -> bool { COMMANDS.iter().any(|&c| c == cmd) } @@ -162,25 +154,25 @@ pub fn ready_crate(sess: session::Session, pub fn compile_input(ctxt: &Ctx, pkg_id: &PkgId, in_file: &Path, - out_dir: &Path, + workspace: &Path, flags: &[~str], cfgs: &[~str], opt: bool, what: OutputType) -> bool { - let workspace = out_dir.pop().pop(); - assert!(in_file.components.len() > 1); let input = driver::file_input((*in_file).clone()); debug!("compile_input: %s / %?", in_file.to_str(), what); // tjc: by default, use the package ID name as the link name // not sure if we should support anything else + let out_dir = workspace.push("build").push_rel(&pkg_id.path); + let binary = os::args()[0].to_managed(); debug!("flags: %s", flags.connect(" ")); debug!("cfgs: %s", cfgs.connect(" ")); - debug!("compile_input's sysroot = %?", ctxt.sysroot_opt); + debug!("out_dir = %s", out_dir.to_str()); let crate_type = match what { Lib => lib_crate, @@ -196,12 +188,22 @@ pub fn compile_input(ctxt: &Ctx, + flags + cfgs.flat_map(|c| { ~[~"--cfg", (*c).clone()] }), driver::optgroups()).unwrap(); + // Hack so that rustpkg can run either out of a rustc target dir, + // or the host dir + let sysroot_to_use = if !in_target(ctxt.sysroot_opt) { + ctxt.sysroot_opt + } + else { + ctxt.sysroot_opt.map(|p| { @p.pop().pop().pop() }) + }; + debug!("compile_input's sysroot = %?", ctxt.sysroot_opt_str()); + debug!("sysroot_to_use = %?", sysroot_to_use); let options = @session::options { crate_type: crate_type, optimize: if opt { session::Aggressive } else { session::No }, test: what == Test || what == Bench, - maybe_sysroot: ctxt.sysroot_opt, - addl_lib_search_paths: @mut (~[(*out_dir).clone()]), + maybe_sysroot: sysroot_to_use, + addl_lib_search_paths: @mut (~[out_dir.clone()]), // output_type should be conditional output_type: output_type_exe, // Use this to get a library? That's weird .. (*driver::build_session_options(binary, &matches, diagnostic::emit)).clone() @@ -211,7 +213,12 @@ pub fn compile_input(ctxt: &Ctx, // Make sure all the library directories actually exist, since the linker will complain // otherwise for p in addl_lib_search_paths.iter() { - assert!(os::path_is_dir(p)); + if os::path_exists(p) { + assert!(os::path_is_dir(p)); + } + else { + assert!(os::mkdir_recursive(p, U_RWX)); + } } let sess = driver::build_session(options, diagnostic::emit); @@ -224,35 +231,44 @@ pub fn compile_input(ctxt: &Ctx, // Not really right. Should search other workspaces too, and the installed // database (which doesn't exist yet) - find_and_install_dependencies(ctxt, sess, &workspace, crate, + find_and_install_dependencies(ctxt, sess, workspace, crate, |p| { debug!("a dependency: %s", p.to_str()); // Pass the directory containing a dependency // as an additional lib search path - addl_lib_search_paths.push(p); + if !addl_lib_search_paths.contains(&p) { + // Might be inefficient, but this set probably + // won't get too large -- tjc + addl_lib_search_paths.push(p); + } }); // Inject the link attributes so we get the right package name and version if attr::find_linkage_metas(crate.attrs).is_empty() { - let short_name_to_use = match what { - Test => fmt!("%stest", pkg_id.short_name), - Bench => fmt!("%sbench", pkg_id.short_name), - _ => pkg_id.short_name.clone() + let name_to_use = match what { + Test => fmt!("%stest", pkg_id.short_name).to_managed(), + Bench => fmt!("%sbench", pkg_id.short_name).to_managed(), + _ => pkg_id.short_name.to_managed() }; - debug!("Injecting link name: %s", short_name_to_use); + debug!("Injecting link name: %s", name_to_use); let link_options = - ~[attr::mk_name_value_item_str(@"name", short_name_to_use.to_managed()), - attr::mk_name_value_item_str(@"vers", pkg_id.version.to_str().to_managed())]; - + ~[attr::mk_name_value_item_str(@"name", name_to_use), + attr::mk_name_value_item_str(@"vers", pkg_id.version.to_str().to_managed())] + + if pkg_id.is_complex() { + ~[attr::mk_name_value_item_str(@"package_id", + pkg_id.path.to_str().to_managed())] + } else { ~[] }; + + debug!("link options: %?", link_options); crate = @ast::Crate { attrs: ~[attr::mk_attr(attr::mk_list_item(@"link", link_options))], .. (*crate).clone() - }; + } } - debug!("calling compile_crate_from_input, out_dir = %s, + debug!("calling compile_crate_from_input, workspace = %s, building_library = %?", out_dir.to_str(), sess.building_library); - compile_crate_from_input(&input, out_dir, sess, crate); + compile_crate_from_input(&input, &out_dir, sess, crate); true } @@ -262,17 +278,22 @@ pub fn compile_input(ctxt: &Ctx, // call compile_upto and return the crate // also, too many arguments pub fn compile_crate_from_input(input: &driver::input, - build_dir: &Path, + // should be of the form <workspace>/build/<pkg id's path> + out_dir: &Path, sess: session::Session, crate: @ast::Crate) { debug!("Calling build_output_filenames with %s, building library? %?", - build_dir.to_str(), sess.building_library); + out_dir.to_str(), sess.building_library); // bad copy - let outputs = driver::build_output_filenames(input, &Some((*build_dir).clone()), &None, + debug!("out_dir = %s", out_dir.to_str()); + let outputs = driver::build_output_filenames(input, &Some(out_dir.clone()), &None, crate.attrs, sess); - debug!("Outputs are %? and output type = %?", outputs, sess.opts.output_type); + debug!("Outputs are out_filename: %s and obj_filename: %s and output type = %?", + outputs.out_filename.to_str(), + outputs.obj_filename.to_str(), + sess.opts.output_type); debug!("additional libraries:"); for lib in sess.opts.addl_lib_search_paths.iter() { debug!("an additional library: %s", lib.to_str()); @@ -298,15 +319,15 @@ pub fn exe_suffix() -> ~str { ~"" } // Called by build_crates // FIXME (#4432): Use workcache to only compile when needed pub fn compile_crate(ctxt: &Ctx, pkg_id: &PkgId, - crate: &Path, dir: &Path, + crate: &Path, workspace: &Path, flags: &[~str], cfgs: &[~str], opt: bool, what: OutputType) -> bool { - debug!("compile_crate: crate=%s, dir=%s", crate.to_str(), dir.to_str()); + debug!("compile_crate: crate=%s, workspace=%s", crate.to_str(), workspace.to_str()); debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str()); for fl in flags.iter() { debug!("+++ %s", *fl); } - compile_input(ctxt, pkg_id, crate, dir, flags, cfgs, opt, what) + compile_input(ctxt, pkg_id, crate, workspace, flags, cfgs, opt, what) } @@ -327,19 +348,20 @@ pub fn find_and_install_dependencies(ctxt: &Ctx, debug!("A view item!"); match vi.node { // ignore metadata, I guess - ast::view_item_extern_mod(lib_ident, _, _) => { + ast::view_item_extern_mod(lib_ident, path_opt, _, _) => { match my_ctxt.sysroot_opt { - Some(ref x) => debug!("sysroot: %s", x.to_str()), + Some(ref x) => debug!("*** sysroot: %s", x.to_str()), None => debug!("No sysroot given") }; - let lib_name = sess.str_of(lib_ident); + let lib_name = match path_opt { // ??? + Some(p) => p, None => sess.str_of(lib_ident) }; match find_library_in_search_path(my_ctxt.sysroot_opt, lib_name) { Some(installed_path) => { debug!("It exists: %s", installed_path.to_str()); } None => { // Try to install it - let pkg_id = PkgId::new(lib_name, &os::getcwd()); + let pkg_id = PkgId::new(lib_name); my_ctxt.install(&my_workspace, &pkg_id); // Also, add an additional search path debug!("let installed_path...") @@ -372,10 +394,12 @@ pub fn link_exe(_src: &Path, _dest: &Path) -> bool { #[cfg(target_os = "freebsd")] #[cfg(target_os = "macos")] pub fn link_exe(src: &Path, dest: &Path) -> bool { + use std::c_str::ToCStr; use std::libc; + unsafe { - do src.to_str().as_c_str |src_buf| { - do dest.to_str().as_c_str |dest_buf| { + do src.to_c_str().with_ref |src_buf| { + do dest.to_c_str().with_ref |dest_buf| { libc::link(src_buf, dest_buf) == 0 as libc::c_int && libc::chmod(dest_buf, 755) == 0 as libc::c_int } diff --git a/src/librustpkg/version.rs b/src/librustpkg/version.rs index 88391850891..44cb8065b38 100644 --- a/src/librustpkg/version.rs +++ b/src/librustpkg/version.rs @@ -15,8 +15,8 @@ extern mod std; use extra::semver; use std::{char, os, result, run, str}; -use package_path::RemotePath; use extra::tempfile::mkdtemp; +use path_util::rust_path; #[deriving(Clone)] pub enum Version { @@ -92,19 +92,22 @@ pub fn parse_vers(vers: ~str) -> result::Result<semver::Version, ~str> { } } -/// If `local_path` is a git repo, and the most recent tag in that repo denotes a version, -/// return it; otherwise, `None` +/// 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> { - debug!("in try_getting_local_version"); - let outp = run::process_output("git", + let rustpath = rust_path(); + for rp in rustpath.iter() { + let local_path = rp.push_rel(local_path); + debug!("in try_getting_local_version"); + let outp = run::process_output("git", [fmt!("--git-dir=%s", local_path.push(".git").to_str()), ~"tag", ~"-l"]); - debug!("git --git-dir=%s tag -l ~~~> %?", local_path.push(".git").to_str(), outp.status); + debug!("git --git-dir=%s tag -l ~~~> %?", local_path.push(".git").to_str(), outp.status); - if outp.status != 0 { - return None; - } + if outp.status != 0 { + loop; + } let mut output = None; let output_text = str::from_bytes(outp.output); @@ -112,14 +115,19 @@ pub fn try_getting_local_version(local_path: &Path) -> Option<Version> { if !l.is_whitespace() { output = Some(l); } + match output.chain(try_parsing_version) { + Some(v) => return Some(v), + None => () + } } - output.chain(try_parsing_version) + } + 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: &RemotePath) -> Option<Version> { +pub fn try_getting_version(remote_path: &Path) -> Option<Version> { debug!("try_getting_version: %s", remote_path.to_str()); if is_url_like(remote_path) { debug!("Trying to fetch its sources.."); @@ -190,9 +198,9 @@ fn try_parsing_version(s: &str) -> Option<Version> { } /// Just an approximation -fn is_url_like(p: &RemotePath) -> bool { +fn is_url_like(p: &Path) -> bool { let str = p.to_str(); - str.split_iter('/').len_() > 2 + str.split_iter('/').len() > 2 } /// If s is of the form foo#bar, where bar is a valid version @@ -207,7 +215,7 @@ pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Vers for st in s.split_iter(sep) { debug!("whole = %s part = %s", s, st); } - if s.split_iter(sep).len_() > 2 { + if s.split_iter(sep).len() > 2 { return None; } match s.rfind(sep) { diff --git a/src/librustpkg/workspace.rs b/src/librustpkg/workspace.rs index d877b4ff489..6ac959e4a32 100644 --- a/src/librustpkg/workspace.rs +++ b/src/librustpkg/workspace.rs @@ -12,9 +12,11 @@ use std::os; use std::path::Path; -use path_util::{rust_path, workspace_contains_package_id}; +use path_util::workspace_contains_package_id; use package_id::PkgId; +use rustc::metadata::filesearch::rust_path; + pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool { // Using the RUST_PATH, find workspaces that contain // this package ID @@ -23,7 +25,7 @@ pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> b // tjc: make this a condition fail!("Package %s not found in any of \ the following workspaces: %s", - pkgid.remote_path.to_str(), + pkgid.path.to_str(), rust_path().to_str()); } for ws in workspaces.iter() { @@ -35,7 +37,7 @@ pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> b } pub fn pkg_parent_workspaces(pkgid: &PkgId) -> ~[Path] { - rust_path().consume_iter() + rust_path().move_iter() .filter(|ws| workspace_contains_package_id(pkgid, ws)) .collect() } @@ -58,5 +60,5 @@ pub fn cwd_to_workspace() -> (Path, PkgId) { let ws = cwd.pop().pop(); let cwd_ = cwd.clone(); let pkgid = cwd_.components.last().to_str(); - (ws, PkgId::new(pkgid, &cwd)) + (ws, PkgId::new(pkgid)) } diff --git a/src/libstd/at_vec.rs b/src/libstd/at_vec.rs index a84f3137bbd..c948074990a 100644 --- a/src/libstd/at_vec.rs +++ b/src/libstd/at_vec.rs @@ -12,7 +12,7 @@ use clone::Clone; use container::Container; -use iterator::{Iterator, range}; +use iterator::Iterator; use option::{Option, Some, None}; use sys; use unstable::raw::Repr; @@ -92,8 +92,8 @@ pub fn append<T:Clone>(lhs: @[T], rhs: &[T]) -> @[T] { for x in lhs.iter() { push((*x).clone()); } - for i in range(0u, rhs.len()) { - push(rhs[i].clone()); + for elt in rhs.iter() { + push(elt.clone()); } } } @@ -141,11 +141,11 @@ pub fn from_elem<T:Clone>(n_elts: uint, t: T) -> @[T] { * Creates and initializes an immutable managed vector by moving all the * elements from an owned vector. */ -pub fn to_managed_consume<T>(v: ~[T]) -> @[T] { +pub fn to_managed_move<T>(v: ~[T]) -> @[T] { let mut av = @[]; unsafe { raw::reserve(&mut av, v.len()); - for x in v.consume_iter() { + for x in v.move_iter() { raw::push(&mut av, x); } av @@ -275,24 +275,11 @@ pub mod raw { } fn local_realloc(ptr: *(), size: uint) -> *() { - use rt; - use rt::OldTaskContext; use rt::local::Local; use rt::task::Task; - if rt::context() == OldTaskContext { - unsafe { - return rust_local_realloc(ptr, size as libc::size_t); - } - - extern { - #[fast_ffi] - fn rust_local_realloc(ptr: *(), size: libc::size_t) -> *(); - } - } else { - do Local::borrow::<Task, *()> |task| { - task.heap.realloc(ptr as *libc::c_void, size) as *() - } + do Local::borrow::<Task, *()> |task| { + task.heap.realloc(ptr as *libc::c_void, size) as *() } } } @@ -344,12 +331,12 @@ mod test { } #[test] - fn test_to_managed_consume() { - assert_eq!(to_managed_consume::<int>(~[]), @[]); - assert_eq!(to_managed_consume(~[true]), @[true]); - assert_eq!(to_managed_consume(~[1, 2, 3, 4, 5]), @[1, 2, 3, 4, 5]); - assert_eq!(to_managed_consume(~[~"abc", ~"123"]), @[~"abc", ~"123"]); - assert_eq!(to_managed_consume(~[~[42]]), @[~[42]]); + fn test_to_managed_move() { + assert_eq!(to_managed_move::<int>(~[]), @[]); + assert_eq!(to_managed_move(~[true]), @[true]); + assert_eq!(to_managed_move(~[1, 2, 3, 4, 5]), @[1, 2, 3, 4, 5]); + assert_eq!(to_managed_move(~[~"abc", ~"123"]), @[~"abc", ~"123"]); + assert_eq!(to_managed_move(~[~[42]]), @[~[42]]); } #[test] diff --git a/src/libstd/bool.rs b/src/libstd/bool.rs index eeaea6a2cff..598e8080618 100644 --- a/src/libstd/bool.rs +++ b/src/libstd/bool.rs @@ -284,12 +284,6 @@ impl Not<bool> for bool { impl Ord for bool { #[inline] fn lt(&self, other: &bool) -> bool { to_bit(*self) < to_bit(*other) } - #[inline] - fn le(&self, other: &bool) -> bool { to_bit(*self) <= to_bit(*other) } - #[inline] - fn gt(&self, other: &bool) -> bool { to_bit(*self) > to_bit(*other) } - #[inline] - fn ge(&self, other: &bool) -> bool { to_bit(*self) >= to_bit(*other) } } #[cfg(not(test))] diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs new file mode 100644 index 00000000000..7e313543660 --- /dev/null +++ b/src/libstd/c_str.rs @@ -0,0 +1,233 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cast; +use iterator::Iterator; +use libc; +use ops::Drop; +use option::{Option, Some, None}; +use ptr::RawPtr; +use ptr; +use str::StrSlice; +use vec::ImmutableVector; + +/// The representation of a C String. +/// +/// This structure wraps a `*libc::c_char`, and will automatically free the +/// memory it is pointing to when it goes out of scope. +pub struct CString { + priv buf: *libc::c_char, + priv owns_buffer_: bool, +} + +impl CString { + /// Create a C String from a pointer. + pub unsafe fn new(buf: *libc::c_char, owns_buffer: bool) -> CString { + CString { buf: buf, owns_buffer_: owns_buffer } + } + + /// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper. + pub unsafe fn unwrap(self) -> *libc::c_char { + let mut c_str = self; + c_str.owns_buffer_ = false; + c_str.buf + } + + /// Calls a closure with a reference to the underlying `*libc::c_char`. + /// + /// # Failure + /// + /// Fails if the CString is null. + pub fn with_ref<T>(&self, f: &fn(*libc::c_char) -> T) -> T { + if self.buf.is_null() { fail!("CString is null!"); } + f(self.buf) + } + + /// Calls a closure with a mutable reference to the underlying `*libc::c_char`. + /// + /// # Failure + /// + /// Fails if the CString is null. + pub fn with_mut_ref<T>(&mut self, f: &fn(*mut libc::c_char) -> T) -> T { + if self.buf.is_null() { fail!("CString is null!"); } + f(unsafe { cast::transmute_mut_unsafe(self.buf) }) + } + + /// Returns true if the CString is a null. + pub fn is_null(&self) -> bool { + self.buf.is_null() + } + + /// Returns true if the CString is not null. + pub fn is_not_null(&self) -> bool { + self.buf.is_not_null() + } + + /// Returns whether or not the `CString` owns the buffer. + pub fn owns_buffer(&self) -> bool { + self.owns_buffer_ + } + + /// Converts the CString into a `&[u8]` without copying. + /// + /// # Failure + /// + /// Fails if the CString is null. + pub fn as_bytes<'a>(&'a self) -> &'a [u8] { + if self.buf.is_null() { fail!("CString is null!"); } + unsafe { + let len = libc::strlen(self.buf) as uint; + cast::transmute((self.buf, len + 1)) + } + } + + /// Return a CString iterator. + fn iter<'a>(&'a self) -> CStringIterator<'a> { + CStringIterator { + ptr: self.buf, + lifetime: unsafe { cast::transmute(self.buf) }, + } + } +} + +impl Drop for CString { + fn drop(&self) { + if self.owns_buffer_ { + unsafe { + libc::free(self.buf as *libc::c_void) + } + } + } +} + +/// A generic trait for converting a value to a CString. +pub trait ToCStr { + /// Create a C String. + fn to_c_str(&self) -> CString; +} + +impl<'self> ToCStr for &'self str { + #[inline] + fn to_c_str(&self) -> CString { + self.as_bytes().to_c_str() + } +} + +impl<'self> ToCStr for &'self [u8] { + fn to_c_str(&self) -> CString { + do self.as_imm_buf |self_buf, self_len| { + unsafe { + let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8; + if buf.is_null() { + fail!("failed to allocate memory!"); + } + + ptr::copy_memory(buf, self_buf, self_len); + *ptr::mut_offset(buf, self_len as int) = 0; + + CString::new(buf as *libc::c_char, true) + } + } + } +} + +/// External iterator for a CString's bytes. +/// +/// Use with the `std::iterator` module. +pub struct CStringIterator<'self> { + priv ptr: *libc::c_char, + priv lifetime: &'self libc::c_char, // FIXME: #5922 +} + +impl<'self> Iterator<libc::c_char> for CStringIterator<'self> { + fn next(&mut self) -> Option<libc::c_char> { + let ch = unsafe { *self.ptr }; + if ch == 0 { + None + } else { + self.ptr = ptr::offset(self.ptr, 1); + Some(ch) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use libc; + use ptr; + use option::{Some, None}; + + #[test] + fn test_to_c_str() { + do "".to_c_str().with_ref |buf| { + unsafe { + assert_eq!(*ptr::offset(buf, 0), 0); + } + } + + do "hello".to_c_str().with_ref |buf| { + unsafe { + assert_eq!(*ptr::offset(buf, 0), 'h' as libc::c_char); + assert_eq!(*ptr::offset(buf, 1), 'e' as libc::c_char); + assert_eq!(*ptr::offset(buf, 2), 'l' as libc::c_char); + assert_eq!(*ptr::offset(buf, 3), 'l' as libc::c_char); + assert_eq!(*ptr::offset(buf, 4), 'o' as libc::c_char); + assert_eq!(*ptr::offset(buf, 5), 0); + } + } + } + + #[test] + fn test_is_null() { + let c_str = unsafe { CString::new(ptr::null(), false) }; + assert!(c_str.is_null()); + assert!(!c_str.is_not_null()); + } + + #[test] + fn test_unwrap() { + let c_str = "hello".to_c_str(); + unsafe { libc::free(c_str.unwrap() as *libc::c_void) } + } + + #[test] + fn test_with_ref() { + let c_str = "hello".to_c_str(); + let len = unsafe { c_str.with_ref(|buf| libc::strlen(buf)) }; + assert!(!c_str.is_null()); + assert!(c_str.is_not_null()); + assert_eq!(len, 5); + } + + #[test] + #[should_fail] + #[ignore(cfg(windows))] + fn test_with_ref_empty_fail() { + let c_str = unsafe { CString::new(ptr::null(), false) }; + c_str.with_ref(|_| ()); + } + + #[test] + fn test_iterator() { + let c_str = "".to_c_str(); + let mut iter = c_str.iter(); + assert_eq!(iter.next(), None); + + let c_str = "hello".to_c_str(); + let mut iter = c_str.iter(); + assert_eq!(iter.next(), Some('h' as libc::c_char)); + assert_eq!(iter.next(), Some('e' as libc::c_char)); + assert_eq!(iter.next(), Some('l' as libc::c_char)); + assert_eq!(iter.next(), Some('l' as libc::c_char)); + assert_eq!(iter.next(), Some('o' as libc::c_char)); + assert_eq!(iter.next(), None); + } +} diff --git a/src/libstd/cast.rs b/src/libstd/cast.rs index ee91d127909..ff9057afb55 100644 --- a/src/libstd/cast.rs +++ b/src/libstd/cast.rs @@ -165,10 +165,20 @@ mod tests { } } + #[cfg(stage0)] #[test] fn test_transmute2() { unsafe { assert_eq!(~[76u8, 0u8], transmute(~"L")); } } + + #[cfg(not(stage0))] + #[test] + fn test_transmute2() { + unsafe { + assert_eq!(~[76u8], transmute(~"L")); + } + } + } diff --git a/src/libstd/char.rs b/src/libstd/char.rs index 85053855432..9c55e22b1f8 100644 --- a/src/libstd/char.rs +++ b/src/libstd/char.rs @@ -322,12 +322,6 @@ impl Eq for char { impl Ord for char { #[inline] fn lt(&self, other: &char) -> bool { *self < *other } - #[inline] - fn le(&self, other: &char) -> bool { *self <= *other } - #[inline] - fn gt(&self, other: &char) -> bool { *self > *other } - #[inline] - fn ge(&self, other: &char) -> bool { *self >= *other } } #[cfg(not(test))] diff --git a/src/libstd/cleanup.rs b/src/libstd/cleanup.rs index b9535091ed8..7c2348a3533 100644 --- a/src/libstd/cleanup.rs +++ b/src/libstd/cleanup.rs @@ -56,13 +56,8 @@ unsafe fn each_live_alloc(read_next_before: bool, #[cfg(unix)] fn debug_mem() -> bool { - use rt; - use rt::OldTaskContext; // XXX: Need to port the environment struct to newsched - match rt::context() { - OldTaskContext => ::rt::env::get().debug_mem, - _ => false - } + false } #[cfg(windows)] @@ -147,15 +142,3 @@ pub unsafe fn annihilate() { dbg.write_str("\n"); } } - -/// Bindings to the runtime -pub mod rustrt { - use libc::c_void; - - #[link_name = "rustrt"] - extern { - #[rust_stack] - // FIXME (#4386): Unable to make following method private. - pub fn rust_get_task() -> *c_void; - } -} diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs index b66f89e8341..28d45abb688 100644 --- a/src/libstd/cmp.rs +++ b/src/libstd/cmp.rs @@ -101,12 +101,6 @@ impl TotalOrd for Ordering { impl Ord for Ordering { #[inline] fn lt(&self, other: &Ordering) -> bool { (*self as int) < (*other as int) } - #[inline] - fn le(&self, other: &Ordering) -> bool { (*self as int) <= (*other as int) } - #[inline] - fn gt(&self, other: &Ordering) -> bool { (*self as int) > (*other as int) } - #[inline] - fn ge(&self, other: &Ordering) -> bool { (*self as int) >= (*other as int) } } macro_rules! totalord_impl( @@ -174,8 +168,11 @@ pub fn lexical_ordering(o1: Ordering, o2: Ordering) -> Ordering { #[lang="ord"] pub trait Ord { fn lt(&self, other: &Self) -> bool; + #[inline] fn le(&self, other: &Self) -> bool { !other.lt(self) } + #[inline] fn gt(&self, other: &Self) -> bool { other.lt(self) } + #[inline] fn ge(&self, other: &Self) -> bool { !self.lt(other) } } diff --git a/src/libstd/comm.rs b/src/libstd/comm.rs index 4356f1143da..18c7674873f 100644 --- a/src/libstd/comm.rs +++ b/src/libstd/comm.rs @@ -14,13 +14,11 @@ Message passing #[allow(missing_doc)]; -use either::{Either, Left, Right}; +use clone::Clone; use kinds::Send; -use option::{Option, Some}; -use unstable::sync::Exclusive; +use option::Option; pub use rt::comm::SendDeferred; use rtcomm = rt::comm; -use rt; /// A trait for things that can send multiple messages. pub trait GenericChan<T> { @@ -52,614 +50,146 @@ pub trait Peekable<T> { fn peek(&self) -> bool; } -/// An endpoint that can send many messages. -pub struct Chan<T> { - inner: Either<pipesy::Chan<T>, rtcomm::Chan<T>> -} - -/// An endpoint that can receive many messages. -pub struct Port<T> { - inner: Either<pipesy::Port<T>, rtcomm::Port<T>> -} - -/** Creates a `(Port, Chan)` pair. - -These allow sending or receiving an unlimited number of messages. - -*/ -pub fn stream<T:Send>() -> (Port<T>, Chan<T>) { - let (port, chan) = match rt::context() { - rt::OldTaskContext => match pipesy::stream() { - (p, c) => (Left(p), Left(c)) - }, - _ => match rtcomm::stream() { - (p, c) => (Right(p), Right(c)) - } - }; - let port = Port { inner: port }; - let chan = Chan { inner: chan }; - return (port, chan); -} +pub struct PortOne<T> { x: rtcomm::PortOne<T> } +pub struct ChanOne<T> { x: rtcomm::ChanOne<T> } -impl<T: Send> GenericChan<T> for Chan<T> { - fn send(&self, x: T) { - match self.inner { - Left(ref chan) => chan.send(x), - Right(ref chan) => chan.send(x) - } - } -} - -impl<T: Send> GenericSmartChan<T> for Chan<T> { - fn try_send(&self, x: T) -> bool { - match self.inner { - Left(ref chan) => chan.try_send(x), - Right(ref chan) => chan.try_send(x) - } - } -} - -impl<T: Send> SendDeferred<T> for Chan<T> { - fn send_deferred(&self, x: T) { - match self.inner { - Left(ref chan) => chan.send(x), - Right(ref chan) => chan.send_deferred(x) - } - } - fn try_send_deferred(&self, x: T) -> bool { - match self.inner { - Left(ref chan) => chan.try_send(x), - Right(ref chan) => chan.try_send_deferred(x) - } - } +pub fn oneshot<T: Send>() -> (PortOne<T>, ChanOne<T>) { + let (p, c) = rtcomm::oneshot(); + (PortOne { x: p }, ChanOne { x: c }) } -impl<T: Send> GenericPort<T> for Port<T> { - fn recv(&self) -> T { - match self.inner { - Left(ref port) => port.recv(), - Right(ref port) => port.recv() - } - } - - fn try_recv(&self) -> Option<T> { - match self.inner { - Left(ref port) => port.try_recv(), - Right(ref port) => port.try_recv() - } - } -} +pub struct Port<T> { x: rtcomm::Port<T> } +pub struct Chan<T> { x: rtcomm::Chan<T> } -impl<T: Send> Peekable<T> for Port<T> { - fn peek(&self) -> bool { - match self.inner { - Left(ref port) => port.peek(), - Right(ref port) => port.peek() - } - } +pub fn stream<T: Send>() -> (Port<T>, Chan<T>) { + let (p, c) = rtcomm::stream(); + (Port { x: p }, Chan { x: c }) } -/// A channel that can be shared between many senders. -pub struct SharedChan<T> { - inner: Either<Exclusive<pipesy::Chan<T>>, rtcomm::SharedChan<T>> -} +pub struct SharedChan<T> { x: rtcomm::SharedChan<T> } impl<T: Send> SharedChan<T> { - /// Converts a `chan` into a `shared_chan`. pub fn new(c: Chan<T>) -> SharedChan<T> { - let Chan { inner } = c; - let c = match inner { - Left(c) => Left(Exclusive::new(c)), - Right(c) => Right(rtcomm::SharedChan::new(c)) - }; - SharedChan { inner: c } + let Chan { x: c } = c; + SharedChan { x: rtcomm::SharedChan::new(c) } } } -impl<T: Send> GenericChan<T> for SharedChan<T> { - fn send(&self, x: T) { - match self.inner { - Left(ref chan) => { - unsafe { - let mut xx = Some(x); - do chan.with_imm |chan| { - chan.send(xx.take_unwrap()) - } - } - } - Right(ref chan) => chan.send(x) - } +impl<T: Send> ChanOne<T> { + pub fn send(self, val: T) { + let ChanOne { x: c } = self; + c.send(val) } -} -impl<T: Send> GenericSmartChan<T> for SharedChan<T> { - fn try_send(&self, x: T) -> bool { - match self.inner { - Left(ref chan) => { - unsafe { - let mut xx = Some(x); - do chan.with_imm |chan| { - chan.try_send(xx.take_unwrap()) - } - } - } - Right(ref chan) => chan.try_send(x) - } + pub fn try_send(self, val: T) -> bool { + let ChanOne { x: c } = self; + c.try_send(val) } -} -impl<T: Send> ::clone::Clone for SharedChan<T> { - fn clone(&self) -> SharedChan<T> { - SharedChan { inner: self.inner.clone() } + pub fn send_deferred(self, val: T) { + let ChanOne { x: c } = self; + c.send_deferred(val) } -} -pub struct PortOne<T> { - inner: Either<pipesy::PortOne<T>, rtcomm::PortOne<T>> -} - -pub struct ChanOne<T> { - inner: Either<pipesy::ChanOne<T>, rtcomm::ChanOne<T>> -} - -pub fn oneshot<T: Send>() -> (PortOne<T>, ChanOne<T>) { - let (port, chan) = match rt::context() { - rt::OldTaskContext => match pipesy::oneshot() { - (p, c) => (Left(p), Left(c)), - }, - _ => match rtcomm::oneshot() { - (p, c) => (Right(p), Right(c)) - } - }; - let port = PortOne { inner: port }; - let chan = ChanOne { inner: chan }; - return (port, chan); + pub fn try_send_deferred(self, val: T) -> bool { + let ChanOne{ x: c } = self; + c.try_send_deferred(val) + } } impl<T: Send> PortOne<T> { pub fn recv(self) -> T { - let PortOne { inner } = self; - match inner { - Left(p) => p.recv(), - Right(p) => p.recv() - } + let PortOne { x: p } = self; + p.recv() } pub fn try_recv(self) -> Option<T> { - let PortOne { inner } = self; - match inner { - Left(p) => p.try_recv(), - Right(p) => p.try_recv() - } + let PortOne { x: p } = self; + p.try_recv() } } -impl<T: Send> ChanOne<T> { - pub fn send(self, data: T) { - let ChanOne { inner } = self; - match inner { - Left(p) => p.send(data), - Right(p) => p.send(data) - } - } - - pub fn try_send(self, data: T) -> bool { - let ChanOne { inner } = self; - match inner { - Left(p) => p.try_send(data), - Right(p) => p.try_send(data) - } - } - pub fn send_deferred(self, data: T) { - let ChanOne { inner } = self; - match inner { - Left(p) => p.send(data), - Right(p) => p.send_deferred(data) - } - } - pub fn try_send_deferred(self, data: T) -> bool { - let ChanOne { inner } = self; - match inner { - Left(p) => p.try_send(data), - Right(p) => p.try_send_deferred(data) - } +impl<T: Send> Peekable<T> for PortOne<T> { + fn peek(&self) -> bool { + let &PortOne { x: ref p } = self; + p.peek() } } -pub fn recv_one<T: Send>(port: PortOne<T>) -> T { - let PortOne { inner } = port; - match inner { - Left(p) => pipesy::recv_one(p), - Right(p) => p.recv() +impl<T: Send> GenericChan<T> for Chan<T> { + fn send(&self, val: T) { + let &Chan { x: ref c } = self; + c.send(val) } } -pub fn try_recv_one<T: Send>(port: PortOne<T>) -> Option<T> { - let PortOne { inner } = port; - match inner { - Left(p) => pipesy::try_recv_one(p), - Right(p) => p.try_recv() +impl<T: Send> GenericSmartChan<T> for Chan<T> { + fn try_send(&self, val: T) -> bool { + let &Chan { x: ref c } = self; + c.try_send(val) } } -pub fn send_one<T: Send>(chan: ChanOne<T>, data: T) { - let ChanOne { inner } = chan; - match inner { - Left(c) => pipesy::send_one(c, data), - Right(c) => c.send(data) +impl<T: Send> SendDeferred<T> for Chan<T> { + fn send_deferred(&self, val: T) { + let &Chan { x: ref c } = self; + c.send_deferred(val) } -} -pub fn try_send_one<T: Send>(chan: ChanOne<T>, data: T) -> bool { - let ChanOne { inner } = chan; - match inner { - Left(c) => pipesy::try_send_one(c, data), - Right(c) => c.try_send(data) + fn try_send_deferred(&self, val: T) -> bool { + let &Chan { x: ref c } = self; + c.try_send_deferred(val) } } -mod pipesy { - - use kinds::Send; - use option::{Option, Some, None}; - use pipes::{recv, try_recv, peek}; - use super::{GenericChan, GenericSmartChan, GenericPort, Peekable}; - use cast::transmute_mut; - - /*proto! oneshot ( - Oneshot:send<T:Send> { - send(T) -> ! - } - )*/ - - #[allow(non_camel_case_types)] - pub mod oneshot { - priv use std::kinds::Send; - use ptr::to_mut_unsafe_ptr; - - pub fn init<T: Send>() -> (server::Oneshot<T>, client::Oneshot<T>) { - pub use std::pipes::HasBuffer; - - let buffer = ~::std::pipes::Buffer { - header: ::std::pipes::BufferHeader(), - data: __Buffer { - Oneshot: ::std::pipes::mk_packet::<Oneshot<T>>() - }, - }; - do ::std::pipes::entangle_buffer(buffer) |buffer, data| { - data.Oneshot.set_buffer(buffer); - to_mut_unsafe_ptr(&mut data.Oneshot) - } - } - #[allow(non_camel_case_types)] - pub enum Oneshot<T> { pub send(T), } - #[allow(non_camel_case_types)] - pub struct __Buffer<T> { - Oneshot: ::std::pipes::Packet<Oneshot<T>>, - } - - #[allow(non_camel_case_types)] - pub mod client { - - priv use std::kinds::Send; - - #[allow(non_camel_case_types)] - pub fn try_send<T: Send>(pipe: Oneshot<T>, x_0: T) -> - ::std::option::Option<()> { - { - use super::send; - let message = send(x_0); - if ::std::pipes::send(pipe, message) { - ::std::pipes::rt::make_some(()) - } else { ::std::pipes::rt::make_none() } - } - } - - #[allow(non_camel_case_types)] - pub fn send<T: Send>(pipe: Oneshot<T>, x_0: T) { - { - use super::send; - let message = send(x_0); - ::std::pipes::send(pipe, message); - } - } - - #[allow(non_camel_case_types)] - pub type Oneshot<T> = - ::std::pipes::SendPacketBuffered<super::Oneshot<T>, - super::__Buffer<T>>; - } - - #[allow(non_camel_case_types)] - pub mod server { - #[allow(non_camel_case_types)] - pub type Oneshot<T> = - ::std::pipes::RecvPacketBuffered<super::Oneshot<T>, - super::__Buffer<T>>; - } - } - - /// The send end of a oneshot pipe. - pub struct ChanOne<T> { - contents: oneshot::client::Oneshot<T> - } - - impl<T> ChanOne<T> { - pub fn new(contents: oneshot::client::Oneshot<T>) -> ChanOne<T> { - ChanOne { - contents: contents - } - } - } - - /// The receive end of a oneshot pipe. - pub struct PortOne<T> { - contents: oneshot::server::Oneshot<T> - } - - impl<T> PortOne<T> { - pub fn new(contents: oneshot::server::Oneshot<T>) -> PortOne<T> { - PortOne { - contents: contents - } - } - } - - /// Initialiase a (send-endpoint, recv-endpoint) oneshot pipe pair. - pub fn oneshot<T: Send>() -> (PortOne<T>, ChanOne<T>) { - let (port, chan) = oneshot::init(); - (PortOne::new(port), ChanOne::new(chan)) - } - - impl<T: Send> PortOne<T> { - pub fn recv(self) -> T { recv_one(self) } - pub fn try_recv(self) -> Option<T> { try_recv_one(self) } - pub fn unwrap(self) -> oneshot::server::Oneshot<T> { - match self { - PortOne { contents: s } => s - } - } - } - - impl<T: Send> ChanOne<T> { - pub fn send(self, data: T) { send_one(self, data) } - pub fn try_send(self, data: T) -> bool { try_send_one(self, data) } - pub fn unwrap(self) -> oneshot::client::Oneshot<T> { - match self { - ChanOne { contents: s } => s - } - } - } - - /** - * Receive a message from a oneshot pipe, failing if the connection was - * closed. - */ - pub fn recv_one<T: Send>(port: PortOne<T>) -> T { - match port { - PortOne { contents: port } => { - let oneshot::send(message) = recv(port); - message - } - } - } - - /// Receive a message from a oneshot pipe unless the connection was closed. - pub fn try_recv_one<T: Send> (port: PortOne<T>) -> Option<T> { - match port { - PortOne { contents: port } => { - let message = try_recv(port); - - if message.is_none() { - None - } else { - let oneshot::send(message) = message.unwrap(); - Some(message) - } - } - } - } - - /// Send a message on a oneshot pipe, failing if the connection was closed. - pub fn send_one<T: Send>(chan: ChanOne<T>, data: T) { - match chan { - ChanOne { contents: chan } => oneshot::client::send(chan, data), - } - } - - /** - * Send a message on a oneshot pipe, or return false if the connection was - * closed. - */ - pub fn try_send_one<T: Send>(chan: ChanOne<T>, data: T) -> bool { - match chan { - ChanOne { contents: chan } => { - oneshot::client::try_send(chan, data).is_some() - } - } - } - - // Streams - Make pipes a little easier in general. - - /*proto! streamp ( - Open:send<T: Send> { - data(T) -> Open<T> - } - )*/ - - #[allow(non_camel_case_types)] - pub mod streamp { - priv use std::kinds::Send; - - pub fn init<T: Send>() -> (server::Open<T>, client::Open<T>) { - pub use std::pipes::HasBuffer; - ::std::pipes::entangle() - } - - #[allow(non_camel_case_types)] - pub enum Open<T> { pub data(T, server::Open<T>), } - - #[allow(non_camel_case_types)] - pub mod client { - priv use std::kinds::Send; - - #[allow(non_camel_case_types)] - pub fn try_data<T: Send>(pipe: Open<T>, x_0: T) -> - ::std::option::Option<Open<T>> { - { - use super::data; - let (s, c) = ::std::pipes::entangle(); - let message = data(x_0, s); - if ::std::pipes::send(pipe, message) { - ::std::pipes::rt::make_some(c) - } else { ::std::pipes::rt::make_none() } - } - } - - #[allow(non_camel_case_types)] - pub fn data<T: Send>(pipe: Open<T>, x_0: T) -> Open<T> { - { - use super::data; - let (s, c) = ::std::pipes::entangle(); - let message = data(x_0, s); - ::std::pipes::send(pipe, message); - c - } - } - - #[allow(non_camel_case_types)] - pub type Open<T> = ::std::pipes::SendPacket<super::Open<T>>; - } - - #[allow(non_camel_case_types)] - pub mod server { - #[allow(non_camel_case_types)] - pub type Open<T> = ::std::pipes::RecvPacket<super::Open<T>>; - } - } - - /// An endpoint that can send many messages. - #[unsafe_mut_field(endp)] - pub struct Chan<T> { - endp: Option<streamp::client::Open<T>> +impl<T: Send> GenericPort<T> for Port<T> { + fn recv(&self) -> T { + let &Port { x: ref p } = self; + p.recv() } - /// An endpoint that can receive many messages. - #[unsafe_mut_field(endp)] - pub struct Port<T> { - endp: Option<streamp::server::Open<T>>, + fn try_recv(&self) -> Option<T> { + let &Port { x: ref p } = self; + p.try_recv() } +} - /** Creates a `(Port, Chan)` pair. - - These allow sending or receiving an unlimited number of messages. - - */ - pub fn stream<T:Send>() -> (Port<T>, Chan<T>) { - let (s, c) = streamp::init(); - - (Port { - endp: Some(s) - }, Chan { - endp: Some(c) - }) +impl<T: Send> Peekable<T> for Port<T> { + fn peek(&self) -> bool { + let &Port { x: ref p } = self; + p.peek() } +} - impl<T: Send> GenericChan<T> for Chan<T> { - #[inline] - fn send(&self, x: T) { - unsafe { - let self_endp = transmute_mut(&self.endp); - *self_endp = Some(streamp::client::data(self_endp.take_unwrap(), x)) - } - } +impl<T: Send> GenericChan<T> for SharedChan<T> { + fn send(&self, val: T) { + let &SharedChan { x: ref c } = self; + c.send(val) } +} - impl<T: Send> GenericSmartChan<T> for Chan<T> { - #[inline] - fn try_send(&self, x: T) -> bool { - unsafe { - let self_endp = transmute_mut(&self.endp); - match streamp::client::try_data(self_endp.take_unwrap(), x) { - Some(next) => { - *self_endp = Some(next); - true - } - None => false - } - } - } +impl<T: Send> GenericSmartChan<T> for SharedChan<T> { + fn try_send(&self, val: T) -> bool { + let &SharedChan { x: ref c } = self; + c.try_send(val) } +} - impl<T: Send> GenericPort<T> for Port<T> { - #[inline] - fn recv(&self) -> T { - unsafe { - let self_endp = transmute_mut(&self.endp); - let endp = self_endp.take(); - let streamp::data(x, endp) = recv(endp.unwrap()); - *self_endp = Some(endp); - x - } - } - - #[inline] - fn try_recv(&self) -> Option<T> { - unsafe { - let self_endp = transmute_mut(&self.endp); - let endp = self_endp.take(); - match try_recv(endp.unwrap()) { - Some(streamp::data(x, endp)) => { - *self_endp = Some(endp); - Some(x) - } - None => None - } - } - } +impl<T: Send> SendDeferred<T> for SharedChan<T> { + fn send_deferred(&self, val: T) { + let &SharedChan { x: ref c } = self; + c.send_deferred(val) } - impl<T: Send> Peekable<T> for Port<T> { - #[inline] - fn peek(&self) -> bool { - unsafe { - let self_endp = transmute_mut(&self.endp); - let mut endp = self_endp.take(); - let peek = match endp { - Some(ref mut endp) => peek(endp), - None => fail!("peeking empty stream") - }; - *self_endp = endp; - peek - } - } + fn try_send_deferred(&self, val: T) -> bool { + let &SharedChan { x: ref c } = self; + c.try_send_deferred(val) } - } -#[cfg(test)] -mod test { - use either::Right; - use super::{Chan, Port, oneshot, stream}; - - #[test] - fn test_oneshot() { - let (p, c) = oneshot(); - - c.send(()); - - p.recv() - } - - #[test] - fn test_peek_terminated() { - let (port, chan): (Port<int>, Chan<int>) = stream(); - - { - // Destroy the channel - let _chan = chan; - } - - assert!(!port.peek()); +impl<T> Clone for SharedChan<T> { + fn clone(&self) -> SharedChan<T> { + let &SharedChan { x: ref c } = self; + SharedChan { x: c.clone() } } } diff --git a/src/libstd/either.rs b/src/libstd/either.rs index bb74d9b3ec4..132ebc72960 100644 --- a/src/libstd/either.rs +++ b/src/libstd/either.rs @@ -150,7 +150,7 @@ pub fn rights<L, R: Clone>(eithers: &[Either<L, R>]) -> ~[R] { pub fn partition<L, R>(eithers: ~[Either<L, R>]) -> (~[L], ~[R]) { let mut lefts: ~[L] = ~[]; let mut rights: ~[R] = ~[]; - for elt in eithers.consume_iter() { + for elt in eithers.move_iter() { match elt { Left(l) => lefts.push(l), Right(r) => rights.push(r) diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index 3484a5e7d6e..7a224776859 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -19,7 +19,7 @@ use container::{Container, Mutable, Map, MutableMap, Set, MutableSet}; use clone::Clone; use cmp::{Eq, Equiv}; use hash::Hash; -use iterator::{Iterator, IteratorUtil, FromIterator, Extendable, range}; +use iterator::{Iterator, FromIterator, Extendable}; use iterator::{FilterMap, Chain, Repeat, Zip}; use num; use option::{None, Option, Some}; @@ -159,8 +159,8 @@ impl<K:Hash + Eq,V> HashMap<K, V> { vec::from_fn(new_capacity, |_| None)); self.size = 0; - // consume_rev_iter is more efficient - for bucket in old_buckets.consume_rev_iter() { + // move_rev_iter is more efficient + for bucket in old_buckets.move_rev_iter() { self.insert_opt_bucket(bucket); } } @@ -265,8 +265,8 @@ 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 idx in range(0u, self.buckets.len()) { - self.buckets[idx] = None; + for bkt in self.buckets.mut_iter() { + *bkt = None; } self.size = 0; } @@ -470,9 +470,9 @@ impl<K: Hash + Eq, V> HashMap<K, V> { /// Creates a consuming iterator, that is, one that moves each key-value /// pair out of the map in arbitrary order. The map cannot be used after /// calling this. - pub fn consume(self) -> HashMapConsumeIterator<K, V> { - // `consume_rev_iter` is more efficient than `consume_iter` for vectors - HashMapConsumeIterator {iter: self.buckets.consume_rev_iter()} + pub fn move_iter(self) -> HashMapMoveIterator<K, V> { + // `move_rev_iter` is more efficient than `move_iter` for vectors + HashMapMoveIterator {iter: self.buckets.move_rev_iter()} } } @@ -524,9 +524,9 @@ pub struct HashMapMutIterator<'self, K, V> { priv iter: vec::VecMutIterator<'self, Option<Bucket<K, V>>>, } -/// HashMap consume iterator -pub struct HashMapConsumeIterator<K, V> { - priv iter: vec::ConsumeRevIterator<Option<Bucket<K, V>>>, +/// HashMap move iterator +pub struct HashMapMoveIterator<K, V> { + priv iter: vec::MoveRevIterator<Option<Bucket<K, V>>>, } /// HashSet iterator @@ -535,9 +535,9 @@ pub struct HashSetIterator<'self, K> { priv iter: vec::VecIterator<'self, Option<Bucket<K, ()>>>, } -/// HashSet consume iterator -pub struct HashSetConsumeIterator<K> { - priv iter: vec::ConsumeRevIterator<Option<Bucket<K, ()>>>, +/// HashSet move iterator +pub struct HashSetMoveIterator<K> { + priv iter: vec::MoveRevIterator<Option<Bucket<K, ()>>>, } impl<'self, K, V> Iterator<(&'self K, &'self V)> for HashMapIterator<'self, K, V> { @@ -566,7 +566,7 @@ impl<'self, K, V> Iterator<(&'self K, &'self mut V)> for HashMapMutIterator<'sel } } -impl<K, V> Iterator<(K, V)> for HashMapConsumeIterator<K, V> { +impl<K, V> Iterator<(K, V)> for HashMapMoveIterator<K, V> { #[inline] fn next(&mut self) -> Option<(K, V)> { for elt in self.iter { @@ -592,7 +592,7 @@ impl<'self, K> Iterator<&'self K> for HashSetIterator<'self, K> { } } -impl<K> Iterator<K> for HashSetConsumeIterator<K> { +impl<K> Iterator<K> for HashSetMoveIterator<K> { #[inline] fn next(&mut self) -> Option<K> { for elt in self.iter { @@ -707,9 +707,9 @@ impl<T:Hash + Eq> HashSet<T> { /// Creates a consuming iterator, that is, one that moves each value out /// of the set in arbitrary order. The set cannot be used after calling /// this. - pub fn consume(self) -> HashSetConsumeIterator<T> { - // `consume_rev_iter` is more efficient than `consume_iter` for vectors - HashSetConsumeIterator {iter: self.map.buckets.consume_rev_iter()} + pub fn move_iter(self) -> HashSetMoveIterator<T> { + // `move_rev_iter` is more efficient than `move_iter` for vectors + HashSetMoveIterator {iter: self.map.buckets.move_rev_iter()} } /// Visit the values representing the difference @@ -724,7 +724,7 @@ impl<T:Hash + Eq> HashSet<T> { /// Visit the values representing the symmetric difference pub fn symmetric_difference_iter<'a>(&'a self, other: &'a HashSet<T>) -> Chain<SetAlgebraIter<'a, T>, SetAlgebraIter<'a, T>> { - self.difference_iter(other).chain_(other.difference_iter(self)) + self.difference_iter(other).chain(other.difference_iter(self)) } /// Visit the values representing the intersection @@ -740,7 +740,7 @@ impl<T:Hash + Eq> HashSet<T> { /// Visit the values representing the union pub fn union_iter<'a>(&'a self, other: &'a HashSet<T>) -> Chain<HashSetIterator<'a, T>, SetAlgebraIter<'a, T>> { - self.iter().chain_(other.difference_iter(self)) + self.iter().chain(other.difference_iter(self)) } } @@ -881,7 +881,7 @@ mod test_map { } #[test] - fn test_consume() { + fn test_move_iter() { let hm = { let mut hm = HashMap::new(); @@ -891,7 +891,7 @@ mod test_map { hm }; - let v = hm.consume().collect::<~[(char, int)]>(); + let v = hm.move_iter().collect::<~[(char, int)]>(); assert!([('a', 1), ('b', 2)] == v || [('b', 2), ('a', 1)] == v); } @@ -977,7 +977,7 @@ mod test_map { fn test_from_iter() { let xs = ~[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - let map: HashMap<int, int> = xs.iter().transform(|&x| x).collect(); + let map: HashMap<int, int> = xs.iter().map(|&x| x).collect(); for &(k, v) in xs.iter() { assert_eq!(map.find(&k), Some(&v)); @@ -1169,7 +1169,7 @@ mod test_set { fn test_from_iter() { let xs = ~[1, 2, 3, 4, 5, 6, 7, 8, 9]; - let set: HashSet<int> = xs.iter().transform(|&x| x).collect(); + let set: HashSet<int> = xs.iter().map(|&x| x).collect(); for x in xs.iter() { assert!(set.contains(x)); @@ -1177,7 +1177,7 @@ mod test_set { } #[test] - fn test_consume() { + fn test_move_iter() { let hs = { let mut hs = HashSet::new(); @@ -1187,7 +1187,7 @@ mod test_set { hs }; - let v = hs.consume().collect::<~[char]>(); + let v = hs.move_iter().collect::<~[char]>(); assert!(['a', 'b'] == v || ['b', 'a'] == v); } } diff --git a/src/libstd/io.rs b/src/libstd/io.rs index 55e60f03ea9..07572d60917 100644 --- a/src/libstd/io.rs +++ b/src/libstd/io.rs @@ -48,6 +48,7 @@ implement `Reader` and `Writer`, where appropriate. use cast; use clone::Clone; +use c_str::ToCStr; use container::Container; use int; use iterator::Iterator; @@ -1040,8 +1041,8 @@ pub fn stdin() -> @Reader { } pub fn file_reader(path: &Path) -> Result<@Reader, ~str> { - let f = do path.to_str().as_c_str |pathbuf| { - do "rb".as_c_str |modebuf| { + let f = do path.to_c_str().with_ref |pathbuf| { + do "rb".to_c_str().with_ref |modebuf| { unsafe { libc::fopen(pathbuf, modebuf as *libc::c_char) } } }; @@ -1290,9 +1291,8 @@ pub fn mk_file_writer(path: &Path, flags: &[FileFlag]) } } let fd = unsafe { - do path.to_str().as_c_str |pathbuf| { - libc::open(pathbuf, fflags, - (S_IRUSR | S_IWUSR) as c_int) + do path.to_c_str().with_ref |pathbuf| { + libc::open(pathbuf, fflags, (S_IRUSR | S_IWUSR) as c_int) } }; if fd < (0 as c_int) { @@ -1574,8 +1574,8 @@ pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<@Writer, ~str> { // FIXME: fileflags // #2004 pub fn buffered_file_writer(path: &Path) -> Result<@Writer, ~str> { unsafe { - let f = do path.to_str().as_c_str |pathbuf| { - do "w".as_c_str |modebuf| { + let f = do path.to_c_str().with_ref |pathbuf| { + do "w".to_c_str().with_ref |modebuf| { libc::fopen(pathbuf, modebuf) } }; @@ -1707,6 +1707,7 @@ pub fn with_bytes_writer(f: &fn(@Writer)) -> ~[u8] { (*bytes).clone() } +#[cfg(stage0)] pub fn with_str_writer(f: &fn(@Writer)) -> ~str { let mut v = with_bytes_writer(f); @@ -1719,6 +1720,11 @@ pub fn with_str_writer(f: &fn(@Writer)) -> ~str { } } +#[cfg(not(stage0))] +pub fn with_str_writer(f: &fn(@Writer)) -> ~str { + str::from_bytes(with_bytes_writer(f)) +} + // Utility functions pub fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) -> uint { diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 29f54bd10fb..a7a1c0bede8 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -18,9 +18,9 @@ implementing the `Iterator` trait. */ use cmp; -use num::{Zero, One, Saturating}; +use num::{Zero, One, Integer, Saturating}; use option::{Option, Some, None}; -use ops::{Add, Mul}; +use ops::{Add, Mul, Sub}; use cmp::Ord; use clone::Clone; use uint; @@ -49,89 +49,7 @@ pub trait Iterator<A> { /// The common use case for the estimate is pre-allocating space to store the results. #[inline] fn size_hint(&self) -> (uint, Option<uint>) { (0, None) } -} - -/// A range iterator able to yield elements from both ends -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>; -} - -/// An object implementing random access indexing by `uint` -/// -/// A `RandomAccessIterator` should be either infinite or a `DoubleEndedIterator`. -pub trait RandomAccessIterator<A>: Iterator<A> { - /// Return the number of indexable elements. At most `std::uint::max_value` - /// elements are indexable, even if the iterator represents a longer range. - fn indexable(&self) -> uint; - - /// Return an element at an index - fn idx(&self, index: uint) -> Option<A>; -} - -/// Iterator adaptors provided for every `DoubleEndedIterator` implementation. -/// -/// In the future these will be default methods instead of a utility trait. -pub trait DoubleEndedIteratorUtil { - /// Flip the direction of the iterator - fn invert(self) -> Invert<Self>; -} - -/// Iterator adaptors provided for every `DoubleEndedIterator` implementation. -/// -/// In the future these will be default methods instead of a utility trait. -impl<A, T: DoubleEndedIterator<A>> DoubleEndedIteratorUtil for T { - /// Flip the direction of the iterator - /// - /// The inverted iterator flips 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 - /// 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 - /// `uint::max_value` elements of the original iterator. - #[inline] - fn invert(self) -> Invert<T> { - Invert{iter: self} - } -} - -/// An double-ended iterator with the direction inverted -#[deriving(Clone)] -pub struct Invert<T> { - priv iter: T -} - -impl<A, T: DoubleEndedIterator<A>> Iterator<A> for Invert<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> { - #[inline] - fn next_back(&mut self) -> Option<A> { self.iter.next() } -} - -impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterator<A> - for Invert<T> { - #[inline] - fn indexable(&self) -> uint { self.iter.indexable() } - #[inline] - fn idx(&self, index: uint) -> Option<A> { - self.iter.idx(self.indexable() - index - 1) - } -} - -/// Iterator adaptors provided for every `Iterator` implementation. The adaptor objects are also -/// implementations of the `Iterator` trait. -/// -/// In the future these will be default methods instead of a utility trait. -pub trait IteratorUtil<A> { /// Chain this iterator with another, returning a new iterator which will /// finish iterating over the current iterator, and then it will iterate /// over the other specified iterator. @@ -141,12 +59,15 @@ pub trait IteratorUtil<A> { /// ~~~ {.rust} /// let a = [0]; /// let b = [1]; - /// let mut it = a.iter().chain_(b.iter()); + /// let mut it = a.iter().chain(b.iter()); /// assert_eq!(it.next().get(), &0); /// assert_eq!(it.next().get(), &1); /// assert!(it.next().is_none()); /// ~~~ - fn chain_<U: Iterator<A>>(self, other: U) -> Chain<Self, U>; + #[inline] + fn chain<U: Iterator<A>>(self, other: U) -> Chain<Self, U> { + Chain{a: self, b: other, flag: false} + } /// Creates an iterator which iterates over both this and the specified /// iterators simultaneously, yielding the two elements as pairs. When @@ -162,9 +83,11 @@ pub trait IteratorUtil<A> { /// assert_eq!(it.next().get(), (&0, &1)); /// assert!(it.next().is_none()); /// ~~~ - fn zip<B, U: Iterator<B>>(self, other: U) -> Zip<Self, U>; + #[inline] + fn zip<B, U: Iterator<B>>(self, other: U) -> Zip<Self, U> { + Zip{a: self, b: other} + } - // FIXME: #5898: should be called map /// Creates a new iterator which will apply the specified function to each /// element returned by the first, yielding the mapped element instead. /// @@ -172,12 +95,15 @@ pub trait IteratorUtil<A> { /// /// ~~~ {.rust} /// let a = [1, 2]; - /// let mut it = a.iter().transform(|&x| 2 * x); + /// let mut it = a.iter().map(|&x| 2 * x); /// assert_eq!(it.next().get(), 2); /// assert_eq!(it.next().get(), 4); /// assert!(it.next().is_none()); /// ~~~ - fn transform<'r, B>(self, f: &'r fn(A) -> B) -> Map<'r, A, B, Self>; + #[inline] + fn map<'r, B>(self, f: &'r fn(A) -> B) -> Map<'r, A, B, Self> { + Map{iter: self, f: f} + } /// Creates an iterator which applies the predicate to each element returned /// by this iterator. Only elements which have the predicate evaluate to @@ -191,7 +117,10 @@ pub trait IteratorUtil<A> { /// assert_eq!(it.next().get(), &2); /// assert!(it.next().is_none()); /// ~~~ - fn filter<'r>(self, predicate: &'r fn(&A) -> bool) -> Filter<'r, A, Self>; + #[inline] + fn filter<'r>(self, predicate: &'r fn(&A) -> bool) -> Filter<'r, A, Self> { + Filter{iter: self, predicate: predicate} + } /// Creates an iterator which both filters and maps elements. /// If the specified function returns None, the element is skipped. @@ -205,7 +134,10 @@ pub trait IteratorUtil<A> { /// assert_eq!(it.next().get(), 4); /// assert!(it.next().is_none()); /// ~~~ - fn filter_map<'r, B>(self, f: &'r fn(A) -> Option<B>) -> FilterMap<'r, A, B, Self>; + #[inline] + fn filter_map<'r, B>(self, f: &'r fn(A) -> Option<B>) -> FilterMap<'r, A, B, Self> { + FilterMap { iter: self, f: f } + } /// Creates an iterator which yields a pair of the value returned by this /// iterator plus the current index of iteration. @@ -219,7 +151,10 @@ pub trait IteratorUtil<A> { /// assert_eq!(it.next().get(), (1, &200)); /// assert!(it.next().is_none()); /// ~~~ - fn enumerate(self) -> Enumerate<Self>; + #[inline] + fn enumerate(self) -> Enumerate<Self> { + Enumerate{iter: self, count: 0} + } /// Creates an iterator which invokes the predicate on elements until it /// returns false. Once the predicate returns false, all further elements are @@ -235,7 +170,10 @@ pub trait IteratorUtil<A> { /// assert_eq!(it.next().get(), &1); /// assert!(it.next().is_none()); /// ~~~ - fn skip_while<'r>(self, predicate: &'r fn(&A) -> bool) -> SkipWhile<'r, A, Self>; + #[inline] + fn skip_while<'r>(self, predicate: &'r fn(&A) -> bool) -> SkipWhile<'r, A, Self> { + SkipWhile{iter: self, flag: false, predicate: predicate} + } /// Creates an iterator which yields elements so long as the predicate /// returns true. After the predicate returns false for the first time, no @@ -250,7 +188,10 @@ pub trait IteratorUtil<A> { /// assert_eq!(it.next().get(), &2); /// assert!(it.next().is_none()); /// ~~~ - fn take_while<'r>(self, predicate: &'r fn(&A) -> bool) -> TakeWhile<'r, A, Self>; + #[inline] + fn take_while<'r>(self, predicate: &'r fn(&A) -> bool) -> TakeWhile<'r, A, Self> { + TakeWhile{iter: self, flag: false, predicate: predicate} + } /// Creates an iterator which skips the first `n` elements of this iterator, /// and then it yields all further items. @@ -264,9 +205,11 @@ pub trait IteratorUtil<A> { /// assert_eq!(it.next().get(), &5); /// assert!(it.next().is_none()); /// ~~~ - fn skip(self, n: uint) -> Skip<Self>; + #[inline] + fn skip(self, n: uint) -> Skip<Self> { + Skip{iter: self, n: n} + } - // FIXME: #5898: should be called take /// Creates an iterator which yields the first `n` elements of this /// iterator, and then it will always return None. /// @@ -274,13 +217,16 @@ pub trait IteratorUtil<A> { /// /// ~~~ {.rust} /// let a = [1, 2, 3, 4, 5]; - /// let mut it = a.iter().take_(3); + /// let mut it = a.iter().take(3); /// assert_eq!(it.next().get(), &1); /// assert_eq!(it.next().get(), &2); /// assert_eq!(it.next().get(), &3); /// assert!(it.next().is_none()); /// ~~~ - fn take_(self, n: uint) -> Take<Self>; + #[inline] + fn take(self, n: uint) -> Take<Self> { + Take{iter: self, n: n} + } /// Creates a new iterator which behaves in a similar fashion to foldl. /// There is a state which is passed between each iteration and can be @@ -302,8 +248,11 @@ pub trait IteratorUtil<A> { /// assert_eq!(it.next().get(), 120); /// assert!(it.next().is_none()); /// ~~~ + #[inline] fn scan<'r, St, B>(self, initial_state: St, f: &'r fn(&mut St, A) -> Option<B>) - -> Scan<'r, A, B, Self, St>; + -> Scan<'r, A, B, Self, St> { + Scan{iter: self, f: f, state: initial_state} + } /// Creates an iterator that maps each element to an iterator, /// and yields the elements of the produced iterators @@ -313,7 +262,7 @@ pub trait IteratorUtil<A> { /// ~~~ {.rust} /// let xs = [2u, 3]; /// let ys = [0u, 1, 0, 1, 2]; - /// let mut it = xs.iter().flat_map_(|&x| count(0u, 1).take_(x)); + /// let mut it = xs.iter().flat_map(|&x| count(0u, 1).take(x)); /// // Check that `it` has the same elements as `ys` /// let mut i = 0; /// for x: uint in it { @@ -321,9 +270,11 @@ pub trait IteratorUtil<A> { /// i += 1; /// } /// ~~~ - // FIXME: #5898: should be called `flat_map` - fn flat_map_<'r, B, U: Iterator<B>>(self, f: &'r fn(A) -> U) - -> FlatMap<'r, A, Self, U>; + #[inline] + fn flat_map<'r, B, U: Iterator<B>>(self, f: &'r fn(A) -> U) + -> FlatMap<'r, A, Self, U> { + FlatMap{iter: self, f: f, frontiter: None, backiter: None } + } /// Creates an iterator that calls a function with a reference to each /// element before yielding it. This is often useful for debugging an @@ -334,15 +285,17 @@ pub trait IteratorUtil<A> { /// ~~~ {.rust} ///let xs = [1u, 4, 2, 3, 8, 9, 6]; ///let sum = xs.iter() - /// .transform(|&x| x) - /// .peek_(|&x| debug!("filtering %u", x)) + /// .map(|&x| x) + /// .peek(|&x| debug!("filtering %u", x)) /// .filter(|&x| x % 2 == 0) - /// .peek_(|&x| debug!("%u made it through", x)) + /// .peek(|&x| debug!("%u made it through", x)) /// .sum(); ///println(sum.to_str()); /// ~~~ - // FIXME: #5898: should be called `peek` - fn peek_<'r>(self, f: &'r fn(&A)) -> Peek<'r, A, Self>; + #[inline] + fn peek<'r>(self, f: &'r fn(&A)) -> Peek<'r, A, Self> { + Peek{iter: self, f: f} + } /// An adaptation of an external iterator to the for-loop protocol of rust. /// @@ -355,7 +308,17 @@ pub trait IteratorUtil<A> { /// printfln!("%d", i); /// } /// ~~~ - fn advance(&mut self, f: &fn(A) -> bool) -> bool; + #[inline] + fn advance(&mut self, f: &fn(A) -> bool) -> bool { + loop { + match self.next() { + Some(x) => { + if !f(x) { return false; } + } + None => { return true; } + } + } + } /// Loops through the entire iterator, collecting all of the elements into /// a container implementing `FromIterator`. @@ -364,10 +327,13 @@ pub trait IteratorUtil<A> { /// /// ~~~ {.rust} /// let a = [1, 2, 3, 4, 5]; - /// let b: ~[int] = a.iter().transform(|&x| x).collect(); + /// let b: ~[int] = a.iter().map(|&x| x).collect(); /// assert!(a == b); /// ~~~ - fn collect<B: FromIterator<A, Self>>(&mut self) -> B; + #[inline] + fn collect<B: FromIterator<A, Self>>(&mut self) -> B { + FromIterator::from_iterator(self) + } /// Loops through the entire iterator, collecting all of the elements into /// a unique vector. This is simply collect() specialized for vectors. @@ -376,10 +342,13 @@ pub trait IteratorUtil<A> { /// /// ~~~ {.rust} /// let a = [1, 2, 3, 4, 5]; - /// let b: ~[int] = a.iter().transform(|&x| x).to_owned_vec(); + /// let b: ~[int] = a.iter().map(|&x| x).to_owned_vec(); /// assert!(a == b); /// ~~~ - fn to_owned_vec(&mut self) -> ~[A]; + #[inline] + fn to_owned_vec(&mut self) -> ~[A] { + self.collect() + } /// Loops through `n` iterations, returning the `n`th element of the /// iterator. @@ -392,7 +361,16 @@ pub trait IteratorUtil<A> { /// assert!(it.nth(2).get() == &3); /// assert!(it.nth(2) == None); /// ~~~ - fn nth(&mut self, n: uint) -> Option<A>; + #[inline] + fn nth(&mut self, mut n: uint) -> Option<A> { + loop { + match self.next() { + Some(x) => if n == 0 { return Some(x) }, + None => return None + } + n -= 1; + } + } /// Loops through the entire iterator, returning the last element of the /// iterator. @@ -403,8 +381,12 @@ pub trait IteratorUtil<A> { /// let a = [1, 2, 3, 4, 5]; /// assert!(a.iter().last().get() == &5); /// ~~~ - // FIXME: #5898: should be called `last` - fn last_(&mut self) -> Option<A>; + #[inline] + fn last(&mut self) -> Option<A> { + let mut last = None; + for x in *self { last = Some(x); } + last + } /// Performs a fold operation over the entire iterator, returning the /// eventual state at the end of the iteration. @@ -415,9 +397,18 @@ pub trait IteratorUtil<A> { /// let a = [1, 2, 3, 4, 5]; /// assert!(a.iter().fold(0, |a, &b| a + b) == 15); /// ~~~ - fn fold<B>(&mut self, start: B, f: &fn(B, A) -> B) -> B; + #[inline] + fn fold<B>(&mut self, init: B, f: &fn(B, A) -> B) -> B { + let mut accum = init; + loop { + match self.next() { + Some(x) => { accum = f(accum, x); } + None => { break; } + } + } + accum + } - // FIXME: #5898: should be called len /// Counts the number of elements in this iterator. /// /// # Example @@ -425,10 +416,13 @@ pub trait IteratorUtil<A> { /// ~~~ {.rust} /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter(); - /// assert!(it.len_() == 5); - /// assert!(it.len_() == 0); + /// assert!(it.len() == 5); + /// assert!(it.len() == 0); /// ~~~ - fn len_(&mut self) -> uint; + #[inline] + fn len(&mut self) -> uint { + self.fold(0, |cnt, _x| cnt + 1) + } /// Tests whether the predicate holds true for all elements in the iterator. /// @@ -439,7 +433,11 @@ pub trait IteratorUtil<A> { /// assert!(a.iter().all(|&x| *x > 0)); /// assert!(!a.iter().all(|&x| *x > 2)); /// ~~~ - fn all(&mut self, f: &fn(A) -> bool) -> bool; + #[inline] + fn all(&mut self, f: &fn(A) -> bool) -> bool { + for x in *self { if !f(x) { return false; } } + true + } /// Tests whether any element of an iterator satisfies the specified /// predicate. @@ -452,179 +450,6 @@ pub trait IteratorUtil<A> { /// assert!(it.any(|&x| *x == 3)); /// assert!(!it.any(|&x| *x == 3)); /// ~~~ - fn any(&mut self, f: &fn(A) -> bool) -> bool; - - /// Return the first element satisfying the specified predicate - fn find_(&mut self, predicate: &fn(&A) -> bool) -> Option<A>; - - /// Return the index of the first element satisfying the specified predicate - fn position(&mut self, predicate: &fn(A) -> bool) -> Option<uint>; - - /// Count the number of elements satisfying the specified predicate - fn count(&mut self, predicate: &fn(A) -> bool) -> uint; - - /// Return the element that gives the maximum value from the specfied function - /// - /// # Example - /// - /// ~~~ {.rust} - /// let xs = [-3, 0, 1, 5, -10]; - /// assert_eq!(*xs.iter().max_by(|x| x.abs()).unwrap(), -10); - /// ~~~ - fn max_by<B: Ord>(&mut self, f: &fn(&A) -> B) -> Option<A>; - - /// Return the element that gives the minimum value from the specfied function - /// - /// # Example - /// - /// ~~~ {.rust} - /// let xs = [-3, 0, 1, 5, -10]; - /// assert_eq!(*xs.iter().min_by(|x| x.abs()).unwrap(), 0); - /// ~~~ - fn min_by<B: Ord>(&mut self, f: &fn(&A) -> B) -> Option<A>; -} - -/// Iterator adaptors provided for every `Iterator` implementation. The adaptor objects are also -/// implementations of the `Iterator` trait. -/// -/// In the future these will be default methods instead of a utility trait. -impl<A, T: Iterator<A>> IteratorUtil<A> for T { - #[inline] - fn chain_<U: Iterator<A>>(self, other: U) -> Chain<T, U> { - Chain{a: self, b: other, flag: false} - } - - #[inline] - fn zip<B, U: Iterator<B>>(self, other: U) -> Zip<T, U> { - Zip{a: self, b: other} - } - - // FIXME: #5898: should be called map - #[inline] - fn transform<'r, B>(self, f: &'r fn(A) -> B) -> Map<'r, A, B, T> { - Map{iter: self, f: f} - } - - #[inline] - fn filter<'r>(self, predicate: &'r fn(&A) -> bool) -> Filter<'r, A, T> { - Filter{iter: self, predicate: predicate} - } - - #[inline] - fn filter_map<'r, B>(self, f: &'r fn(A) -> Option<B>) -> FilterMap<'r, A, B, T> { - FilterMap { iter: self, f: f } - } - - #[inline] - fn enumerate(self) -> Enumerate<T> { - Enumerate{iter: self, count: 0} - } - - #[inline] - fn skip_while<'r>(self, predicate: &'r fn(&A) -> bool) -> SkipWhile<'r, A, T> { - SkipWhile{iter: self, flag: false, predicate: predicate} - } - - #[inline] - fn take_while<'r>(self, predicate: &'r fn(&A) -> bool) -> TakeWhile<'r, A, T> { - TakeWhile{iter: self, flag: false, predicate: predicate} - } - - #[inline] - fn skip(self, n: uint) -> Skip<T> { - Skip{iter: self, n: n} - } - - // FIXME: #5898: should be called take - #[inline] - fn take_(self, n: uint) -> Take<T> { - Take{iter: self, n: n} - } - - #[inline] - fn scan<'r, St, B>(self, initial_state: St, f: &'r fn(&mut St, A) -> Option<B>) - -> Scan<'r, A, B, T, St> { - Scan{iter: self, f: f, state: initial_state} - } - - #[inline] - fn flat_map_<'r, B, U: Iterator<B>>(self, f: &'r fn(A) -> U) - -> FlatMap<'r, A, T, U> { - FlatMap{iter: self, f: f, frontiter: None, backiter: None } - } - - // FIXME: #5898: should be called `peek` - #[inline] - fn peek_<'r>(self, f: &'r fn(&A)) -> Peek<'r, A, T> { - Peek{iter: self, f: f} - } - - /// A shim implementing the `for` loop iteration protocol for iterator objects - #[inline] - fn advance(&mut self, f: &fn(A) -> bool) -> bool { - loop { - match self.next() { - Some(x) => { - if !f(x) { return false; } - } - None => { return true; } - } - } - } - - #[inline] - fn collect<B: FromIterator<A, T>>(&mut self) -> B { - FromIterator::from_iterator(self) - } - - #[inline] - fn to_owned_vec(&mut self) -> ~[A] { - self.collect() - } - - /// Return the `n`th item yielded by an iterator. - #[inline] - fn nth(&mut self, mut n: uint) -> Option<A> { - loop { - match self.next() { - Some(x) => if n == 0 { return Some(x) }, - None => return None - } - n -= 1; - } - } - - /// Return the last item yielded by an iterator. - #[inline] - fn last_(&mut self) -> Option<A> { - let mut last = None; - for x in *self { last = Some(x); } - last - } - - /// Reduce an iterator to an accumulated value - #[inline] - fn fold<B>(&mut self, init: B, f: &fn(B, A) -> B) -> B { - let mut accum = init; - loop { - match self.next() { - Some(x) => { accum = f(accum, x); } - None => { break; } - } - } - accum - } - - /// Count the number of items yielded by an iterator - #[inline] - fn len_(&mut self) -> uint { self.fold(0, |cnt, _x| cnt + 1) } - - #[inline] - fn all(&mut self, f: &fn(A) -> bool) -> bool { - for x in *self { if !f(x) { return false; } } - true - } - #[inline] fn any(&mut self, f: &fn(A) -> bool) -> bool { for x in *self { if f(x) { return true; } } @@ -633,7 +458,7 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { /// Return the first element satisfying the specified predicate #[inline] - fn find_(&mut self, predicate: &fn(&A) -> bool) -> Option<A> { + fn find(&mut self, predicate: &fn(&A) -> bool) -> Option<A> { for x in *self { if predicate(&x) { return Some(x) } } @@ -653,6 +478,7 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { None } + /// Count the number of elements satisfying the specified predicate #[inline] fn count(&mut self, predicate: &fn(A) -> bool) -> uint { let mut i = 0; @@ -662,6 +488,14 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { i } + /// Return the element that gives the maximum value from the specfied function + /// + /// # Example + /// + /// ~~~ {.rust} + /// let xs = [-3, 0, 1, 5, -10]; + /// assert_eq!(*xs.iter().max_by(|x| x.abs()).unwrap(), -10); + /// ~~~ #[inline] fn max_by<B: Ord>(&mut self, f: &fn(&A) -> B) -> Option<A> { self.fold(None, |max: Option<(A, B)>, x| { @@ -677,6 +511,14 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { }).map_move(|(x, _)| x) } + /// Return the element that gives the minimum value from the specfied function + /// + /// # Example + /// + /// ~~~ {.rust} + /// let xs = [-3, 0, 1, 5, -10]; + /// assert_eq!(*xs.iter().min_by(|x| x.abs()).unwrap(), 0); + /// ~~~ #[inline] fn min_by<B: Ord>(&mut self, f: &fn(&A) -> B) -> Option<A> { self.fold(None, |min: Option<(A, B)>, x| { @@ -693,6 +535,69 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { } } +/// A range iterator able to yield elements from both ends +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 + /// + /// The inverted iterator flips 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 + /// 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 + /// `uint::max_value` elements of the original iterator. + #[inline] + fn invert(self) -> Invert<Self> { + Invert{iter: self} + } +} + +/// An object implementing random access indexing by `uint` +/// +/// A `RandomAccessIterator` should be either infinite or a `DoubleEndedIterator`. +pub trait RandomAccessIterator<A>: Iterator<A> { + /// Return the number of indexable elements. At most `std::uint::max_value` + /// elements are indexable, even if the iterator represents a longer range. + fn indexable(&self) -> uint; + + /// Return an element at an index + fn idx(&self, index: uint) -> Option<A>; +} + +/// An double-ended iterator with the direction inverted +#[deriving(Clone)] +pub struct Invert<T> { + priv iter: T +} + +impl<A, T: DoubleEndedIterator<A>> Iterator<A> for Invert<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> { + #[inline] + fn next_back(&mut self) -> Option<A> { self.iter.next() } +} + +impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterator<A> + for Invert<T> { + #[inline] + fn indexable(&self) -> uint { self.iter.indexable() } + #[inline] + fn idx(&self, index: uint) -> Option<A> { + self.iter.idx(self.indexable() - index - 1) + } +} + /// A trait for iterators over elements which can be added together pub trait AdditiveIterator<A> { /// Iterates over the entire iterator, summing up all the elements @@ -701,7 +606,7 @@ pub trait AdditiveIterator<A> { /// /// ~~~ {.rust} /// let a = [1, 2, 3, 4, 5]; - /// let mut it = a.iter().transform(|&x| x); + /// let mut it = a.iter().map(|&x| x); /// assert!(it.sum() == 15); /// ~~~ fn sum(&mut self) -> A; @@ -790,7 +695,7 @@ pub trait ClonableIterator { /// # Example /// /// ~~~ {.rust} - /// let a = count(1,1).take_(1); + /// let a = count(1,1).take(1); /// let mut cy = a.cycle(); /// assert_eq!(cy.next(), Some(1)); /// assert_eq!(cy.next(), Some(1)); @@ -1531,7 +1436,7 @@ pub fn range<A: Add<A, A> + Ord + Clone + One>(start: A, stop: A) -> Range<A> { Range{state: start, stop: stop, one: One::one()} } -impl<A: Add<A, A> + Ord + Clone + One> Iterator<A> for Range<A> { +impl<A: Add<A, A> + Ord + Clone> Iterator<A> for Range<A> { #[inline] fn next(&mut self) -> Option<A> { if self.state < self.stop { @@ -1544,6 +1449,22 @@ impl<A: Add<A, A> + Ord + Clone + One> Iterator<A> for Range<A> { } } +impl<A: Sub<A, A> + Integer + Ord + Clone> DoubleEndedIterator<A> for Range<A> { + #[inline] + fn next_back(&mut self) -> Option<A> { + if self.stop > self.state { + // Integer doesn't technically define this rule, but we're going to assume that every + // Integer is reachable from every other one by adding or subtracting enough Ones. This + // seems like a reasonable-enough rule that every Integer should conform to, even if it + // can't be statically checked. + self.stop = self.stop - self.one; + Some(self.stop.clone()) + } else { + None + } + } +} + impl<A: Add<A, A> + Clone> Iterator<A> for Counter<A> { #[inline] fn next(&mut self) -> Option<A> { @@ -1601,7 +1522,7 @@ mod tests { #[test] fn test_counter_from_iter() { - let mut it = count(0, 5).take_(10); + let mut it = count(0, 5).take(10); let xs: ~[int] = FromIterator::from_iterator(&mut it); assert_eq!(xs, ~[0, 5, 10, 15, 20, 25, 30, 35, 40, 45]); } @@ -1611,7 +1532,7 @@ mod tests { let xs = [0u, 1, 2, 3, 4, 5]; let ys = [30u, 40, 50, 60]; let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; - let mut it = xs.iter().chain_(ys.iter()); + let mut it = xs.iter().chain(ys.iter()); let mut i = 0; for &x in it { assert_eq!(x, expected[i]); @@ -1619,8 +1540,8 @@ mod tests { } assert_eq!(i, expected.len()); - let ys = count(30u, 10).take_(4); - let mut it = xs.iter().transform(|&x| x).chain_(ys); + let ys = count(30u, 10).take(4); + let mut it = xs.iter().map(|&x| x).chain(ys); let mut i = 0; for x in it { assert_eq!(x, expected[i]); @@ -1631,7 +1552,7 @@ mod tests { #[test] fn test_filter_map() { - let mut it = count(0u, 1u).take_(10) + let mut it = count(0u, 1u).take(10) .filter_map(|x| if x.is_even() { Some(x*x) } else { None }); assert_eq!(it.collect::<~[uint]>(), ~[0*0, 2*2, 4*4, 6*6, 8*8]); } @@ -1688,7 +1609,7 @@ mod tests { fn test_iterator_take() { let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19]; let ys = [0u, 1, 2, 3, 5]; - let mut it = xs.iter().take_(5); + let mut it = xs.iter().take(5); let mut i = 0; for &x in it { assert_eq!(x, ys[i]); @@ -1720,7 +1641,7 @@ mod tests { fn test_iterator_flat_map() { let xs = [0u, 3, 6]; let ys = [0u, 1, 2, 3, 4, 5, 6, 7, 8]; - let mut it = xs.iter().flat_map_(|&x| count(x, 1).take_(3)); + let mut it = xs.iter().flat_map(|&x| count(x, 1).take(3)); let mut i = 0; for x in it { assert_eq!(x, ys[i]); @@ -1735,8 +1656,8 @@ mod tests { let mut n = 0; let ys = xs.iter() - .transform(|&x| x) - .peek_(|_| n += 1) + .map(|&x| x) + .peek(|_| n += 1) .collect::<~[uint]>(); assert_eq!(n, xs.len()); @@ -1767,13 +1688,13 @@ mod tests { #[test] fn test_cycle() { let cycle_len = 3; - let it = count(0u, 1).take_(cycle_len).cycle(); + let it = count(0u, 1).take(cycle_len).cycle(); assert_eq!(it.size_hint(), (uint::max_value, None)); - for (i, x) in it.take_(100).enumerate() { + for (i, x) in it.take(100).enumerate() { assert_eq!(i % cycle_len, x); } - let mut it = count(0u, 1).take_(0).cycle(); + let mut it = count(0u, 1).take(0).cycle(); assert_eq!(it.size_hint(), (0, Some(0))); assert_eq!(it.next(), None); } @@ -1789,48 +1710,48 @@ mod tests { #[test] fn test_iterator_last() { let v = &[0, 1, 2, 3, 4]; - assert_eq!(v.iter().last_().unwrap(), &4); - assert_eq!(v.slice(0, 1).iter().last_().unwrap(), &0); + assert_eq!(v.iter().last().unwrap(), &4); + assert_eq!(v.slice(0, 1).iter().last().unwrap(), &0); } #[test] fn test_iterator_len() { let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v.slice(0, 4).iter().len_(), 4); - assert_eq!(v.slice(0, 10).iter().len_(), 10); - assert_eq!(v.slice(0, 0).iter().len_(), 0); + assert_eq!(v.slice(0, 4).iter().len(), 4); + assert_eq!(v.slice(0, 10).iter().len(), 10); + assert_eq!(v.slice(0, 0).iter().len(), 0); } #[test] fn test_iterator_sum() { let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v.slice(0, 4).iter().transform(|&x| x).sum(), 6); - assert_eq!(v.iter().transform(|&x| x).sum(), 55); - assert_eq!(v.slice(0, 0).iter().transform(|&x| x).sum(), 0); + assert_eq!(v.slice(0, 4).iter().map(|&x| x).sum(), 6); + assert_eq!(v.iter().map(|&x| x).sum(), 55); + assert_eq!(v.slice(0, 0).iter().map(|&x| x).sum(), 0); } #[test] fn test_iterator_product() { let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v.slice(0, 4).iter().transform(|&x| x).product(), 0); - assert_eq!(v.slice(1, 5).iter().transform(|&x| x).product(), 24); - assert_eq!(v.slice(0, 0).iter().transform(|&x| x).product(), 1); + assert_eq!(v.slice(0, 4).iter().map(|&x| x).product(), 0); + assert_eq!(v.slice(1, 5).iter().map(|&x| x).product(), 24); + assert_eq!(v.slice(0, 0).iter().map(|&x| x).product(), 1); } #[test] fn test_iterator_max() { let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v.slice(0, 4).iter().transform(|&x| x).max(), Some(3)); - assert_eq!(v.iter().transform(|&x| x).max(), Some(10)); - assert_eq!(v.slice(0, 0).iter().transform(|&x| x).max(), None); + assert_eq!(v.slice(0, 4).iter().map(|&x| x).max(), Some(3)); + assert_eq!(v.iter().map(|&x| x).max(), Some(10)); + assert_eq!(v.slice(0, 0).iter().map(|&x| x).max(), None); } #[test] fn test_iterator_min() { let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v.slice(0, 4).iter().transform(|&x| x).min(), Some(0)); - assert_eq!(v.iter().transform(|&x| x).min(), Some(0)); - assert_eq!(v.slice(0, 0).iter().transform(|&x| x).min(), None); + assert_eq!(v.slice(0, 4).iter().map(|&x| x).min(), Some(0)); + assert_eq!(v.iter().map(|&x| x).min(), Some(0)); + assert_eq!(v.slice(0, 0).iter().map(|&x| x).min(), None); } #[test] @@ -1843,43 +1764,43 @@ mod tests { assert_eq!(c.size_hint(), (uint::max_value, None)); assert_eq!(vi.size_hint(), (10, Some(10))); - assert_eq!(c.take_(5).size_hint(), (5, Some(5))); + assert_eq!(c.take(5).size_hint(), (5, Some(5))); assert_eq!(c.skip(5).size_hint().second(), None); assert_eq!(c.take_while(|_| false).size_hint(), (0, None)); assert_eq!(c.skip_while(|_| false).size_hint(), (0, None)); assert_eq!(c.enumerate().size_hint(), (uint::max_value, None)); - assert_eq!(c.chain_(vi.transform(|&i| i)).size_hint(), (uint::max_value, None)); + assert_eq!(c.chain(vi.map(|&i| i)).size_hint(), (uint::max_value, None)); assert_eq!(c.zip(vi).size_hint(), (10, Some(10))); assert_eq!(c.scan(0, |_,_| Some(0)).size_hint(), (0, None)); assert_eq!(c.filter(|_| false).size_hint(), (0, None)); - assert_eq!(c.transform(|_| 0).size_hint(), (uint::max_value, None)); + assert_eq!(c.map(|_| 0).size_hint(), (uint::max_value, None)); assert_eq!(c.filter_map(|_| Some(0)).size_hint(), (0, None)); - assert_eq!(vi.take_(5).size_hint(), (5, Some(5))); - assert_eq!(vi.take_(12).size_hint(), (10, Some(10))); + assert_eq!(vi.take(5).size_hint(), (5, Some(5))); + assert_eq!(vi.take(12).size_hint(), (10, Some(10))); assert_eq!(vi.skip(3).size_hint(), (7, Some(7))); assert_eq!(vi.skip(12).size_hint(), (0, Some(0))); assert_eq!(vi.take_while(|_| false).size_hint(), (0, Some(10))); assert_eq!(vi.skip_while(|_| false).size_hint(), (0, Some(10))); assert_eq!(vi.enumerate().size_hint(), (10, Some(10))); - assert_eq!(vi.chain_(v2.iter()).size_hint(), (13, Some(13))); + assert_eq!(vi.chain(v2.iter()).size_hint(), (13, Some(13))); assert_eq!(vi.zip(v2.iter()).size_hint(), (3, Some(3))); assert_eq!(vi.scan(0, |_,_| Some(0)).size_hint(), (0, Some(10))); assert_eq!(vi.filter(|_| false).size_hint(), (0, Some(10))); - assert_eq!(vi.transform(|i| i+1).size_hint(), (10, Some(10))); + assert_eq!(vi.map(|i| i+1).size_hint(), (10, Some(10))); assert_eq!(vi.filter_map(|_| Some(0)).size_hint(), (0, Some(10))); } #[test] fn test_collect() { let a = ~[1, 2, 3, 4, 5]; - let b: ~[int] = a.iter().transform(|&x| x).collect(); + let b: ~[int] = a.iter().map(|&x| x).collect(); assert_eq!(a, b); } #[test] fn test_all() { - let v = ~&[1, 2, 3, 4, 5]; + let v: ~&[int] = ~&[1, 2, 3, 4, 5]; assert!(v.iter().all(|&x| x < 10)); assert!(!v.iter().all(|&x| x.is_even())); assert!(!v.iter().all(|&x| x > 100)); @@ -1888,7 +1809,7 @@ mod tests { #[test] fn test_any() { - let v = ~&[1, 2, 3, 4, 5]; + let v: ~&[int] = ~&[1, 2, 3, 4, 5]; assert!(v.iter().any(|&x| x < 10)); assert!(v.iter().any(|&x| x.is_even())); assert!(!v.iter().any(|&x| x > 100)); @@ -1897,10 +1818,10 @@ mod tests { #[test] fn test_find() { - let v = &[1, 3, 9, 27, 103, 14, 11]; - assert_eq!(*v.iter().find_(|x| *x & 1 == 0).unwrap(), 14); - assert_eq!(*v.iter().find_(|x| *x % 3 == 0).unwrap(), 3); - assert!(v.iter().find_(|x| *x % 12 == 0).is_none()); + let v: &[int] = &[1, 3, 9, 27, 103, 14, 11]; + assert_eq!(*v.iter().find(|x| *x & 1 == 0).unwrap(), 14); + assert_eq!(*v.iter().find(|x| *x % 3 == 0).unwrap(), 3); + assert!(v.iter().find(|x| *x % 12 == 0).is_none()); } #[test] @@ -1921,13 +1842,13 @@ mod tests { #[test] fn test_max_by() { - let xs = [-3, 0, 1, 5, -10]; + let xs: &[int] = &[-3, 0, 1, 5, -10]; assert_eq!(*xs.iter().max_by(|x| x.abs()).unwrap(), -10); } #[test] fn test_min_by() { - let xs = [-3, 0, 1, 5, -10]; + let xs: &[int] = &[-3, 0, 1, 5, -10]; assert_eq!(*xs.iter().min_by(|x| x.abs()).unwrap(), 0); } @@ -1937,13 +1858,13 @@ mod tests { let mut it = xs.iter(); it.next(); it.next(); - assert_eq!(it.invert().transform(|&x| x).collect::<~[int]>(), ~[16, 14, 12, 10, 8, 6]); + assert_eq!(it.invert().map(|&x| x).collect::<~[int]>(), ~[16, 14, 12, 10, 8, 6]); } #[test] fn test_double_ended_map() { let xs = [1, 2, 3, 4, 5, 6]; - let mut it = xs.iter().transform(|&x| x * -1); + let mut it = xs.iter().map(|&x| x * -1); assert_eq!(it.next(), Some(-1)); assert_eq!(it.next(), Some(-2)); assert_eq!(it.next_back(), Some(-6)); @@ -1977,7 +1898,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()).invert(); assert_eq!(it.next().unwrap(), &11) assert_eq!(it.next().unwrap(), &9) assert_eq!(it.next_back().unwrap(), &1) @@ -2013,7 +1934,7 @@ mod tests { fn test_double_ended_flat_map() { let u = [0u,1]; let v = [5,6,7,8]; - let mut it = u.iter().flat_map_(|x| v.slice(*x, v.len()).iter()); + let mut it = u.iter().flat_map(|x| v.slice(*x, v.len()).iter()); assert_eq!(it.next_back().unwrap(), &8); assert_eq!(it.next().unwrap(), &5); assert_eq!(it.next_back().unwrap(), &7); @@ -2030,7 +1951,7 @@ mod tests { fn test_random_access_chain() { let xs = [1, 2, 3, 4, 5]; let ys = ~[7, 9, 11]; - let mut it = xs.iter().chain_(ys.iter()); + let mut it = xs.iter().chain(ys.iter()); assert_eq!(it.idx(0).unwrap(), &1); assert_eq!(it.idx(5).unwrap(), &7); assert_eq!(it.idx(7).unwrap(), &11); @@ -2075,10 +1996,10 @@ mod tests { fn test_random_access_take() { let xs = [1, 2, 3, 4, 5]; let empty: &[int] = []; - check_randacc_iter(xs.iter().take_(3), 3); - check_randacc_iter(xs.iter().take_(20), xs.len()); - check_randacc_iter(xs.iter().take_(0), 0); - check_randacc_iter(empty.iter().take_(2), 0); + check_randacc_iter(xs.iter().take(3), 3); + check_randacc_iter(xs.iter().take(20), xs.len()); + check_randacc_iter(xs.iter().take(0), 0); + check_randacc_iter(empty.iter().take(2), 0); } #[test] @@ -2093,8 +2014,8 @@ mod tests { fn test_random_access_peek() { let xs = [1, 2, 3, 4, 5]; - // test .transform and .peek_ that don't implement Clone - let it = xs.iter().peek_(|_| {}); + // test .map and .peek that don't implement Clone + let it = xs.iter().peek(|_| {}); assert_eq!(xs.len(), it.indexable()); for (i, elt) in xs.iter().enumerate() { assert_eq!(Some(elt), it.idx(i)); @@ -2103,11 +2024,11 @@ mod tests { } #[test] - fn test_random_access_transform() { + fn test_random_access_map() { let xs = [1, 2, 3, 4, 5]; - // test .transform and .peek_ that don't implement Clone - let it = xs.iter().transform(|x| *x); + // test .map and .peek that don't implement Clone + let it = xs.iter().map(|x| *x); assert_eq!(xs.len(), it.indexable()); for (i, elt) in xs.iter().enumerate() { assert_eq!(Some(*elt), it.idx(i)); @@ -2118,7 +2039,20 @@ mod tests { fn test_random_access_cycle() { let xs = [1, 2, 3, 4, 5]; let empty: &[int] = []; - check_randacc_iter(xs.iter().cycle().take_(27), 27); + check_randacc_iter(xs.iter().cycle().take(27), 27); check_randacc_iter(empty.iter().cycle(), 0); } + + #[test] + fn test_double_ended_range() { + assert_eq!(range(11i, 14).invert().collect::<~[int]>(), ~[13i, 12, 11]); + for _ in range(10i, 0).invert() { + fail!("unreachable"); + } + + assert_eq!(range(11u, 14).invert().collect::<~[uint]>(), ~[13u, 12, 11]); + for _ in range(10u, 0).invert() { + fail!("unreachable"); + } + } } diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index f96d3ce263e..678704fe098 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -2652,7 +2652,7 @@ pub mod funcs { pub fn execvpe(c: *c_char, argv: **c_char, envp: **c_char) -> c_int; #[link_name = "_getcwd"] - pub fn getcwd(buf: *c_char, size: size_t) -> *c_char; + pub fn getcwd(buf: *mut c_char, size: size_t) -> *c_char; #[link_name = "_getpid"] pub fn getpid() -> c_int; #[link_name = "_isatty"] @@ -2804,7 +2804,7 @@ pub mod funcs { pub fn execvp(c: *c_char, argv: **c_char) -> c_int; pub fn fork() -> pid_t; pub fn fpathconf(filedes: c_int, name: c_int) -> c_long; - pub fn getcwd(buf: *c_char, size: size_t) -> *c_char; + pub fn getcwd(buf: *mut c_char, size: size_t) -> *c_char; pub fn getegid() -> gid_t; pub fn geteuid() -> uid_t; pub fn getgid() -> gid_t ; diff --git a/src/libstd/logging.rs b/src/libstd/logging.rs index 6e11d14aea9..7de55f48317 100644 --- a/src/libstd/logging.rs +++ b/src/libstd/logging.rs @@ -14,18 +14,11 @@ use option::*; use os; use either::*; use rt; -use rt::OldTaskContext; use rt::logging::{Logger, StdErrLogger}; /// Turns on logging to stdout globally pub fn console_on() { - if rt::context() == OldTaskContext { - unsafe { - rustrt::rust_log_console_on(); - } - } else { - rt::logging::console_on(); - } + rt::logging::console_on(); } /** @@ -41,45 +34,24 @@ pub fn console_off() { return; } - if rt::context() == OldTaskContext { - unsafe { - rustrt::rust_log_console_off(); - } - } else { - rt::logging::console_off(); - } + rt::logging::console_off(); } #[cfg(not(test))] #[lang="log_type"] #[allow(missing_doc)] -pub fn log_type<T>(level: u32, object: &T) { - use cast; - use container::Container; +pub fn log_type<T>(_level: u32, object: &T) { use io; - use libc; use repr; - use rt; use str; - use vec; let bytes = do io::with_bytes_writer |writer| { repr::write_repr(writer, object); }; - match rt::context() { - rt::OldTaskContext => { - unsafe { - let len = bytes.len() as libc::size_t; - rustrt::rust_log_str(level, cast::transmute(vec::raw::to_ptr(bytes)), len); - } - } - _ => { - // XXX: Bad allocation - let msg = str::from_bytes(bytes); - newsched_log_str(msg); - } - } + // XXX: Bad allocation + let msg = str::from_bytes(bytes); + newsched_log_str(msg); } fn newsched_log_str(msg: ~str) { @@ -100,15 +72,3 @@ fn newsched_log_str(msg: ~str) { } } } - -pub mod rustrt { - use libc; - - extern { - pub fn rust_log_console_on(); - pub fn rust_log_console_off(); - pub fn rust_log_str(level: u32, - string: *libc::c_char, - size: libc::size_t); - } -} diff --git a/src/libstd/nil.rs b/src/libstd/nil.rs index 360db9608b6..d2e9cf9ae7e 100644 --- a/src/libstd/nil.rs +++ b/src/libstd/nil.rs @@ -33,12 +33,6 @@ impl Eq for () { impl Ord for () { #[inline] fn lt(&self, _other: &()) -> bool { false } - #[inline] - fn le(&self, _other: &()) -> bool { true } - #[inline] - fn ge(&self, _other: &()) -> bool { true } - #[inline] - fn gt(&self, _other: &()) -> bool { false } } #[cfg(not(test))] diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index c7db60e6fd2..60527905779 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -278,18 +278,22 @@ impl One for f64 { #[cfg(not(test))] impl Add<f64,f64> for f64 { + #[inline] fn add(&self, other: &f64) -> f64 { *self + *other } } #[cfg(not(test))] impl Sub<f64,f64> for f64 { + #[inline] fn sub(&self, other: &f64) -> f64 { *self - *other } } #[cfg(not(test))] impl Mul<f64,f64> for f64 { + #[inline] fn mul(&self, other: &f64) -> f64 { *self * *other } } #[cfg(not(test))] impl Div<f64,f64> for f64 { + #[inline] fn div(&self, other: &f64) -> f64 { *self / *other } } #[cfg(not(test))] diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 9842a570d7e..41da9a6ccbe 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -124,26 +124,12 @@ pub fn range_step_inclusive(start: $T, last: $T, step: $T, it: &fn($T) -> bool) range_step_core(start, last, step, Closed, it) } - -#[inline] -/// Iterate over the range (`hi`..`lo`] -pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool { - if hi == min_value { return true; } - range_step_inclusive(hi-1, lo, -1 as $T, it) -} - impl Num for $T {} #[cfg(not(test))] impl Ord for $T { #[inline] fn lt(&self, other: &$T) -> bool { return (*self) < (*other); } - #[inline] - fn le(&self, other: &$T) -> bool { return (*self) <= (*other); } - #[inline] - fn ge(&self, other: &$T) -> bool { return (*self) >= (*other); } - #[inline] - fn gt(&self, other: &$T) -> bool { return (*self) > (*other); } } #[cfg(not(test))] @@ -889,10 +875,6 @@ mod tests { fn test_ranges() { let mut l = ~[]; - do range_rev(14,11) |i| { - l.push(i); - true - }; do range_step(20,26,2) |i| { l.push(i); true @@ -917,8 +899,7 @@ mod tests { l.push(i); true }; - assert_eq!(l, ~[13,12,11, - 20,22,24, + assert_eq!(l, ~[20,22,24, 36,34,32, max_value-2, max_value-3,max_value-1, @@ -926,9 +907,6 @@ mod tests { min_value+3,min_value+1]); // None of the `fail`s should execute. - do range_rev(0,10) |_i| { - fail!(~"unreachable"); - }; do range_step(10,0,1) |_i| { fail!(~"unreachable"); }; diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index 7ab3c81b61f..1f22343ad9c 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -422,9 +422,9 @@ pub fn float_to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Float+Round+ // Some constants for from_str_bytes_common's input validation, // they define minimum radix values for which the character is a valid digit. -priv static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u; -priv static DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u; -priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u; +static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u; +static DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u; +static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u; /** * Parses a byte slice as a number. This is meant to diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index a2874c96703..86b5b4ddfc0 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -125,25 +125,12 @@ pub fn range_step_inclusive(start: $T, last: $T, step: $T_SIGNED, it: &fn($T) -> range_step_core(start, last, step, Closed, it) } -#[inline] -/// Iterate over the range (`hi`..`lo`] -pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool { - if hi == min_value { return true; } - range_step_inclusive(hi-1, lo, -1 as $T_SIGNED, it) -} - impl Num for $T {} #[cfg(not(test))] impl Ord for $T { #[inline] fn lt(&self, other: &$T) -> bool { (*self) < (*other) } - #[inline] - fn le(&self, other: &$T) -> bool { (*self) <= (*other) } - #[inline] - fn ge(&self, other: &$T) -> bool { (*self) >= (*other) } - #[inline] - fn gt(&self, other: &$T) -> bool { (*self) > (*other) } } #[cfg(not(test))] @@ -654,10 +641,6 @@ mod tests { pub fn test_ranges() { let mut l = ~[]; - do range_rev(14,11) |i| { - l.push(i); - true - }; do range_step(20,26,2) |i| { l.push(i); true @@ -683,8 +666,7 @@ mod tests { true }; - assert_eq!(l, ~[13,12,11, - 20,22,24, + assert_eq!(l, ~[20,22,24, 36,34,32, max_value-2, max_value-3,max_value-1, @@ -692,9 +674,6 @@ mod tests { min_value+3,min_value+1]); // None of the `fail`s should execute. - do range_rev(0,0) |_i| { - fail!("unreachable"); - }; do range_step(10,0,1) |_i| { fail!("unreachable"); }; diff --git a/src/libstd/option.rs b/src/libstd/option.rs index 66b30d8dd03..c1999ae47d6 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -134,7 +134,7 @@ impl<T> Option<T> { /// Return a consuming iterator over the possibly contained value #[inline] - pub fn consume(self) -> OptionIterator<T> { + pub fn move_iter(self) -> OptionIterator<T> { OptionIterator{opt: self} } diff --git a/src/libstd/os.rs b/src/libstd/os.rs index f246a61a4d5..c916be79c53 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -28,11 +28,11 @@ #[allow(missing_doc)]; -use cast; +use c_str::ToCStr; use clone::Clone; use container::Container; use io; -use iterator::{IteratorUtil, range}; +use iterator::range; use libc; use libc::{c_char, c_void, c_int, size_t}; use libc::FILE; @@ -61,11 +61,8 @@ pub mod rustrt { use libc; extern { - pub fn rust_get_argc() -> c_int; - pub fn rust_get_argv() -> **c_char; pub fn rust_path_is_dir(path: *libc::c_char) -> c_int; pub fn rust_path_exists(path: *libc::c_char) -> c_int; - pub fn rust_set_exit_status(code: libc::intptr_t); } } @@ -73,14 +70,15 @@ pub static TMPBUF_SZ : uint = 1000u; static BUF_BYTES : uint = 2048u; pub fn getcwd() -> Path { - let buf = [0 as libc::c_char, ..BUF_BYTES]; - unsafe { - if(0 as *libc::c_char == libc::getcwd( - &buf[0], - BUF_BYTES as libc::size_t)) { - fail!(); + let mut buf = [0 as libc::c_char, ..BUF_BYTES]; + do buf.as_mut_buf |buf, len| { + unsafe { + if libc::getcwd(buf, len as size_t).is_null() { + fail!() + } + + Path(str::raw::from_c_str(buf as *c_char)) } - Path(str::raw::from_c_str(&buf[0])) } } @@ -91,7 +89,7 @@ pub fn fill_charp_buf(f: &fn(*mut c_char, size_t) -> bool) -> Option<~str> { do buf.as_mut_buf |b, sz| { if f(b, sz as size_t) { unsafe { - Some(str::raw::from_buf(b as *u8)) + Some(str::raw::from_c_str(b as *c_char)) } } else { None @@ -241,11 +239,13 @@ pub fn env() -> ~[(~str,~str)] { pub fn getenv(n: &str) -> Option<~str> { unsafe { do with_env_lock { - let s = n.as_c_str(|s| libc::getenv(s as *libc::c_char)); - if ptr::null::<u8>() == cast::transmute(s) { + let s = do n.to_c_str().with_ref |buf| { + libc::getenv(buf) + }; + if s.is_null() { None } else { - Some(str::raw::from_buf(cast::transmute(s))) + Some(str::raw::from_c_str(s)) } } } @@ -274,8 +274,8 @@ pub fn getenv(n: &str) -> Option<~str> { pub fn setenv(n: &str, v: &str) { unsafe { do with_env_lock { - do n.to_str().as_c_str |nbuf| { - do v.to_str().as_c_str |vbuf| { + do n.to_c_str().with_ref |nbuf| { + do v.to_c_str().with_ref |vbuf| { libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1); } } @@ -306,7 +306,7 @@ pub fn unsetenv(n: &str) { fn _unsetenv(n: &str) { unsafe { do with_env_lock { - do n.to_str().as_c_str |nbuf| { + do n.to_c_str().with_ref |nbuf| { libc::funcs::posix01::unistd::unsetenv(nbuf); } } @@ -328,7 +328,7 @@ pub fn unsetenv(n: &str) { } pub fn fdopen(fd: c_int) -> *FILE { - do "r".as_c_str |modebuf| { + do "r".to_c_str().with_ref |modebuf| { unsafe { libc::fdopen(fd, modebuf) } @@ -461,18 +461,18 @@ pub fn self_exe_path() -> Option<Path> { unsafe { use libc::funcs::posix01::unistd::readlink; - let mut path_str = str::with_capacity(TMPBUF_SZ); - let len = do path_str.as_c_str |buf| { - let buf = buf as *mut c_char; - do "/proc/self/exe".as_c_str |proc_self_buf| { - readlink(proc_self_buf, buf, TMPBUF_SZ as size_t) + let mut path = [0 as c_char, .. TMPBUF_SZ]; + + do path.as_mut_buf |buf, len| { + let len = do "/proc/self/exe".to_c_str().with_ref |proc_self_buf| { + readlink(proc_self_buf, buf, len as size_t) as uint + }; + + if len == -1 { + None + } else { + Some(str::raw::from_buf_len(buf as *u8, len)) } - }; - if len == -1 { - None - } else { - str::raw::set_len(&mut path_str, len as uint); - Some(path_str) } } } @@ -593,7 +593,7 @@ pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool { /// Indicates whether a path represents a directory pub fn path_is_dir(p: &Path) -> bool { unsafe { - do p.to_str().as_c_str |buf| { + do p.to_c_str().with_ref |buf| { rustrt::rust_path_is_dir(buf) != 0 as c_int } } @@ -602,7 +602,7 @@ pub fn path_is_dir(p: &Path) -> bool { /// Indicates whether a path exists pub fn path_exists(p: &Path) -> bool { unsafe { - do p.to_str().as_c_str |buf| { + do p.to_c_str().with_ref |buf| { rustrt::rust_path_exists(buf) != 0 as c_int } } @@ -637,7 +637,7 @@ pub fn make_dir(p: &Path, mode: c_int) -> bool { use os::win32::as_utf16_p; // FIXME: turn mode into something useful? #2623 do as_utf16_p(p.to_str()) |buf| { - libc::CreateDirectoryW(buf, cast::transmute(0)) + libc::CreateDirectoryW(buf, ptr::mut_null()) != (0 as libc::BOOL) } } @@ -645,7 +645,7 @@ pub fn make_dir(p: &Path, mode: c_int) -> bool { #[cfg(unix)] fn mkdir(p: &Path, mode: c_int) -> bool { - do p.to_str().as_c_str |buf| { + do p.to_c_str().with_ref |buf| { unsafe { libc::mkdir(buf, mode as libc::mode_t) == (0 as c_int) } @@ -694,13 +694,15 @@ pub fn list_dir(p: &Path) -> ~[~str] { extern { fn rust_list_dir_val(ptr: *dirent_t) -> *libc::c_char; } - let input = p.to_str(); let mut strings = ~[]; - let input_ptr = ::cast::transmute(&input[0]); debug!("os::list_dir -- BEFORE OPENDIR"); - let dir_ptr = opendir(input_ptr); + + let dir_ptr = do p.to_c_str().with_ref |buf| { + opendir(buf) + }; + if (dir_ptr as uint != 0) { - debug!("os::list_dir -- opendir() SUCCESS"); + debug!("os::list_dir -- opendir() SUCCESS"); let mut entry_ptr = readdir(dir_ptr); while (entry_ptr as uint != 0) { strings.push(str::raw::from_c_str(rust_list_dir_val( @@ -710,7 +712,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { closedir(dir_ptr); } else { - debug!("os::list_dir -- opendir() FAILURE"); + debug!("os::list_dir -- opendir() FAILURE"); } debug!( "os::list_dir -- AFTER -- #: %?", @@ -726,6 +728,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { FindNextFileW, FindClose, }; + use libc::types::os::arch::extra::HANDLE; use os::win32::{ as_utf16_p }; @@ -740,10 +743,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { do as_utf16_p(star(p).to_str()) |path_ptr| { let mut strings = ~[]; let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint); - let find_handle = - FindFirstFileW( - path_ptr, - ::cast::transmute(wfd_ptr)); + let find_handle = FindFirstFileW(path_ptr, wfd_ptr as HANDLE); if find_handle as libc::c_int != INVALID_HANDLE_VALUE { let mut more_files = 1 as libc::c_int; while more_files != 0 { @@ -757,9 +757,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { let fp_str = str::from_utf16(fp_vec); strings.push(fp_str); } - more_files = FindNextFileW( - find_handle, - ::cast::transmute(wfd_ptr)); + more_files = FindNextFileW(find_handle, wfd_ptr as HANDLE); } FindClose(find_handle); free(wfd_ptr) @@ -767,7 +765,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { strings } } - do get_list(p).consume_iter().filter |filename| { + do get_list(p).move_iter().filter |filename| { "." != *filename && ".." != *filename }.collect() } @@ -821,7 +819,7 @@ pub fn remove_dir(p: &Path) -> bool { #[cfg(unix)] fn rmdir(p: &Path) -> bool { - do p.to_str().as_c_str |buf| { + do p.to_c_str().with_ref |buf| { unsafe { libc::rmdir(buf) == (0 as c_int) } @@ -846,7 +844,7 @@ pub fn change_dir(p: &Path) -> bool { #[cfg(unix)] fn chdir(p: &Path) -> bool { - do p.to_str().as_c_str |buf| { + do p.to_c_str().with_ref |buf| { unsafe { libc::chdir(buf) == (0 as c_int) } @@ -874,8 +872,8 @@ pub fn copy_file(from: &Path, to: &Path) -> bool { #[cfg(unix)] fn do_copy_file(from: &Path, to: &Path) -> bool { unsafe { - let istream = do from.to_str().as_c_str |fromp| { - do "rb".as_c_str |modebuf| { + let istream = do from.to_c_str().with_ref |fromp| { + do "rb".to_c_str().with_ref |modebuf| { libc::fopen(fromp, modebuf) } }; @@ -886,8 +884,8 @@ pub fn copy_file(from: &Path, to: &Path) -> bool { let from_mode = from.get_mode().expect("copy_file: couldn't get permissions \ for source file"); - let ostream = do to.to_str().as_c_str |top| { - do "w+b".as_c_str |modebuf| { + let ostream = do to.to_c_str().with_ref |top| { + do "w+b".to_c_str().with_ref |modebuf| { libc::fopen(top, modebuf) } }; @@ -919,7 +917,7 @@ pub fn copy_file(from: &Path, to: &Path) -> bool { fclose(ostream); // Give the new file the old file's permissions - if do to.to_str().as_c_str |to_buf| { + if do to.to_c_str().with_ref |to_buf| { libc::chmod(to_buf, from_mode as libc::mode_t) } != 0 { return false; // should be a condition... @@ -946,7 +944,7 @@ pub fn remove_file(p: &Path) -> bool { #[cfg(unix)] fn unlink(p: &Path) -> bool { unsafe { - do p.to_str().as_c_str |buf| { + do p.to_c_str().with_ref |buf| { libc::unlink(buf) == (0 as c_int) } } @@ -1038,14 +1036,15 @@ pub fn last_os_error() -> ~str { } let mut buf = [0 as c_char, ..TMPBUF_SZ]; - unsafe { - let err = strerror_r(errno() as c_int, &mut buf[0], - TMPBUF_SZ as size_t); - if err < 0 { - fail!("strerror_r failure"); - } - str::raw::from_c_str(&buf[0]) + do buf.as_mut_buf |buf, len| { + unsafe { + if strerror_r(errno() as c_int, buf, len as size_t) < 0 { + fail!("strerror_r failure"); + } + + str::raw::from_c_str(buf as *c_char) + } } } @@ -1071,23 +1070,31 @@ pub fn last_os_error() -> ~str { static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; - let mut buf = [0 as c_char, ..TMPBUF_SZ]; - // This value is calculated from the macro // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) let langId = 0x0800 as DWORD; let err = errno() as DWORD; + + let mut buf = [0 as c_char, ..TMPBUF_SZ]; + unsafe { - let res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - ptr::mut_null(), err, langId, - &mut buf[0], TMPBUF_SZ as DWORD, - ptr::null()); - if res == 0 { - fail!("[%?] FormatMessage failure", errno()); + do buf.as_mut_buf |buf, len| { + let res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + ptr::mut_null(), + err, + langId, + buf, + len as DWORD, + ptr::null()); + if res == 0 { + fail!("[%?] FormatMessage failure", errno()); + } } - str::raw::from_c_str(&buf[0]) + do buf.as_imm_buf |buf, _len| { + str::raw::from_c_str(buf) + } } } @@ -1104,15 +1111,7 @@ pub fn last_os_error() -> ~str { */ pub fn set_exit_status(code: int) { use rt; - use rt::OldTaskContext; - - if rt::context() == OldTaskContext { - unsafe { - rustrt::rust_set_exit_status(code as libc::intptr_t); - } - } else { - rt::util::set_exit_status(code); - } + rt::util::set_exit_status(code); } unsafe fn load_argc_and_argv(argc: c_int, argv: **c_char) -> ~[~str] { @@ -1142,19 +1141,10 @@ pub fn real_args() -> ~[~str] { #[cfg(target_os = "freebsd")] pub fn real_args() -> ~[~str] { use rt; - use rt::TaskContext; - if rt::context() == TaskContext { - match rt::args::clone() { - Some(args) => args, - None => fail!("process arguments not initialized") - } - } else { - unsafe { - let argc = rustrt::rust_get_argc(); - let argv = rustrt::rust_get_argv(); - load_argc_and_argv(argc, argv) - } + match rt::args::clone() { + Some(args) => args, + None => fail!("process arguments not initialized") } } @@ -1180,7 +1170,7 @@ pub fn real_args() -> ~[~str] { } unsafe { - LocalFree(cast::transmute(szArgList)); + LocalFree(szArgList as *c_void); } return args; @@ -1292,7 +1282,7 @@ pub fn glob(pattern: &str) -> ~[Path] { } let mut g = default_glob_t(); - do pattern.as_c_str |c_pattern| { + do pattern.to_c_str().with_ref |c_pattern| { unsafe { libc::glob(c_pattern, 0, ptr::null(), &mut g) } }; do(|| { @@ -1697,6 +1687,7 @@ pub mod consts { #[cfg(test)] mod tests { + use c_str::ToCStr; use libc::{c_int, c_void, size_t}; use libc; use option::Some; @@ -1709,7 +1700,6 @@ mod tests { use rand; use run; use str::StrSlice; - use vec::CopyableVector; use libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; @@ -1932,39 +1922,39 @@ mod tests { #[test] fn copy_file_ok() { unsafe { - let tempdir = getcwd(); // would like to use $TMPDIR, - // doesn't seem to work on Linux - assert!((tempdir.to_str().len() > 0u)); - let input = tempdir.push("in.txt"); - let out = tempdir.push("out.txt"); - - /* Write the temp input file */ - let ostream = do input.to_str().as_c_str |fromp| { - do "w+b".as_c_str |modebuf| { + let tempdir = getcwd(); // would like to use $TMPDIR, + // doesn't seem to work on Linux + assert!((tempdir.to_str().len() > 0u)); + let input = tempdir.push("in.txt"); + let out = tempdir.push("out.txt"); + + /* Write the temp input file */ + let ostream = do input.to_c_str().with_ref |fromp| { + do "w+b".to_c_str().with_ref |modebuf| { libc::fopen(fromp, modebuf) } - }; - assert!((ostream as uint != 0u)); - let s = ~"hello"; - let mut buf = s.as_bytes_with_null().to_owned(); - let len = buf.len(); - do buf.as_mut_buf |b, _len| { - assert_eq!(libc::fwrite(b as *c_void, 1u as size_t, - (s.len() + 1u) as size_t, ostream), - len as size_t) - } - assert_eq!(libc::fclose(ostream), (0u as c_int)); - let in_mode = input.get_mode(); - let rs = os::copy_file(&input, &out); - if (!os::path_exists(&input)) { - fail!("%s doesn't exist", input.to_str()); - } - assert!((rs)); - let rslt = run::process_status("diff", [input.to_str(), out.to_str()]); - assert_eq!(rslt, 0); - assert_eq!(out.get_mode(), in_mode); - assert!((remove_file(&input))); - assert!((remove_file(&out))); + }; + assert!((ostream as uint != 0u)); + let s = ~"hello"; + do "hello".to_c_str().with_ref |buf| { + let write_len = libc::fwrite(buf as *c_void, + 1u as size_t, + (s.len() + 1u) as size_t, + ostream); + assert_eq!(write_len, (s.len() + 1) as size_t) + } + assert_eq!(libc::fclose(ostream), (0u as c_int)); + let in_mode = input.get_mode(); + let rs = os::copy_file(&input, &out); + if (!os::path_exists(&input)) { + fail!("%s doesn't exist", input.to_str()); + } + assert!((rs)); + let rslt = run::process_status("diff", [input.to_str(), out.to_str()]); + assert_eq!(rslt, 0); + assert_eq!(out.get_mode(), in_mode); + assert!((remove_file(&input))); + assert!((remove_file(&out))); } } @@ -2023,11 +2013,11 @@ mod tests { remove_file(&path); let fd = unsafe { - let fd = do path.to_str().as_c_str |path| { + let fd = do path.to_c_str().with_ref |path| { open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR) }; lseek_(fd, size); - do "x".as_c_str |x| { + do "x".to_c_str().with_ref |x| { assert!(write(fd, x as *c_void, 1) == 1); } fd diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 76001ae4188..177f0efb6da 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -16,16 +16,19 @@ Cross-platform file path handling #[allow(missing_doc)]; +use c_str::ToCStr; +use c_str; use clone::Clone; -use container::Container; use cmp::Eq; -use iterator::{Iterator, IteratorUtil}; +use container::Container; +use iterator::{Iterator, range}; use libc; +use num; use option::{None, Option, Some}; use str::{OwnedStr, Str, StrSlice, StrVector}; use to_str::ToStr; use ascii::{AsciiCast, AsciiStr}; -use vec::{OwnedVector, ImmutableVector}; +use vec::{OwnedVector, ImmutableVector, OwnedCopyableVector}; #[cfg(windows)] pub use Path = self::WindowsPath; @@ -124,6 +127,43 @@ pub trait GenericPath { /// True if `self` is an ancestor of `other`. See `test_is_ancestor_of` for examples fn is_ancestor_of(&self, (&Self)) -> bool; + + /// Find the relative path from one file to another + fn get_relative_to(&self, abs2: (&Self)) -> Self { + assert!(self.is_absolute()); + assert!(abs2.is_absolute()); + let abs1 = self.normalize(); + let abs2 = abs2.normalize(); + + let split1: &[~str] = abs1.components(); + let split2: &[~str] = abs2.components(); + let len1 = split1.len(); + let len2 = split2.len(); + assert!(len1 > 0); + assert!(len2 > 0); + + let max_common_path = num::min(len1, len2) - 1; + let mut start_idx = 0; + while start_idx < max_common_path + && split1[start_idx] == split2[start_idx] { + start_idx += 1; + } + + let mut path: ~[~str] = ~[]; + for _ in range(start_idx, len1 - 1) { path.push(~".."); }; + + path.push_all(split2.slice(start_idx, len2 - 1)); + + let mut result: Self = GenericPath::from_str("."); + if !path.is_empty() { + // Without this type hint, the typechecker doesn't seem to like it + let p: Self = GenericPath::from_str(""); + result = p.push_many(path); + }; + result + } + + fn components(self) -> ~[~str]; } #[cfg(target_os = "linux")] @@ -341,7 +381,7 @@ mod stat { #[cfg(target_os = "win32")] impl WindowsPath { pub fn stat(&self) -> Option<libc::stat> { - do self.to_str().as_c_str |buf| { + do self.to_c_str().with_ref |buf| { let mut st = stat::arch::default_stat(); match unsafe { libc::stat(buf, &mut st) } { 0 => Some(st), @@ -375,7 +415,7 @@ impl WindowsPath { #[cfg(not(target_os = "win32"))] impl PosixPath { pub fn stat(&self) -> Option<libc::stat> { - do self.to_str().as_c_str |buf| { + do self.to_c_str().with_ref |buf| { let mut st = stat::arch::default_stat(); match unsafe { libc::stat(buf as *libc::c_char, &mut st) } { 0 => Some(st), @@ -453,7 +493,7 @@ impl PosixPath { #[cfg(unix)] impl PosixPath { pub fn lstat(&self) -> Option<libc::stat> { - do self.to_str().as_c_str |buf| { + do self.to_c_str().with_ref |buf| { let mut st = stat::arch::default_stat(); match unsafe { libc::lstat(buf, &mut st) } { 0 => Some(st), @@ -525,6 +565,12 @@ impl ToStr for PosixPath { } } +impl ToCStr for PosixPath { + fn to_c_str(&self) -> c_str::CString { + self.to_str().to_c_str() + } +} + // FIXME (#3227): when default methods in traits are working, de-duplicate // PosixPath and WindowsPath, most of their methods are common. impl GenericPath for PosixPath { @@ -703,6 +749,7 @@ impl GenericPath for PosixPath { self.is_ancestor_of(&other.pop())) } + fn components(self) -> ~[~str] { self.components } } @@ -730,6 +777,11 @@ impl ToStr for WindowsPath { } } +impl c_str::ToCStr for WindowsPath { + fn to_c_str(&self) -> c_str::CString { + self.to_str().to_c_str() + } +} impl GenericPath for WindowsPath { fn from_str(s: &str) -> WindowsPath { @@ -909,7 +961,7 @@ impl GenericPath for WindowsPath { match self.filestem() { Some(stem) => { // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use - // to_ascii_consume and to_str_consume to not do a unnecessary copy. + // to_ascii_move and to_str_move to not do a unnecessary copy. match stem.to_ascii().to_lower().to_str_ascii() { ~"con" | ~"aux" | ~"com1" | ~"com2" | ~"com3" | ~"com4" | ~"lpt1" | ~"lpt2" | ~"lpt3" | ~"prn" | ~"nul" => true, @@ -968,7 +1020,7 @@ impl GenericPath for WindowsPath { None => None, // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use - // to_ascii_consume and to_str_consume to not do a unnecessary copy. + // to_ascii_move and to_str_move to not do a unnecessary copy. Some(ref device) => Some(device.to_ascii().to_upper().to_str_ascii()) }, is_absolute: self.is_absolute, @@ -985,6 +1037,8 @@ impl GenericPath for WindowsPath { (!other.components.is_empty() && !(self.components.is_empty() && !self.is_absolute) && self.is_ancestor_of(&other.pop())) } + + fn components(self) -> ~[~str] { self.components } } pub fn normalize(components: &[~str]) -> ~[~str] { @@ -1341,4 +1395,124 @@ mod tests { } + #[test] + fn test_relative_to1() { + let p1 = PosixPath("/usr/bin/rustc"); + let p2 = PosixPath("/usr/lib/mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../lib")); + + let p1 = WindowsPath("C:\\usr\\bin\\rustc"); + let p2 = WindowsPath("C:\\usr\\lib\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\lib")); + + } + + #[test] + fn test_relative_to2() { + let p1 = PosixPath("/usr/bin/rustc"); + let p2 = PosixPath("/usr/bin/../lib/mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../lib")); + + let p1 = WindowsPath("C:\\usr\\bin\\rustc"); + let p2 = WindowsPath("C:\\usr\\bin\\..\\lib\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\lib")); + } + + #[test] + fn test_relative_to3() { + let p1 = PosixPath("/usr/bin/whatever/rustc"); + let p2 = PosixPath("/usr/lib/whatever/mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../../lib/whatever")); + + let p1 = WindowsPath("C:\\usr\\bin\\whatever\\rustc"); + let p2 = WindowsPath("C:\\usr\\lib\\whatever\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\..\\lib\\whatever")); + + } + + #[test] + fn test_relative_to4() { + let p1 = PosixPath("/usr/bin/whatever/../rustc"); + let p2 = PosixPath("/usr/lib/whatever/mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../lib/whatever")); + + let p1 = WindowsPath("C:\\usr\\bin\\whatever\\..\\rustc"); + let p2 = WindowsPath("C:\\usr\\lib\\whatever\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\lib\\whatever")); + + } + + #[test] + fn test_relative_to5() { + let p1 = PosixPath("/usr/bin/whatever/../rustc"); + let p2 = PosixPath("/usr/lib/whatever/../mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("../lib")); + + let p1 = WindowsPath("C:\\usr\\bin/whatever\\..\\rustc"); + let p2 = WindowsPath("C:\\usr\\lib\\whatever\\..\\mylib"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..\\lib")); + } + + #[test] + fn test_relative_to6() { + let p1 = PosixPath("/1"); + let p2 = PosixPath("/2/3"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("2")); + + let p1 = WindowsPath("C:\\1"); + let p2 = WindowsPath("C:\\2\\3"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("2")); + + } + + #[test] + fn test_relative_to7() { + let p1 = PosixPath("/1/2"); + let p2 = PosixPath("/3"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, PosixPath("..")); + + let p1 = WindowsPath("C:\\1\\2"); + let p2 = WindowsPath("C:\\3"); + let res = p1.get_relative_to(&p2); + assert_eq!(res, WindowsPath("..")); + + } + + #[test] + fn test_relative_to8() { + let p1 = PosixPath("/home/brian/Dev/rust/build/").push_rel( + &PosixPath("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so")); + let p2 = PosixPath("/home/brian/Dev/rust/build/stage2/bin/..").push_rel( + &PosixPath("lib/rustc/i686-unknown-linux-gnu/lib/libstd.so")); + let res = p1.get_relative_to(&p2); + debug!("test_relative_to8: %s vs. %s", + res.to_str(), + PosixPath(".").to_str()); + assert_eq!(res, PosixPath(".")); + + let p1 = WindowsPath("C:\\home\\brian\\Dev\\rust\\build\\").push_rel( + &WindowsPath("stage2\\lib\\rustc\\i686-unknown-linux-gnu\\lib\\librustc.so")); + let p2 = WindowsPath("\\home\\brian\\Dev\\rust\\build\\stage2\\bin\\..").push_rel( + &WindowsPath("lib\\rustc\\i686-unknown-linux-gnu\\lib\\libstd.so")); + let res = p1.get_relative_to(&p2); + debug!("test_relative_to8: %s vs. %s", + res.to_str(), + WindowsPath(".").to_str()); + assert_eq!(res, WindowsPath(".")); + + } + } diff --git a/src/libstd/pipes.rs b/src/libstd/pipes.rs deleted file mode 100644 index 78f937e058a..00000000000 --- a/src/libstd/pipes.rs +++ /dev/null @@ -1,870 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! Runtime support for message passing with protocol enforcement. - - -Pipes consist of two endpoints. One endpoint can send messages and -the other can receive messages. The set of legal messages and which -directions they can flow at any given point are determined by a -protocol. Below is an example protocol. - -~~~ {.rust} -proto! pingpong ( - ping: send { - ping -> pong - } - pong: recv { - pong -> ping - } -) -~~~ - -The `proto!` syntax extension will convert this into a module called -`pingpong`, which includes a set of types and functions that can be -used to write programs that follow the pingpong protocol. - -*/ - -/* IMPLEMENTATION NOTES - -The initial design for this feature is available at: - -https://github.com/eholk/rust/wiki/Proposal-for-channel-contracts - -Much of the design in that document is still accurate. There are -several components for the pipe implementation. First of all is the -syntax extension. To see how that works, it is best see comments in -libsyntax/ext/pipes.rs. - -This module includes two related pieces of the runtime -implementation: support for unbounded and bounded -protocols. The main difference between the two is the type of the -buffer that is carried along in the endpoint data structures. - - -The heart of the implementation is the packet type. It contains a -header and a payload field. Much of the code in this module deals with -the header field. This is where the synchronization information is -stored. In the case of a bounded protocol, the header also includes a -pointer to the buffer the packet is contained in. - -Packets represent a single message in a protocol. The payload field -gets instatiated at the type of the message, which is usually an enum -generated by the pipe compiler. Packets are conceptually single use, -although in bounded protocols they are reused each time around the -loop. - - -Packets are usually handled through a send_packet_buffered or -recv_packet_buffered object. Each packet is referenced by one -send_packet and one recv_packet, and these wrappers enforce that only -one end can send and only one end can receive. The structs also -include a destructor that marks packets are terminated if the sender -or receiver destroys the object before sending or receiving a value. - -The *_packet_buffered structs take two type parameters. The first is -the message type for the current packet (or state). The second -represents the type of the whole buffer. For bounded protocols, the -protocol compiler generates a struct with a field for each protocol -state. This generated struct is used as the buffer type parameter. For -unbounded protocols, the buffer is simply one packet, so there is a -shorthand struct called send_packet and recv_packet, where the buffer -type is just `packet<T>`. Using the same underlying structure for both -bounded and unbounded protocols allows for less code duplication. - -*/ - -#[allow(missing_doc)]; - -use container::Container; -use cast::{forget, transmute, transmute_copy, transmute_mut}; -use either::{Either, Left, Right}; -use iterator::{Iterator, IteratorUtil}; -use kinds::Send; -use libc; -use ops::Drop; -use option::{None, Option, Some}; -use unstable::finally::Finally; -use unstable::intrinsics; -use ptr; -use ptr::RawPtr; -use task; -use vec::{OwnedVector, MutableVector}; -use util::replace; - -static SPIN_COUNT: uint = 0; - -#[deriving(Eq)] -enum State { - Empty, - Full, - Blocked, - Terminated -} - -pub struct BufferHeader { - // Tracks whether this buffer needs to be freed. We can probably - // get away with restricting it to 0 or 1, if we're careful. - ref_count: int, - - // We may want a drop, and to be careful about stringing this - // thing along. -} - -pub fn BufferHeader() -> BufferHeader { - BufferHeader { - ref_count: 0 - } -} - -// This is for protocols to associate extra data to thread around. -pub struct Buffer<T> { - header: BufferHeader, - data: T, -} - -pub struct PacketHeader { - state: State, - blocked_task: *rust_task, - - // This is a transmute_copy of a ~buffer, that can also be cast - // to a buffer_header if need be. - buffer: *libc::c_void, -} - -pub fn PacketHeader() -> PacketHeader { - PacketHeader { - state: Empty, - blocked_task: ptr::null(), - buffer: ptr::null() - } -} - -impl PacketHeader { - // Returns the old state. - pub unsafe fn mark_blocked(&mut self, this: *rust_task) -> State { - rustrt::rust_task_ref(this); - let old_task = swap_task(&mut self.blocked_task, this); - assert!(old_task.is_null()); - swap_state_acq(&mut self.state, Blocked) - } - - pub unsafe fn unblock(&mut self) { - let old_task = swap_task(&mut self.blocked_task, ptr::null()); - if !old_task.is_null() { - rustrt::rust_task_deref(old_task) - } - match swap_state_acq(&mut self.state, Empty) { - Empty | Blocked => (), - Terminated => self.state = Terminated, - Full => self.state = Full - } - } - - // unsafe because this can do weird things to the space/time - // continuum. It ends making multiple unique pointers to the same - // thing. You'll probably want to forget them when you're done. - pub unsafe fn buf_header(&mut self) -> ~BufferHeader { - assert!(self.buffer.is_not_null()); - transmute_copy(&self.buffer) - } - - pub fn set_buffer<T:Send>(&mut self, b: ~Buffer<T>) { - unsafe { - self.buffer = transmute_copy(&b); - } - } -} - -pub struct Packet<T> { - header: PacketHeader, - payload: Option<T>, -} - -pub trait HasBuffer { - fn set_buffer(&mut self, b: *libc::c_void); -} - -impl<T:Send> HasBuffer for Packet<T> { - fn set_buffer(&mut self, b: *libc::c_void) { - self.header.buffer = b; - } -} - -pub fn mk_packet<T:Send>() -> Packet<T> { - Packet { - header: PacketHeader(), - payload: None, - } -} -fn unibuffer<T>() -> ~Buffer<Packet<T>> { - let mut b = ~Buffer { - header: BufferHeader(), - data: Packet { - header: PacketHeader(), - payload: None, - } - }; - - unsafe { - b.data.header.buffer = transmute_copy(&b); - } - b -} - -pub fn packet<T>() -> *mut Packet<T> { - let mut b = unibuffer(); - let p = ptr::to_mut_unsafe_ptr(&mut b.data); - // We'll take over memory management from here. - unsafe { - forget(b); - } - p -} - -pub fn entangle_buffer<T:Send,Tstart:Send>( - mut buffer: ~Buffer<T>, - init: &fn(*libc::c_void, x: &mut T) -> *mut Packet<Tstart>) - -> (RecvPacketBuffered<Tstart, T>, SendPacketBuffered<Tstart, T>) { - unsafe { - let p = init(transmute_copy(&buffer), &mut buffer.data); - forget(buffer); - (RecvPacketBuffered(p), SendPacketBuffered(p)) - } -} - -pub fn swap_task(dst: &mut *rust_task, src: *rust_task) -> *rust_task { - // It might be worth making both acquire and release versions of - // this. - unsafe { - transmute(intrinsics::atomic_xchg(transmute(dst), src as int)) - } -} - -#[allow(non_camel_case_types)] -pub type rust_task = libc::c_void; - -pub mod rustrt { - use libc; - use super::rust_task; - - extern { - #[rust_stack] - pub fn rust_get_task() -> *rust_task; - #[rust_stack] - pub fn rust_task_ref(task: *rust_task); - pub fn rust_task_deref(task: *rust_task); - - #[rust_stack] - pub fn task_clear_event_reject(task: *rust_task); - - pub fn task_wait_event(this: *rust_task, killed: &mut *libc::c_void) - -> bool; - pub fn task_signal_event(target: *rust_task, event: *libc::c_void); - } -} - -fn wait_event(this: *rust_task) -> *libc::c_void { - unsafe { - let mut event = ptr::null(); - - let killed = rustrt::task_wait_event(this, &mut event); - if killed && !task::failing() { - fail!("killed") - } - event - } -} - -fn swap_state_acq(dst: &mut State, src: State) -> State { - unsafe { - transmute(intrinsics::atomic_xchg_acq(transmute(dst), src as int)) - } -} - -fn swap_state_rel(dst: &mut State, src: State) -> State { - unsafe { - transmute(intrinsics::atomic_xchg_rel(transmute(dst), src as int)) - } -} - -pub unsafe fn get_buffer<T>(p: *mut PacketHeader) -> ~Buffer<T> { - transmute((*p).buf_header()) -} - -// This could probably be done with SharedMutableState to avoid move_it!(). -struct BufferResource<T> { - buffer: ~Buffer<T>, - -} - -#[unsafe_destructor] -impl<T> Drop for BufferResource<T> { - fn drop(&self) { - unsafe { - // FIXME(#4330) Need self by value to get mutability. - let this: &mut BufferResource<T> = transmute_mut(self); - - let null_buffer: ~Buffer<T> = transmute(ptr::null::<Buffer<T>>()); - let mut b = replace(&mut this.buffer, null_buffer); - - //let p = ptr::to_unsafe_ptr(*b); - //error!("drop %?", p); - let old_count = intrinsics::atomic_xsub_rel( - &mut b.header.ref_count, - 1); - //let old_count = atomic_xchng_rel(b.header.ref_count, 0); - if old_count == 1 { - // The new count is 0. - - // go go gadget drop glue - } - else { - forget(b) - } - } - } -} - -fn BufferResource<T>(mut b: ~Buffer<T>) -> BufferResource<T> { - //let p = ptr::to_unsafe_ptr(*b); - //error!("take %?", p); - unsafe { - intrinsics::atomic_xadd_acq(&mut b.header.ref_count, 1); - } - - BufferResource { - // tjc: ???? - buffer: b - } -} - -pub fn send<T,Tbuffer>(mut p: SendPacketBuffered<T,Tbuffer>, - payload: T) - -> bool { - let header = p.header(); - let p_ = p.unwrap(); - let p = unsafe { &mut *p_ }; - assert_eq!(ptr::to_unsafe_ptr(&(p.header)), header); - assert!(p.payload.is_none()); - p.payload = Some(payload); - let old_state = swap_state_rel(&mut p.header.state, Full); - match old_state { - Empty => { - // Yay, fastpath. - - // The receiver will eventually clean this up. - //unsafe { forget(p); } - return true; - } - Full => fail!("duplicate send"), - Blocked => { - debug!("waking up task for %?", p_); - let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); - if !old_task.is_null() { - unsafe { - rustrt::task_signal_event( - old_task, - ptr::to_unsafe_ptr(&(p.header)) as *libc::c_void); - rustrt::rust_task_deref(old_task); - } - } - - // The receiver will eventually clean this up. - //unsafe { forget(p); } - return true; - } - Terminated => { - // The receiver will never receive this. Rely on drop_glue - // to clean everything up. - return false; - } - } -} - -/** Receives a message from a pipe. - -Fails if the sender closes the connection. - -*/ -pub fn recv<T:Send,Tbuffer:Send>( - p: RecvPacketBuffered<T, Tbuffer>) -> T { - try_recv(p).expect("connection closed") -} - -/** Attempts to receive a message from a pipe. - -Returns `None` if the sender has closed the connection without sending -a message, or `Some(T)` if a message was received. - -*/ -pub fn try_recv<T:Send,Tbuffer:Send>(mut p: RecvPacketBuffered<T, Tbuffer>) - -> Option<T> { - let p_ = p.unwrap(); - let p = unsafe { &mut *p_ }; - - do (|| { - try_recv_(p) - }).finally { - unsafe { - if task::failing() { - p.header.state = Terminated; - let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); - if !old_task.is_null() { - rustrt::rust_task_deref(old_task); - } - } - } - } -} - -fn try_recv_<T:Send>(p: &mut Packet<T>) -> Option<T> { - // optimistic path - match p.header.state { - Full => { - let payload = p.payload.take(); - p.header.state = Empty; - return Some(payload.unwrap()) - }, - Terminated => return None, - _ => {} - } - - // regular path - let this = unsafe { rustrt::rust_get_task() }; - unsafe { - rustrt::task_clear_event_reject(this); - rustrt::rust_task_ref(this); - }; - debug!("blocked = %x this = %x", p.header.blocked_task as uint, - this as uint); - let old_task = swap_task(&mut p.header.blocked_task, this); - debug!("blocked = %x this = %x old_task = %x", - p.header.blocked_task as uint, - this as uint, old_task as uint); - assert!(old_task.is_null()); - let mut first = true; - let mut count = SPIN_COUNT; - loop { - unsafe { - rustrt::task_clear_event_reject(this); - } - - let old_state = swap_state_acq(&mut p.header.state, - Blocked); - match old_state { - Empty => { - debug!("no data available on %?, going to sleep.", p); - if count == 0 { - wait_event(this); - } - else { - count -= 1; - // FIXME (#524): Putting the yield here destroys a lot - // of the benefit of spinning, since we still go into - // the scheduler at every iteration. However, without - // this everything spins too much because we end up - // sometimes blocking the thing we are waiting on. - task::yield(); - } - debug!("woke up, p.state = %?", p.header.state); - } - Blocked => if first { - fail!("blocking on already blocked packet") - }, - Full => { - let payload = p.payload.take(); - let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); - if !old_task.is_null() { - unsafe { - rustrt::rust_task_deref(old_task); - } - } - p.header.state = Empty; - return Some(payload.unwrap()) - } - Terminated => { - // This assert detects when we've accidentally unsafely - // casted too big of a number to a state. - assert_eq!(old_state, Terminated); - - let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); - if !old_task.is_null() { - unsafe { - rustrt::rust_task_deref(old_task); - } - } - return None; - } - } - first = false; - } -} - -/// Returns true if messages are available. -pub fn peek<T:Send,Tb:Send>(p: &mut RecvPacketBuffered<T, Tb>) -> bool { - unsafe { - match (*p.header()).state { - Empty | Terminated => false, - Blocked => fail!("peeking on blocked packet"), - Full => true - } - } -} - -fn sender_terminate<T:Send>(p: *mut Packet<T>) { - let p = unsafe { - &mut *p - }; - match swap_state_rel(&mut p.header.state, Terminated) { - Empty => { - // The receiver will eventually clean up. - } - Blocked => { - // wake up the target - let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); - if !old_task.is_null() { - unsafe { - rustrt::task_signal_event( - old_task, - ptr::to_unsafe_ptr(&(p.header)) as *libc::c_void); - rustrt::rust_task_deref(old_task); - } - } - // The receiver will eventually clean up. - } - Full => { - // This is impossible - fail!("you dun goofed") - } - Terminated => { - assert!(p.header.blocked_task.is_null()); - // I have to clean up, use drop_glue - } - } -} - -fn receiver_terminate<T:Send>(p: *mut Packet<T>) { - let p = unsafe { - &mut *p - }; - match swap_state_rel(&mut p.header.state, Terminated) { - Empty => { - assert!(p.header.blocked_task.is_null()); - // the sender will clean up - } - Blocked => { - let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); - if !old_task.is_null() { - unsafe { - rustrt::rust_task_deref(old_task); - assert_eq!(old_task, rustrt::rust_get_task()); - } - } - } - Terminated | Full => { - assert!(p.header.blocked_task.is_null()); - // I have to clean up, use drop_glue - } - } -} - -/** Returns when one of the packet headers reports data is available. - -This function is primarily intended for building higher level waiting -functions, such as `select`, `select2`, etc. - -It takes a vector slice of packet_headers and returns an index into -that vector. The index points to an endpoint that has either been -closed by the sender or has a message waiting to be received. - -*/ -pub fn wait_many<T: Selectable>(pkts: &mut [T]) -> uint { - let this = unsafe { - rustrt::rust_get_task() - }; - - unsafe { - rustrt::task_clear_event_reject(this); - } - - let mut data_avail = false; - let mut ready_packet = pkts.len(); - for (i, p) in pkts.mut_iter().enumerate() { - unsafe { - let p = &mut *p.header(); - let old = p.mark_blocked(this); - match old { - Full | Terminated => { - data_avail = true; - ready_packet = i; - (*p).state = old; - break; - } - Blocked => fail!("blocking on blocked packet"), - Empty => () - } - } - } - - while !data_avail { - debug!("sleeping on %? packets", pkts.len()); - let event = wait_event(this) as *PacketHeader; - - let mut pos = None; - for (i, p) in pkts.mut_iter().enumerate() { - if p.header() == event { - pos = Some(i); - break; - } - }; - - match pos { - Some(i) => { - ready_packet = i; - data_avail = true; - } - None => debug!("ignoring spurious event, %?", event) - } - } - - debug!("%?", &mut pkts[ready_packet]); - - for p in pkts.mut_iter() { - unsafe { - (*p.header()).unblock() - } - } - - debug!("%?, %?", ready_packet, &mut pkts[ready_packet]); - - unsafe { - assert!((*pkts[ready_packet].header()).state == Full - || (*pkts[ready_packet].header()).state == Terminated); - } - - ready_packet -} - -/** The sending end of a pipe. It can be used to send exactly one -message. - -*/ -pub type SendPacket<T> = SendPacketBuffered<T, Packet<T>>; - -pub fn SendPacket<T>(p: *mut Packet<T>) -> SendPacket<T> { - SendPacketBuffered(p) -} - -pub struct SendPacketBuffered<T, Tbuffer> { - p: Option<*mut Packet<T>>, - buffer: Option<BufferResource<Tbuffer>>, -} - -#[unsafe_destructor] -impl<T:Send,Tbuffer:Send> Drop for SendPacketBuffered<T,Tbuffer> { - fn drop(&self) { - unsafe { - let this: &mut SendPacketBuffered<T,Tbuffer> = transmute(self); - if this.p != None { - sender_terminate(this.p.take_unwrap()); - } - } - } -} - -pub fn SendPacketBuffered<T,Tbuffer>(p: *mut Packet<T>) - -> SendPacketBuffered<T,Tbuffer> { - SendPacketBuffered { - p: Some(p), - buffer: unsafe { - Some(BufferResource(get_buffer(&mut (*p).header))) - } - } -} - -impl<T,Tbuffer> SendPacketBuffered<T,Tbuffer> { - pub fn unwrap(&mut self) -> *mut Packet<T> { - self.p.take_unwrap() - } - - pub fn header(&mut self) -> *mut PacketHeader { - match self.p { - Some(packet) => unsafe { - let packet = &mut *packet; - let header = ptr::to_mut_unsafe_ptr(&mut packet.header); - header - }, - None => fail!("packet already consumed") - } - } - - pub fn reuse_buffer(&mut self) -> BufferResource<Tbuffer> { - //error!("send reuse_buffer"); - self.buffer.take_unwrap() - } -} - -/// Represents the receive end of a pipe. It can receive exactly one -/// message. -pub type RecvPacket<T> = RecvPacketBuffered<T, Packet<T>>; - -pub fn RecvPacket<T>(p: *mut Packet<T>) -> RecvPacket<T> { - RecvPacketBuffered(p) -} - -pub struct RecvPacketBuffered<T, Tbuffer> { - p: Option<*mut Packet<T>>, - buffer: Option<BufferResource<Tbuffer>>, -} - -#[unsafe_destructor] -impl<T:Send,Tbuffer:Send> Drop for RecvPacketBuffered<T,Tbuffer> { - fn drop(&self) { - unsafe { - let this: &mut RecvPacketBuffered<T,Tbuffer> = transmute(self); - if this.p != None { - receiver_terminate(this.p.take_unwrap()) - } - } - } -} - -impl<T:Send,Tbuffer:Send> RecvPacketBuffered<T, Tbuffer> { - pub fn unwrap(&mut self) -> *mut Packet<T> { - self.p.take_unwrap() - } - - pub fn reuse_buffer(&mut self) -> BufferResource<Tbuffer> { - self.buffer.take_unwrap() - } -} - -impl<T:Send,Tbuffer:Send> Selectable for RecvPacketBuffered<T, Tbuffer> { - fn header(&mut self) -> *mut PacketHeader { - match self.p { - Some(packet) => unsafe { - let packet = &mut *packet; - let header = ptr::to_mut_unsafe_ptr(&mut packet.header); - header - }, - None => fail!("packet already consumed") - } - } -} - -pub fn RecvPacketBuffered<T,Tbuffer>(p: *mut Packet<T>) - -> RecvPacketBuffered<T,Tbuffer> { - RecvPacketBuffered { - p: Some(p), - buffer: unsafe { - Some(BufferResource(get_buffer(&mut (*p).header))) - } - } -} - -pub fn entangle<T>() -> (RecvPacket<T>, SendPacket<T>) { - let p = packet(); - (RecvPacket(p), SendPacket(p)) -} - -/** Receives a message from one of two endpoints. - -The return value is `left` if the first endpoint received something, -or `right` if the second endpoint receives something. In each case, -the result includes the other endpoint as well so it can be used -again. Below is an example of using `select2`. - -~~~ {.rust} -match select2(a, b) { - left((none, b)) { - // endpoint a was closed. - } - right((a, none)) { - // endpoint b was closed. - } - left((Some(_), b)) { - // endpoint a received a message - } - right(a, Some(_)) { - // endpoint b received a message. - } -} -~~~ - -Sometimes messages will be available on both endpoints at once. In -this case, `select2` may return either `left` or `right`. - -*/ -pub fn select2<A:Send,Ab:Send,B:Send,Bb:Send>( - mut a: RecvPacketBuffered<A, Ab>, - mut b: RecvPacketBuffered<B, Bb>) - -> Either<(Option<A>, RecvPacketBuffered<B, Bb>), - (RecvPacketBuffered<A, Ab>, Option<B>)> { - let mut endpoints = [ a.header(), b.header() ]; - let i = wait_many(endpoints); - match i { - 0 => Left((try_recv(a), b)), - 1 => Right((a, try_recv(b))), - _ => fail!("select2 return an invalid packet") - } -} - -pub trait Selectable { - fn header(&mut self) -> *mut PacketHeader; -} - -impl Selectable for *mut PacketHeader { - fn header(&mut self) -> *mut PacketHeader { *self } -} - -/// Returns the index of an endpoint that is ready to receive. -pub fn selecti<T:Selectable>(endpoints: &mut [T]) -> uint { - wait_many(endpoints) -} - -/// Returns 0 or 1 depending on which endpoint is ready to receive -pub fn select2i<A:Selectable,B:Selectable>(a: &mut A, b: &mut B) - -> Either<(), ()> { - let mut endpoints = [ a.header(), b.header() ]; - match wait_many(endpoints) { - 0 => Left(()), - 1 => Right(()), - _ => fail!("wait returned unexpected index") - } -} - -/// Waits on a set of endpoints. Returns a message, its index, and a -/// list of the remaining endpoints. -pub fn select<T:Send,Tb:Send>(mut endpoints: ~[RecvPacketBuffered<T, Tb>]) - -> (uint, - Option<T>, - ~[RecvPacketBuffered<T, Tb>]) { - let mut endpoint_headers = ~[]; - for endpoint in endpoints.mut_iter() { - endpoint_headers.push(endpoint.header()); - } - - let ready = wait_many(endpoint_headers); - let mut remaining = endpoints; - let port = remaining.swap_remove(ready); - let result = try_recv(port); - (ready, result, remaining) -} - -pub mod rt { - use option::{None, Option, Some}; - - // These are used to hide the option constructors from the - // compiler because their names are changing - pub fn make_some<T>(val: T) -> Option<T> { Some(val) } - pub fn make_none<T>() -> Option<T> { None } -} diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 65db55297b3..9a8737f4dee 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -43,6 +43,7 @@ pub use io::{print, println}; pub use iterator::range; // Reexported types and traits +pub use c_str::ToCStr; pub use clone::{Clone, DeepClone}; pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv}; pub use char::Char; @@ -50,7 +51,7 @@ pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet}; pub use hash::Hash; pub use iter::Times; pub use iterator::Extendable; -pub use iterator::{Iterator, IteratorUtil, DoubleEndedIterator, DoubleEndedIteratorUtil}; +pub use iterator::{Iterator, DoubleEndedIterator}; pub use iterator::{ClonableIterator, OrdIterator}; pub use num::{Num, NumCast}; pub use num::{Orderable, Signed, Unsigned, Round}; @@ -64,7 +65,7 @@ pub use path::PosixPath; pub use path::WindowsPath; pub use ptr::RawPtr; pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr, ToBytesConsume}; -pub use str::{Str, StrVector, StrSlice, OwnedStr, NullTerminatedStr}; +pub use str::{Str, StrVector, StrSlice, OwnedStr}; pub use from_str::FromStr; pub use to_bytes::IterBytes; pub use to_str::{ToStr, ToStrConsume}; diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index 5a2bd0c4de9..26653a51d66 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -456,6 +456,7 @@ pub mod ptr_tests { use super::*; use prelude::*; + use c_str::ToCStr; use cast; use libc; use str; @@ -502,22 +503,20 @@ pub mod ptr_tests { fn test_position() { use libc::c_char; - let s = ~"hello"; - unsafe { - assert!(2u == s.as_c_str(|p| position(p, |c| *c == 'l' as c_char))); - assert!(4u == s.as_c_str(|p| position(p, |c| *c == 'o' as c_char))); - assert!(5u == s.as_c_str(|p| position(p, |c| *c == 0 as c_char))); + do "hello".to_c_str().with_ref |p| { + unsafe { + assert!(2u == position(p, |c| *c == 'l' as c_char)); + assert!(4u == position(p, |c| *c == 'o' as c_char)); + assert!(5u == position(p, |c| *c == 0 as c_char)); + } } } #[test] fn test_buf_len() { - let s0 = ~"hello"; - let s1 = ~"there"; - let s2 = ~"thing"; - do s0.as_c_str |p0| { - do s1.as_c_str |p1| { - do s2.as_c_str |p2| { + do "hello".to_c_str().with_ref |p0| { + do "there".to_c_str().with_ref |p1| { + do "thing".to_c_str().with_ref |p2| { let v = ~[p0, p1, p2, null()]; do v.as_imm_buf |vp, len| { assert_eq!(unsafe { buf_len(vp) }, 3u); @@ -621,66 +620,75 @@ pub mod ptr_tests { #[test] fn test_ptr_array_each_with_len() { unsafe { - let one = ~"oneOne"; - let two = ~"twoTwo"; - let three = ~"threeThree"; - let arr: ~[*i8] = ~[ - ::cast::transmute(&one[0]), - ::cast::transmute(&two[0]), - ::cast::transmute(&three[0]), + let one = "oneOne".to_c_str(); + let two = "twoTwo".to_c_str(); + let three = "threeThree".to_c_str(); + let arr = ~[ + one.with_ref(|buf| buf), + two.with_ref(|buf| buf), + three.with_ref(|buf| buf), ]; let expected_arr = [ one, two, three ]; - let arr_ptr = &arr[0]; - let mut ctr = 0; - let mut iteration_count = 0; - array_each_with_len(arr_ptr, arr.len(), - |e| { - let actual = str::raw::from_c_str(e); - let expected = expected_arr[ctr].clone(); - debug!( - "test_ptr_array_each e: %s, a: %s", - expected, actual); - assert_eq!(actual, expected); - ctr += 1; - iteration_count += 1; - }); - assert_eq!(iteration_count, 3u); + + do arr.as_imm_buf |arr_ptr, arr_len| { + let mut ctr = 0; + let mut iteration_count = 0; + do array_each_with_len(arr_ptr, arr_len) |e| { + let actual = str::raw::from_c_str(e); + let expected = do expected_arr[ctr].with_ref |buf| { + str::raw::from_c_str(buf) + }; + debug!( + "test_ptr_array_each_with_len e: %s, a: %s", + expected, actual); + assert_eq!(actual, expected); + ctr += 1; + iteration_count += 1; + } + assert_eq!(iteration_count, 3u); + } } } + #[test] fn test_ptr_array_each() { unsafe { - let one = ~"oneOne"; - let two = ~"twoTwo"; - let three = ~"threeThree"; - let arr: ~[*i8] = ~[ - ::cast::transmute(&one[0]), - ::cast::transmute(&two[0]), - ::cast::transmute(&three[0]), + let one = "oneOne".to_c_str(); + let two = "twoTwo".to_c_str(); + let three = "threeThree".to_c_str(); + let arr = ~[ + one.with_ref(|buf| buf), + two.with_ref(|buf| buf), + three.with_ref(|buf| buf), // fake a null terminator - 0 as *i8 + null(), ]; let expected_arr = [ one, two, three ]; - let arr_ptr = &arr[0]; - let mut ctr = 0; - let mut iteration_count = 0; - array_each(arr_ptr, |e| { - let actual = str::raw::from_c_str(e); - let expected = expected_arr[ctr].clone(); - debug!( - "test_ptr_array_each e: %s, a: %s", - expected, actual); - assert_eq!(actual, expected); - ctr += 1; - iteration_count += 1; - }); - assert_eq!(iteration_count, 3); + + do arr.as_imm_buf |arr_ptr, arr_len| { + let mut ctr = 0; + let mut iteration_count = 0; + do array_each(arr_ptr) |e| { + let actual = str::raw::from_c_str(e); + let expected = do expected_arr[ctr].with_ref |buf| { + str::raw::from_c_str(buf) + }; + debug!( + "test_ptr_array_each e: %s, a: %s", + expected, actual); + assert_eq!(actual, expected); + ctr += 1; + iteration_count += 1; + } + assert_eq!(iteration_count, 3); + } } } + #[test] #[should_fail] #[ignore(cfg(windows))] diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs index 4ef524d7715..5f8fa9fddbc 100644 --- a/src/libstd/rand.rs +++ b/src/libstd/rand.rs @@ -610,15 +610,32 @@ impl<R: Rng> RngUtil for R { } /// Create a random number generator with a default algorithm and seed. +/// +/// It returns the cryptographically-safest `Rng` algorithm currently +/// available in Rust. If you require a specifically seeded `Rng` for +/// consistency over time you should pick one algorithm and create the +/// `Rng` yourself. pub fn rng() -> IsaacRng { IsaacRng::new() } +/// Create a weak random number generator with a default algorithm and seed. +/// +/// It returns the fatest `Rng` algorithm currently available in Rust without +/// consideration for cryptography or security. If you require a specifically +/// seeded `Rng` for consistency over time you should pick one algorithm and +/// create the `Rng` yourself. +pub fn weak_rng() -> XorShiftRng { + XorShiftRng::new() +} + static RAND_SIZE_LEN: u32 = 8; static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN; /// A random number generator that uses the [ISAAC /// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29). +/// +/// The ISAAC algorithm is suitable for cryptographic purposes. pub struct IsaacRng { priv cnt: u32, priv rsl: [u32, .. RAND_SIZE], @@ -794,8 +811,11 @@ impl Rng for IsaacRng { } /// An [Xorshift random number -/// generator](http://en.wikipedia.org/wiki/Xorshift). Not suitable for -/// cryptographic purposes. +/// generator](http://en.wikipedia.org/wiki/Xorshift). +/// +/// The Xorshift algorithm is not suitable for cryptographic purposes +/// but is very fast. If you do not know for sure that it fits your +/// requirements, use a more secure one such as `IsaacRng`. pub struct XorShiftRng { priv x: u32, priv y: u32, diff --git a/src/libstd/result.rs b/src/libstd/result.rs index 3e429c6116d..9de5e69148a 100644 --- a/src/libstd/result.rs +++ b/src/libstd/result.rs @@ -94,7 +94,7 @@ impl<T, E: ToStr> Result<T, E> { match *self { Ok(ref t) => Some(t), Err(*) => None, - }.consume() + }.move_iter() } /// Call a method based on a previous result @@ -108,7 +108,7 @@ impl<T, E: ToStr> Result<T, E> { match *self { Ok(*) => None, Err(ref t) => Some(t), - }.consume() + }.move_iter() } /// Unwraps a result, yielding the content of an `Ok`. diff --git a/src/libstd/rt/borrowck.rs b/src/libstd/rt/borrowck.rs index dcfcc3a9fc6..f620a7347a4 100644 --- a/src/libstd/rt/borrowck.rs +++ b/src/libstd/rt/borrowck.rs @@ -8,8 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use c_str::ToCStr; use cast::transmute; -use libc::{c_char, c_void, size_t, STDERR_FILENO}; +use libc::{c_char, size_t, STDERR_FILENO}; use io; use io::{Writer, WriterUtil}; use option::{Option, None, Some}; @@ -20,9 +21,6 @@ use sys; use unstable::raw; use vec::ImmutableVector; -#[allow(non_camel_case_types)] -type rust_task = c_void; - pub static FROZEN_BIT: uint = 1 << (uint::bits - 1); pub static MUT_BIT: uint = 1 << (uint::bits - 2); static ALL_BITS: uint = FROZEN_BIT | MUT_BIT; @@ -35,34 +33,12 @@ struct BorrowRecord { } fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> { - unsafe { - let cur_task: *rust_task = rust_try_get_task(); - if cur_task.is_not_null() { - let ptr = rust_take_task_borrow_list(cur_task); - if ptr.is_null() { - None - } else { - let v: ~[BorrowRecord] = transmute(ptr); - Some(v) - } - } else { - None - } - } + // XXX + None } -fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) { - unsafe { - let cur_task: *rust_task = rust_try_get_task(); - if cur_task.is_not_null() { - let mut borrow_list: ~[BorrowRecord] = { - let ptr = rust_take_task_borrow_list(cur_task); - if ptr.is_null() { ~[] } else { transmute(ptr) } - }; - borrow_list = f(borrow_list); - rust_set_task_borrow_list(cur_task, transmute(borrow_list)); - } - } +fn swap_task_borrow_list(_f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) { + // XXX } pub unsafe fn clear_task_borrow_list() { @@ -76,8 +52,8 @@ unsafe fn fail_borrowed(box: *mut raw::Box<()>, file: *c_char, line: size_t) { match try_take_task_borrow_list() { None => { // not recording borrows let msg = "borrowed"; - do msg.as_c_str |msg_p| { - sys::begin_unwind_(msg_p as *c_char, file, line); + do msg.to_c_str().with_ref |msg_p| { + sys::begin_unwind_(msg_p, file, line); } } Some(borrow_list) => { // recording borrows @@ -92,8 +68,8 @@ unsafe fn fail_borrowed(box: *mut raw::Box<()>, file: *c_char, line: size_t) { sep = " and at "; } } - do msg.as_c_str |msg_p| { - sys::begin_unwind_(msg_p as *c_char, file, line) + do msg.to_c_str().with_ref |msg_p| { + sys::begin_unwind_(msg_p, file, line) } } } @@ -113,7 +89,8 @@ unsafe fn debug_borrow<T>(tag: &'static str, //! A useful debugging function that prints a pointer + tag + newline //! without allocating memory. - if ENABLE_DEBUG && ::rt::env::get().debug_borrow { + // XXX + if false { debug_borrow_slow(tag, p, old_bits, new_bits, filename, line); } @@ -231,8 +208,8 @@ pub unsafe fn unrecord_borrow(a: *u8, old_ref_count: uint, let br = borrow_list.pop(); if br.box != a || br.file != file || br.line != line { let err = fmt!("wrong borrow found, br=%?", br); - do err.as_c_str |msg_p| { - sys::begin_unwind_(msg_p as *c_char, file, line) + do err.to_c_str().with_ref |msg_p| { + sys::begin_unwind_(msg_p, file, line) } } borrow_list @@ -269,15 +246,3 @@ pub unsafe fn check_not_borrowed(a: *u8, fail_borrowed(a, file, line); } } - - -extern { - #[rust_stack] - pub fn rust_take_task_borrow_list(task: *rust_task) -> *c_void; - - #[rust_stack] - pub fn rust_set_task_borrow_list(task: *rust_task, map: *c_void); - - #[rust_stack] - pub fn rust_try_get_task() -> *rust_task; -} diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs index 0cf223f3029..793e244bec7 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -15,6 +15,7 @@ use cast; use ops::Drop; use rt::kill::BlockedTask; use kinds::Send; +use rt; use rt::sched::Scheduler; use rt::local::Local; use rt::select::{Select, SelectPort}; @@ -24,7 +25,6 @@ use util::Void; use comm::{GenericChan, GenericSmartChan, GenericPort, Peekable}; use cell::Cell; use clone::Clone; -use rt::{context, SchedulerContext}; use tuple::ImmutableTuple; /// A combined refcount / BlockedTask-as-uint pointer. @@ -113,7 +113,7 @@ impl<T> ChanOne<T> { // 'do_resched' configures whether the scheduler immediately switches to // the receiving task, or leaves the sending task still running. fn try_send_inner(self, val: T, do_resched: bool) -> bool { - rtassert!(context() != SchedulerContext); + rtassert!(!rt::in_sched_context()); let mut this = self; let mut recvr_active = true; @@ -225,9 +225,10 @@ impl<T> Select for PortOne<T> { fn optimistic_check(&mut self) -> bool { // The optimistic check is never necessary for correctness. For testing // purposes, making it randomly return false simulates a racing sender. - use rand::{Rand, rng}; - let mut rng = rng(); - let actually_check = Rand::rand(&mut rng); + use rand::{Rand}; + let actually_check = do Local::borrow::<Scheduler, bool> |sched| { + Rand::rand(&mut sched.rng) + }; if actually_check { unsafe { (*self.packet()).state.load(Acquire) == STATE_ONE } } else { @@ -508,7 +509,11 @@ impl<T> Peekable<T> for Port<T> { } } -impl<T> Select for Port<T> { +// XXX: Kind of gross. A Port<T> should be selectable so you can make an array +// of them, but a &Port<T> should also be selectable so you can select2 on it +// alongside a PortOne<U> without passing the port by value in recv_ready. + +impl<'self, T> Select for &'self Port<T> { #[inline] fn optimistic_check(&mut self) -> bool { do self.next.with_mut_ref |pone| { pone.optimistic_check() } @@ -526,12 +531,29 @@ impl<T> Select for Port<T> { } } -impl<T> SelectPort<(T, Port<T>)> for Port<T> { - fn recv_ready(self) -> Option<(T, Port<T>)> { +impl<T> Select for Port<T> { + #[inline] + fn optimistic_check(&mut self) -> bool { + (&*self).optimistic_check() + } + + #[inline] + fn block_on(&mut self, sched: &mut Scheduler, task: BlockedTask) -> bool { + (&*self).block_on(sched, task) + } + + #[inline] + fn unblock_from(&mut self) -> bool { + (&*self).unblock_from() + } +} + +impl<'self, T> SelectPort<T> for &'self Port<T> { + fn recv_ready(self) -> Option<T> { match self.next.take().recv_ready() { Some(StreamPayload { val, next }) => { self.next.put_back(next); - Some((val, self)) + Some(val) } None => None } diff --git a/src/libstd/rt/env.rs b/src/libstd/rt/env.rs index 6e671742fb6..3ca39acbfcd 100644 --- a/src/libstd/rt/env.rs +++ b/src/libstd/rt/env.rs @@ -11,50 +11,9 @@ //! Runtime environment settings use from_str::FromStr; -use libc::{size_t, c_char, c_int}; use option::{Some, None}; use os; -// OLD RT stuff - -pub struct Environment { - /// The number of threads to use by default - num_sched_threads: size_t, - /// The minimum size of a stack segment - min_stack_size: size_t, - /// The maximum amount of total stack per task before aborting - max_stack_size: size_t, - /// The default logging configuration - logspec: *c_char, - /// Record and report detailed information about memory leaks - detailed_leaks: bool, - /// Seed the random number generator - rust_seed: *c_char, - /// Poison allocations on free - poison_on_free: bool, - /// The argc value passed to main - argc: c_int, - /// The argv value passed to main - argv: **c_char, - /// Print GC debugging info (true if env var RUST_DEBUG_MEM is set) - debug_mem: bool, - /// Print GC debugging info (true if env var RUST_DEBUG_BORROW is set) - debug_borrow: bool, -} - -/// Get the global environment settings -/// # Safety Note -/// This will abort the process if run outside of task context -pub fn get() -> &Environment { - unsafe { rust_get_rt_env() } -} - -extern { - fn rust_get_rt_env() -> &Environment; -} - -// NEW RT stuff - // Note that these are all accessed without any synchronization. // They are expected to be initialized once then left alone. diff --git a/src/libstd/rt/io/comm_adapters.rs b/src/libstd/rt/io/comm_adapters.rs index 7e891f1718e..6a3e44b2a4d 100644 --- a/src/libstd/rt/io/comm_adapters.rs +++ b/src/libstd/rt/io/comm_adapters.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::*; +use option::Option; +use comm::{GenericPort, GenericChan}; use super::{Reader, Writer}; struct PortReader<P>; diff --git a/src/libstd/rt/io/net/ip.rs b/src/libstd/rt/io/net/ip.rs index 815ec9b5c61..77176088801 100644 --- a/src/libstd/rt/io/net/ip.rs +++ b/src/libstd/rt/io/net/ip.rs @@ -9,7 +9,11 @@ // except according to those terms. use num::FromStrRadix; +use vec::MutableCloneableVector; use to_str::ToStr; +use from_str::FromStr; +use option::{Option, None, Some}; + type Port = u16; @@ -39,7 +43,7 @@ impl ToStr for IpAddr { } // Ipv4-Mapped address - Ipv6Addr(0, 0, 0, 0, 0, 1, g, h) => { + Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, g, h) => { let a = fmt!("%04x", g as uint); let b = FromStrRadix::from_str_radix(a.slice(2, 4), 16).unwrap(); let a = FromStrRadix::from_str_radix(a.slice(0, 2), 16).unwrap(); @@ -73,3 +77,371 @@ impl ToStr for SocketAddr { } } } + +struct Parser<'self> { + // parsing as ASCII, so can use byte array + s: &'self [u8], + pos: uint, +} + +impl<'self> Parser<'self> { + fn new(s: &'self str) -> Parser<'self> { + Parser { + s: s.as_bytes(), + pos: 0, + } + } + + fn is_eof(&self) -> bool { + self.pos == self.s.len() + } + + // Commit only if parser returns Some + fn read_atomically<T>(&mut self, cb: &fn(&mut Parser) -> Option<T>) -> Option<T> { + let pos = self.pos; + let r = cb(self); + if r.is_none() { + self.pos = pos; + } + r + } + + // Commit only if parser read till EOF + fn read_till_eof<T>(&mut self, cb: &fn(&mut Parser) -> Option<T>) -> Option<T> { + do self.read_atomically |p| { + cb(p).filtered(|_| p.is_eof()) + } + } + + // Return result of first successful parser + fn read_or<T>(&mut self, parsers: &[&fn(&mut Parser) -> Option<T>]) -> Option<T> { + for pf in parsers.iter() { + match self.read_atomically(|p: &mut Parser| (*pf)(p)) { + Some(r) => return Some(r), + None => {} + } + } + None + } + + // Apply 3 parsers sequentially + fn read_seq_3<A, B, C>(&mut self, + pa: &fn(&mut Parser) -> Option<A>, + pb: &fn(&mut Parser) -> Option<B>, + pc: &fn(&mut Parser) -> Option<C> + ) -> Option<(A, B, C)> + { + do self.read_atomically |p| { + let a = pa(p); + let b = if a.is_some() { pb(p) } else { None }; + let c = if b.is_some() { pc(p) } else { None }; + match (a, b, c) { + (Some(a), Some(b), Some(c)) => Some((a, b, c)), + _ => None + } + } + } + + // Read next char + fn read_char(&mut self) -> Option<char> { + if self.is_eof() { + None + } else { + let r = self.s[self.pos] as char; + self.pos += 1; + Some(r) + } + } + + // Return char and advance iff next char is equal to requested + fn read_given_char(&mut self, c: char) -> Option<char> { + do self.read_atomically |p| { + p.read_char().filtered(|&next| next == c) + } + } + + // Read digit + fn read_digit(&mut self, radix: u8) -> Option<u8> { + fn parse_digit(c: char, radix: u8) -> Option<u8> { + // assuming radix is either 10 or 16 + if c >= '0' && c <= '9' { + Some((c - '0') as u8) + } else if radix > 10 && c >= 'a' && c < 'a' + (radix - 10) as char { + Some((c - 'a' + (10 as char)) as u8) + } else if radix > 10 && c >= 'A' && c < 'A' + (radix - 10) as char { + Some((c - 'A' + (10 as char)) as u8) + } else { + None + } + } + + do self.read_atomically |p| { + p.read_char().chain(|c| parse_digit(c, radix)) + } + } + + fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> { + let mut r = 0u32; + let mut digit_count = 0; + loop { + match self.read_digit(radix) { + Some(d) => { + r = r * (radix as u32) + (d as u32); + digit_count += 1; + if digit_count > max_digits || r >= upto { + return None + } + } + None => { + if digit_count == 0 { + return None + } else { + return Some(r) + } + } + }; + } + } + + // Read number, failing if max_digits of number value exceeded + fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> { + do self.read_atomically |p| { + p.read_number_impl(radix, max_digits, upto) + } + } + + fn read_ipv4_addr_impl(&mut self) -> Option<IpAddr> { + let mut bs = [0u8, ..4]; + let mut i = 0; + while i < 4 { + if i != 0 && self.read_given_char('.').is_none() { + return None; + } + + let octet = self.read_number(10, 3, 0x100).map(|&n| n as u8); + match octet { + Some(d) => bs[i] = d, + None => return None, + }; + i += 1; + } + Some(Ipv4Addr(bs[0], bs[1], bs[2], bs[3])) + } + + // Read IPv4 address + fn read_ipv4_addr(&mut self) -> Option<IpAddr> { + do self.read_atomically |p| { + p.read_ipv4_addr_impl() + } + } + + fn read_ipv6_addr_impl(&mut self) -> Option<IpAddr> { + fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> IpAddr { + assert!(head.len() + tail.len() <= 8); + let mut gs = [0u16, ..8]; + gs.copy_from(head); + gs.mut_slice(8 - tail.len(), 8).copy_from(tail); + Ipv6Addr(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7]) + } + + fn read_groups(p: &mut Parser, groups: &mut [u16, ..8], limit: uint) -> (uint, bool) { + let mut i = 0; + while i < limit { + if i < limit - 1 { + let ipv4 = do p.read_atomically |p| { + if i == 0 || p.read_given_char(':').is_some() { + p.read_ipv4_addr() + } else { + None + } + }; + match ipv4 { + Some(Ipv4Addr(a, b, c, d)) => { + groups[i + 0] = (a as u16 << 8) | (b as u16); + groups[i + 1] = (c as u16 << 8) | (d as u16); + return (i + 2, true); + } + _ => {} + } + } + + let group = do p.read_atomically |p| { + if i == 0 || p.read_given_char(':').is_some() { + p.read_number(16, 4, 0x10000).map(|&n| n as u16) + } else { + None + } + }; + match group { + Some(g) => groups[i] = g, + None => return (i, false) + } + i += 1; + } + (i, false) + } + + let mut head = [0u16, ..8]; + let (head_size, head_ipv4) = read_groups(self, &mut head, 8); + + if head_size == 8 { + return Some(Ipv6Addr( + head[0], head[1], head[2], head[3], + head[4], head[5], head[6], head[7])) + } + + // IPv4 part is not allowed before `::` + if head_ipv4 { + return None + } + + // read `::` if previous code parsed less than 8 groups + if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() { + return None; + } + + let mut tail = [0u16, ..8]; + let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size); + Some(ipv6_addr_from_head_tail(head.slice(0, head_size), tail.slice(0, tail_size))) + } + + fn read_ipv6_addr(&mut self) -> Option<IpAddr> { + do self.read_atomically |p| { + p.read_ipv6_addr_impl() + } + } + + fn read_ip_addr(&mut self) -> Option<IpAddr> { + let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr(); + let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr(); + self.read_or([ipv4_addr, ipv6_addr]) + } + + fn read_socket_addr(&mut self) -> Option<SocketAddr> { + let ip_addr = |p: &mut Parser| { + let ipv4_p = |p: &mut Parser| p.read_ip_addr(); + let ipv6_p = |p: &mut Parser| { + let open_br = |p: &mut Parser| p.read_given_char('['); + let ip_addr = |p: &mut Parser| p.read_ipv6_addr(); + let clos_br = |p: &mut Parser| p.read_given_char(']'); + p.read_seq_3::<char, IpAddr, char>(open_br, ip_addr, clos_br) + .map(|&t| match t { (_, ip, _) => ip }) + }; + p.read_or([ipv4_p, ipv6_p]) + }; + let colon = |p: &mut Parser| p.read_given_char(':'); + let port = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|&n| n as u16); + + // host, colon, port + self.read_seq_3::<IpAddr, char, u16>(ip_addr, colon, port) + .map(|&t| match t { (ip, _, port) => SocketAddr { ip: ip, port: port } }) + } +} + +impl FromStr for IpAddr { + fn from_str(s: &str) -> Option<IpAddr> { + do Parser::new(s).read_till_eof |p| { + p.read_ip_addr() + } + } +} + +impl FromStr for SocketAddr { + fn from_str(s: &str) -> Option<SocketAddr> { + do Parser::new(s).read_till_eof |p| { + p.read_socket_addr() + } + } +} + + +#[cfg(test)] +mod test { + use super::*; + use from_str::FromStr; + use option::{Some, None}; + + #[test] + fn test_from_str_ipv4() { + assert_eq!(Some(Ipv4Addr(127, 0, 0, 1)), FromStr::from_str("127.0.0.1")); + assert_eq!(Some(Ipv4Addr(255, 255, 255, 255)), FromStr::from_str("255.255.255.255")); + assert_eq!(Some(Ipv4Addr(0, 0, 0, 0)), FromStr::from_str("0.0.0.0")); + + // out of range + assert_eq!(None, FromStr::from_str::<IpAddr>("256.0.0.1")); + // too short + assert_eq!(None, FromStr::from_str::<IpAddr>("255.0.0")); + // too long + assert_eq!(None, FromStr::from_str::<IpAddr>("255.0.0.1.2")); + // no number between dots + assert_eq!(None, FromStr::from_str::<IpAddr>("255.0..1")); + } + + #[test] + fn test_from_str_ipv6() { + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), FromStr::from_str("0:0:0:0:0:0:0:0")); + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), FromStr::from_str("0:0:0:0:0:0:0:1")); + + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), FromStr::from_str("::1")); + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), FromStr::from_str("::")); + + assert_eq!(Some(Ipv6Addr(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), + FromStr::from_str("2a02:6b8::11:11")); + + // too long group + assert_eq!(None, FromStr::from_str::<IpAddr>("::00000")); + // too short + assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:3:4:5:6:7")); + // too long + assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:3:4:5:6:7:8:9")); + // triple colon + assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:::6:7:8")); + // two double colons + assert_eq!(None, FromStr::from_str::<IpAddr>("1:2::6::8")); + } + + #[test] + fn test_from_str_ipv4_in_ipv6() { + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 49152, 545)), + FromStr::from_str("::192.0.2.33")); + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), + FromStr::from_str("::FFFF:192.0.2.33")); + assert_eq!(Some(Ipv6Addr(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), + FromStr::from_str("64:ff9b::192.0.2.33")); + assert_eq!(Some(Ipv6Addr(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), + FromStr::from_str("2001:db8:122:c000:2:2100:192.0.2.33")); + + // colon after v4 + assert_eq!(None, FromStr::from_str::<IpAddr>("::127.0.0.1:")); + // not enought groups + assert_eq!(None, FromStr::from_str::<IpAddr>("1.2.3.4.5:127.0.0.1")); + // too many groups + assert_eq!(None, FromStr::from_str::<IpAddr>("1.2.3.4.5:6:7:127.0.0.1")); + } + + #[test] + fn test_from_str_socket_addr() { + assert_eq!(Some(SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 80 }), + FromStr::from_str("77.88.21.11:80")); + assert_eq!(Some(SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 }), + FromStr::from_str("[2a02:6b8:0:1::1]:53")); + assert_eq!(Some(SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0x7F00, 1), port: 22 }), + FromStr::from_str("[::127.0.0.1]:22")); + + // without port + assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1")); + // without port + assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1:")); + // wrong brackets around v4 + assert_eq!(None, FromStr::from_str::<SocketAddr>("[127.0.0.1]:22")); + // port out of range + assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1:123456")); + } + + #[test] + fn ipv6_addr_to_str() { + let a1 = Ipv6Addr(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); + assert!(a1.to_str() == ~"::ffff:192.0.2.128" || a1.to_str() == ~"::FFFF:192.0.2.128"); + } + +} diff --git a/src/libstd/rt/kill.rs b/src/libstd/rt/kill.rs index fbc9d1d2445..07b4ea10b6a 100644 --- a/src/libstd/rt/kill.rs +++ b/src/libstd/rt/kill.rs @@ -239,7 +239,7 @@ impl BlockedTask { }; // Even if the task was unkillable before, we use 'Killable' because // multiple pipes will have handles. It does not really mean killable. - handles.consume_iter().transform(|x| Killable(x)).collect() + handles.move_iter().map(|x| Killable(x)).collect() } // This assertion has two flavours because the wake involves an atomic op. @@ -590,7 +590,8 @@ impl Death { #[inline] pub fn assert_may_sleep(&self) { if self.wont_sleep != 0 { - rtabort!("illegal atomic-sleep: can't deschedule inside atomically()"); + rtabort!("illegal atomic-sleep: attempt to reschedule while \ + using an Exclusive or LittleLock"); } } } diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs index e1e7ceacc38..11afd03033a 100644 --- a/src/libstd/rt/local_heap.rs +++ b/src/libstd/rt/local_heap.rs @@ -13,8 +13,6 @@ use libc; use libc::{c_void, uintptr_t, size_t}; use ops::Drop; -use rt; -use rt::OldTaskContext; use rt::local::Local; use rt::task::Task; use unstable::raw; @@ -86,54 +84,41 @@ impl Drop for LocalHeap { // A little compatibility function pub unsafe fn local_free(ptr: *libc::c_char) { - match rt::context() { - OldTaskContext => { - rust_upcall_free_noswitch(ptr); - - extern { - #[fast_ffi] - fn rust_upcall_free_noswitch(ptr: *libc::c_char); - } - } - _ => { - do Local::borrow::<Task,()> |task| { - task.heap.free(ptr as *libc::c_void); - } - } + do Local::borrow::<Task,()> |task| { + task.heap.free(ptr as *libc::c_void); } } pub fn live_allocs() -> *raw::Box<()> { - let region = match rt::context() { - OldTaskContext => { - unsafe { rust_current_boxed_region() } - } - _ => { - do Local::borrow::<Task, *BoxedRegion> |task| { - task.heap.boxed_region - } - } + let region = do Local::borrow::<Task, *BoxedRegion> |task| { + task.heap.boxed_region }; return unsafe { (*region).live_allocs }; } extern { + #[fast_ffi] fn rust_new_memory_region(synchronized: uintptr_t, detailed_leaks: uintptr_t, poison_on_free: uintptr_t) -> *MemoryRegion; + #[fast_ffi] fn rust_delete_memory_region(region: *MemoryRegion); + #[fast_ffi] fn rust_new_boxed_region(region: *MemoryRegion, poison_on_free: uintptr_t) -> *BoxedRegion; + #[fast_ffi] fn rust_delete_boxed_region(region: *BoxedRegion); + #[fast_ffi] fn rust_boxed_region_malloc(region: *BoxedRegion, td: *TypeDesc, size: size_t) -> *OpaqueBox; + #[fast_ffi] fn rust_boxed_region_realloc(region: *BoxedRegion, ptr: *OpaqueBox, size: size_t) -> *OpaqueBox; + #[fast_ffi] fn rust_boxed_region_free(region: *BoxedRegion, box: *OpaqueBox); - fn rust_current_boxed_region() -> *BoxedRegion; } #[cfg(test)] diff --git a/src/libstd/rt/logging.rs b/src/libstd/rt/logging.rs index 9056f0d52e0..117795f6c90 100644 --- a/src/libstd/rt/logging.rs +++ b/src/libstd/rt/logging.rs @@ -58,15 +58,15 @@ impl Logger for StdErrLogger { /// Configure logging by traversing the crate map and setting the /// per-module global logging flags based on the logging spec pub fn init(crate_map: *u8) { + use c_str::ToCStr; use os; - use str::StrSlice; use ptr; use option::{Some, None}; let log_spec = os::getenv("RUST_LOG"); match log_spec { Some(spec) => { - do spec.as_c_str |buf| { + do spec.to_c_str().with_ref |buf| { unsafe { rust_update_log_settings(crate_map, buf) } } } diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 147c75e5c41..1b9f28b95fb 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -63,8 +63,7 @@ Several modules in `core` are clients of `rt`: use cell::Cell; use clone::Clone; use container::Container; -use iter::Times; -use iterator::{Iterator, IteratorUtil}; +use iterator::{Iterator, range}; use option::{Some, None}; use ptr::RawPtr; use rt::local::Local; @@ -121,7 +120,7 @@ mod context; /// Bindings to system threading libraries. mod thread; -/// The runtime configuration, read from environment variables +/// The runtime configuration, read from environment variables. pub mod env; /// The local, managed heap @@ -247,11 +246,16 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { let main = Cell::new(main); - // The shared list of sleeping schedulers. Schedulers wake each other - // occassionally to do new work. + // The shared list of sleeping schedulers. let sleepers = SleeperList::new(); - // The shared work queue. Temporary until work stealing is implemented. - let work_queue = WorkQueue::new(); + + // Create a work queue for each scheduler, ntimes. Create an extra + // for the main thread if that flag is set. We won't steal from it. + let mut work_queues = ~[]; + for _ in range(0u, nscheds) { + let work_queue: WorkQueue<~Task> = WorkQueue::new(); + work_queues.push(work_queue); + } // The schedulers. let mut scheds = ~[]; @@ -259,12 +263,15 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { // sent the Shutdown message to terminate the schedulers. let mut handles = ~[]; - do nscheds.times { + for i in range(0u, nscheds) { rtdebug!("inserting a regular scheduler"); // Every scheduler is driven by an I/O event loop. let loop_ = ~UvEventLoop::new(); - let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone()); + let mut sched = ~Scheduler::new(loop_, + work_queues[i].clone(), + work_queues.clone(), + sleepers.clone()); let handle = sched.make_handle(); scheds.push(sched); @@ -280,9 +287,14 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { let friend_handle = friend_sched.make_handle(); scheds.push(friend_sched); + // This scheduler needs a queue that isn't part of the stealee + // set. + let work_queue = WorkQueue::new(); + let main_loop = ~UvEventLoop::new(); let mut main_sched = ~Scheduler::new_special(main_loop, - work_queue.clone(), + work_queue, + work_queues.clone(), sleepers.clone(), false, Some(friend_handle)); @@ -371,7 +383,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, None, home, main.take()); main_task.death.on_exit = Some(on_exit.take()); - rtdebug!("boostrapping main_task"); + rtdebug!("bootstrapping main_task"); main_sched.bootstrap(main_task); } @@ -379,7 +391,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { rtdebug!("waiting for threads"); // Wait for schedulers - for thread in threads.consume_iter() { + for thread in threads.move_iter() { thread.join(); } @@ -389,46 +401,30 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { } } -/// Possible contexts in which Rust code may be executing. -/// Different runtime services are available depending on context. -/// Mostly used for determining if we're using the new scheduler -/// or the old scheduler. -#[deriving(Eq)] -pub enum RuntimeContext { - // Only the exchange heap is available - GlobalContext, - // The scheduler may be accessed - SchedulerContext, - // Full task services, e.g. local heap, unwinding - TaskContext, - // Running in an old-style task - OldTaskContext -} - -/// Determine the current RuntimeContext -pub fn context() -> RuntimeContext { - - use task::rt::rust_task; - - if unsafe { rust_try_get_task().is_not_null() } { - return OldTaskContext; - } else if Local::exists::<Task>() { - // In this case we know it is a new runtime context, but we - // need to check which one. Going to try borrowing task to - // check. Task should always be in TLS, so hopefully this - // doesn't conflict with other ops that borrow. - return do Local::borrow::<Task,RuntimeContext> |task| { - match task.task_type { - SchedTask => SchedulerContext, - GreenTask(_) => TaskContext +pub fn in_sched_context() -> bool { + unsafe { + match Local::try_unsafe_borrow::<Task>() { + Some(task) => { + match (*task).task_type { + SchedTask => true, + _ => false + } } - }; - } else { - return GlobalContext; + None => false + } } +} - extern { - #[rust_stack] - pub fn rust_try_get_task() -> *rust_task; +pub fn in_green_task_context() -> bool { + unsafe { + match Local::try_unsafe_borrow::<Task>() { + Some(task) => { + match (*task).task_type { + GreenTask(_) => true, + _ => false + } + } + None => false + } } } diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index 990e1a4a3de..ce4e64c47d2 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -13,7 +13,6 @@ use option::{Option, Some, None}; use cast::{transmute, transmute_mut_region, transmute_mut_unsafe}; use clone::Clone; use unstable::raw; - use super::sleeper_list::SleeperList; use super::work_queue::WorkQueue; use super::stack::{StackPool}; @@ -28,6 +27,9 @@ use rt::rtio::RemoteCallback; use rt::metrics::SchedMetrics; use borrow::{to_uint}; use cell::Cell; +use rand::{XorShiftRng, RngUtil}; +use iterator::{range}; +use vec::{OwnedVector}; /// The Scheduler is responsible for coordinating execution of Coroutines /// on a single thread. When the scheduler is running it is owned by @@ -37,9 +39,11 @@ use cell::Cell; /// XXX: This creates too many callbacks to run_sched_once, resulting /// in too much allocation and too many events. pub struct Scheduler { - /// A queue of available work. Under a work-stealing policy there - /// is one per Scheduler. - work_queue: WorkQueue<~Task>, + /// There are N work queues, one per scheduler. + priv work_queue: WorkQueue<~Task>, + /// Work queues for the other schedulers. These are created by + /// cloning the core work queues. + work_queues: ~[WorkQueue<~Task>], /// The queue of incoming messages from other schedulers. /// These are enqueued by SchedHandles after which a remote callback /// is triggered to handle the message. @@ -70,7 +74,10 @@ pub struct Scheduler { run_anything: bool, /// If the scheduler shouldn't run some tasks, a friend to send /// them to. - friend_handle: Option<SchedHandle> + friend_handle: Option<SchedHandle>, + /// A fast XorShift rng for scheduler use + rng: XorShiftRng + } pub struct SchedHandle { @@ -97,10 +104,13 @@ impl Scheduler { pub fn new(event_loop: ~EventLoopObject, work_queue: WorkQueue<~Task>, + work_queues: ~[WorkQueue<~Task>], sleeper_list: SleeperList) -> Scheduler { - Scheduler::new_special(event_loop, work_queue, sleeper_list, true, None) + Scheduler::new_special(event_loop, work_queue, + work_queues, + sleeper_list, true, None) } @@ -108,6 +118,7 @@ impl Scheduler { // task field is None. pub fn new_special(event_loop: ~EventLoopObject, work_queue: WorkQueue<~Task>, + work_queues: ~[WorkQueue<~Task>], sleeper_list: SleeperList, run_anything: bool, friend: Option<SchedHandle>) @@ -120,12 +131,14 @@ impl Scheduler { no_sleep: false, event_loop: event_loop, work_queue: work_queue, + work_queues: work_queues, stack_pool: StackPool::new(), sched_task: None, cleanup_job: None, metrics: SchedMetrics::new(), run_anything: run_anything, - friend_handle: friend + friend_handle: friend, + rng: XorShiftRng::new() } } @@ -248,7 +261,7 @@ impl Scheduler { // Second activity is to try resuming a task from the queue. - let result = sched.resume_task_from_queue(); + let result = sched.do_work(); let mut sched = match result { Some(sched) => { // Failed to dequeue a task, so we return. @@ -415,47 +428,98 @@ impl Scheduler { } } - // Resume a task from the queue - but also take into account that - // it might not belong here. + // Workstealing: In this iteration of the runtime each scheduler + // thread has a distinct work queue. When no work is available + // locally, make a few attempts to steal work from the queues of + // other scheduler threads. If a few steals fail we end up in the + // old "no work" path which is fine. + + // First step in the process is to find a task. This function does + // that by first checking the local queue, and if there is no work + // there, trying to steal from the remote work queues. + fn find_work(&mut self) -> Option<~Task> { + rtdebug!("scheduler looking for work"); + match self.work_queue.pop() { + Some(task) => { + rtdebug!("found a task locally"); + return Some(task) + } + None => { + // Our naive stealing, try kinda hard. + rtdebug!("scheduler trying to steal"); + let _len = self.work_queues.len(); + return self.try_steals(2); + } + } + } + + // With no backoff try stealing n times from the queues the + // scheduler knows about. This naive implementation can steal from + // our own queue or from other special schedulers. + fn try_steals(&mut self, n: uint) -> Option<~Task> { + for _ in range(0, n) { + let index = self.rng.gen_uint_range(0, self.work_queues.len()); + let work_queues = &mut self.work_queues; + match work_queues[index].steal() { + Some(task) => { + rtdebug!("found task by stealing"); return Some(task) + } + None => () + } + }; + rtdebug!("giving up on stealing"); + return None; + } - // If we perform a scheduler action we give away the scheduler ~ - // pointer, if it is still available we return it. + // Given a task, execute it correctly. + fn process_task(~self, task: ~Task) -> Option<~Scheduler> { + let mut this = self; + let mut task = task; - fn resume_task_from_queue(~self) -> Option<~Scheduler> { + rtdebug!("processing a task"); + let home = task.take_unwrap_home(); + match home { + Sched(home_handle) => { + if home_handle.sched_id != this.sched_id() { + rtdebug!("sending task home"); + task.give_home(Sched(home_handle)); + Scheduler::send_task_home(task); + return Some(this); + } else { + rtdebug!("running task here"); + task.give_home(Sched(home_handle)); + this.resume_task_immediately(task); + return None; + } + } + AnySched if this.run_anything => { + rtdebug!("running anysched task here"); + task.give_home(AnySched); + this.resume_task_immediately(task); + return None; + } + AnySched => { + rtdebug!("sending task to friend"); + task.give_home(AnySched); + this.send_to_friend(task); + return Some(this); + } + } + } + + // Bundle the helpers together. + fn do_work(~self) -> Option<~Scheduler> { let mut this = self; - match this.work_queue.pop() { + rtdebug!("scheduler calling do work"); + match this.find_work() { Some(task) => { - let mut task = task; - let home = task.take_unwrap_home(); - match home { - Sched(home_handle) => { - if home_handle.sched_id != this.sched_id() { - task.give_home(Sched(home_handle)); - Scheduler::send_task_home(task); - return Some(this); - } else { - this.event_loop.callback(Scheduler::run_sched_once); - task.give_home(Sched(home_handle)); - this.resume_task_immediately(task); - return None; - } - } - AnySched if this.run_anything => { - this.event_loop.callback(Scheduler::run_sched_once); - task.give_home(AnySched); - this.resume_task_immediately(task); - return None; - } - AnySched => { - task.give_home(AnySched); - this.send_to_friend(task); - return Some(this); - } - } + rtdebug!("found some work! processing the task"); + return this.process_task(task); } None => { + rtdebug!("no work was found, returning the scheduler struct"); return Some(this); } } @@ -711,7 +775,6 @@ impl Scheduler { GiveTask(task, f) => f.to_fn()(self, task) } } - } // The cases for the below function. @@ -745,6 +808,8 @@ impl ClosureConverter for UnsafeTaskReceiver { #[cfg(test)] mod test { + extern mod extra; + use prelude::*; use rt::test::*; use unstable::run_in_bare_thread; @@ -862,12 +927,15 @@ mod test { do run_in_bare_thread { let sleepers = SleeperList::new(); - let work_queue = WorkQueue::new(); + let normal_queue = WorkQueue::new(); + let special_queue = WorkQueue::new(); + let queues = ~[normal_queue.clone(), special_queue.clone()]; // Our normal scheduler let mut normal_sched = ~Scheduler::new( ~UvEventLoop::new(), - work_queue.clone(), + normal_queue, + queues.clone(), sleepers.clone()); let normal_handle = Cell::new(normal_sched.make_handle()); @@ -877,7 +945,8 @@ mod test { // Our special scheduler let mut special_sched = ~Scheduler::new_special( ~UvEventLoop::new(), - work_queue.clone(), + special_queue.clone(), + queues.clone(), sleepers.clone(), false, Some(friend_handle)); diff --git a/src/libstd/rt/select.rs b/src/libstd/rt/select.rs index 006b777b71b..bde703af315 100644 --- a/src/libstd/rt/select.rs +++ b/src/libstd/rt/select.rs @@ -54,7 +54,7 @@ pub fn select<A: Select>(ports: &mut [A]) -> uint { let task_handles = task.make_selectable(ports.len()); for (index, (port, task_handle)) in - ports.mut_iter().zip(task_handles.consume_iter()).enumerate() { + ports.mut_iter().zip(task_handles.move_iter()).enumerate() { // If one of the ports has data by now, it will wake the handle. if port.block_on(sched, task_handle) { ready_index = index; @@ -128,7 +128,7 @@ mod test { let (ports, chans) = unzip(from_fn(num_ports, |_| oneshot::<()>())); let mut dead_chans = ~[]; let mut ports = ports; - for (i, chan) in chans.consume_iter().enumerate() { + for (i, chan) in chans.move_iter().enumerate() { if send_on_chans.contains(&i) { chan.send(()); } else { @@ -145,7 +145,7 @@ mod test { let (ports, chans) = unzip(from_fn(num_ports, |_| stream::<()>())); let mut dead_chans = ~[]; let mut ports = ports; - for (i, chan) in chans.consume_iter().enumerate() { + for (i, chan) in chans.move_iter().enumerate() { if send_on_chans.contains(&i) { chan.send(()); } else { @@ -182,6 +182,7 @@ mod test { fn select_stream() { use util; use comm::GenericChan; + use iter::Times; // Sends 10 buffered packets, and uses select to retrieve them all. // Puts the port in a different spot in the vector each time. @@ -199,9 +200,7 @@ mod test { // get it back out util::swap(port.get_mut_ref(), &mut ports[index]); // NB. Not recv(), because optimistic_check randomly fails. - let (data, new_port) = port.take_unwrap().recv_ready().unwrap(); - assert!(data == 31337); - port = Some(new_port); + assert!(port.get_ref().recv_ready().unwrap() == 31337); } } } @@ -265,6 +264,7 @@ mod test { fn select_racing_senders_helper(killable: bool, send_on_chans: ~[uint]) { use rt::test::spawntask_random; + use iter::Times; do run_in_newsched_task { // A bit of stress, since ordinarily this is just smoke and mirrors. diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 364439a4526..b50e794cce0 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -515,8 +515,8 @@ mod test { do run_in_newsched_task { let (port, chan) = oneshot(); - send_one(chan, 10); - assert!(recv_one(port) == 10); + chan.send(10); + assert!(port.recv() == 10); } } diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs index 792ea5eb33f..ca94468e1ad 100644 --- a/src/libstd/rt/test.rs +++ b/src/libstd/rt/test.rs @@ -15,8 +15,8 @@ use cell::Cell; use clone::Clone; use container::Container; use iterator::{Iterator, range}; -use vec::{OwnedVector, MutableVector}; use super::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr}; +use vec::{OwnedVector, MutableVector, ImmutableVector}; use rt::sched::Scheduler; use unstable::run_in_bare_thread; use rt::thread::Thread; @@ -29,8 +29,12 @@ use result::{Result, Ok, Err}; pub fn new_test_uv_sched() -> Scheduler { + let queue = WorkQueue::new(); + let queues = ~[queue.clone()]; + let mut sched = Scheduler::new(~UvEventLoop::new(), - WorkQueue::new(), + queue, + queues, SleeperList::new()); // Don't wait for the Shutdown message @@ -164,15 +168,21 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { }; let sleepers = SleeperList::new(); - let work_queue = WorkQueue::new(); let mut handles = ~[]; let mut scheds = ~[]; + let mut work_queues = ~[]; for _ in range(0u, nthreads) { + let work_queue = WorkQueue::new(); + work_queues.push(work_queue); + } + + for i in range(0u, nthreads) { let loop_ = ~UvEventLoop::new(); let mut sched = ~Scheduler::new(loop_, - work_queue.clone(), + work_queues[i].clone(), + work_queues.clone(), sleepers.clone()); let handle = sched.make_handle(); @@ -222,7 +232,7 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { } // Wait for schedulers - for thread in threads.consume_iter() { + for thread in threads.move_iter() { thread.join(); } } diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 40e5c8d4bf1..6280b64ecf5 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -10,7 +10,6 @@ use container::Container; use from_str::FromStr; -use iterator::IteratorUtil; use libc; use option::{Some, None}; use os; diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index fd3042899f6..c8b3d41a78d 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -20,7 +20,6 @@ use rt::uv::last_uv_error; use vec; use str; use from_str::{FromStr}; -use num; pub enum UvSocketAddr { UvIpv4SocketAddr(*sockaddr_in), @@ -85,77 +84,10 @@ fn uv_socket_addr_as_socket_addr<T>(addr: UvSocketAddr, f: &fn(SocketAddr) -> T) port as u16 }; let ip_str = str::from_bytes_slice(ip_name).trim_right_chars(&'\x00'); - let ip = match addr { - UvIpv4SocketAddr(*) => { - let ip: ~[u8] = - ip_str.split_iter('.') - .transform(|s: &str| -> u8 { FromStr::from_str(s).unwrap() }) - .collect(); - assert_eq!(ip.len(), 4); - SocketAddr { - ip: Ipv4Addr(ip[0], ip[1], ip[2], ip[3]), - port: ip_port - } - }, - UvIpv6SocketAddr(*) => { - let ip: ~[u16] = { - let expand_shorthand_and_convert = |s: &str| -> ~[~[u16]] { - let convert_each_segment = |s: &str| -> ~[u16] { - let read_hex_segment = |s: &str| -> u16 { - num::FromStrRadix::from_str_radix(s, 16u).unwrap() - }; - match s { - "" => ~[], - // IPv4-Mapped/Compatible IPv6 Address? - s if s.find('.').is_some() => { - let i = s.rfind(':').unwrap_or_default(-1); - - let b = s.slice(i + 1, s.len()); // the ipv4 part - - let h = b.split_iter('.') - .transform(|s: &str| -> u8 { FromStr::from_str(s).unwrap() }) - .transform(|s: u8| -> ~str { fmt!("%02x", s as uint) }) - .collect::<~[~str]>(); - - if i == -1 { - // Ipv4 Compatible Address (::x.x.x.x) - // first 96 bits are zero leaving 32 bits - // for the ipv4 part - // (i.e ::127.0.0.1 == ::7F00:1) - ~[num::FromStrRadix::from_str_radix(h[0] + h[1], 16).unwrap(), - num::FromStrRadix::from_str_radix(h[2] + h[3], 16).unwrap()] - } else { - // Ipv4-Mapped Address (::FFFF:x.x.x.x) - // first 80 bits are zero, followed by all ones - // for the next 16 bits, leaving 32 bits for - // the ipv4 part - // (i.e ::FFFF:127.0.0.1 == ::FFFF:7F00:1) - ~[1, - num::FromStrRadix::from_str_radix(h[0] + h[1], 16).unwrap(), - num::FromStrRadix::from_str_radix(h[2] + h[3], 16).unwrap()] - } - }, - s => s.split_iter(':').transform(read_hex_segment).collect() - } - }; - s.split_str_iter("::").transform(convert_each_segment).collect() - }; - match expand_shorthand_and_convert(ip_str) { - [x] => x, // no shorthand found - [l, r] => l + vec::from_elem(8 - l.len() - r.len(), 0u16) + r, // fill the gap - _ => fail!(), // impossible. only one shorthand allowed. - } - }; - assert_eq!(ip.len(), 8); - SocketAddr { - ip: Ipv6Addr(ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]), - port: ip_port - } - }, - }; + let ip_addr = FromStr::from_str(ip_str).unwrap(); // finally run the closure - f(ip) + f(SocketAddr { ip: ip_addr, port: ip_port }) } pub fn uv_socket_addr_to_socket_addr(addr: UvSocketAddr) -> SocketAddr { diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 70a397199ab..038ebad3540 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -8,26 +8,26 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use option::*; -use result::*; -use ops::Drop; -use cell::Cell; -use cast; +use c_str::ToCStr; use cast::transmute; +use cast; +use cell::Cell; use clone::Clone; use libc::{c_int, c_uint, c_void}; +use ops::Drop; +use option::*; use ptr; +use result::*; use rt::io::IoError; use rt::io::net::ip::{SocketAddr, IpAddr}; -use rt::uv::*; -use rt::uv::idle::IdleWatcher; -use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr}; +use rt::io::{standard_error, OtherIoError}; +use rt::local::Local; use rt::rtio::*; use rt::sched::Scheduler; -use rt::io::{standard_error, OtherIoError}; use rt::tube::Tube; -use rt::local::Local; -use str::StrSlice; +use rt::uv::*; +use rt::uv::idle::IdleWatcher; +use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr}; use unstable::sync::Exclusive; #[cfg(test)] use container::Container; @@ -654,7 +654,7 @@ impl RtioUdpSocket for UvUdpSocket { fn join_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> { let r = unsafe { - do multi.to_str().as_c_str |m_addr| { + do multi.to_str().to_c_str().with_ref |m_addr| { uvll::udp_set_membership(self.native_handle(), m_addr, ptr::null(), uvll::UV_JOIN_GROUP) } @@ -668,7 +668,7 @@ impl RtioUdpSocket for UvUdpSocket { fn leave_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> { let r = unsafe { - do multi.to_str().as_c_str |m_addr| { + do multi.to_str().to_c_str().with_ref |m_addr| { uvll::udp_set_membership(self.native_handle(), m_addr, ptr::null(), uvll::UV_LEAVE_GROUP) } diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 07264839c35..e240395a495 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -29,6 +29,7 @@ #[allow(non_camel_case_types)]; // C types +use c_str::ToCStr; use libc::{size_t, c_int, c_uint, c_void, c_char, uintptr_t}; use libc::{malloc, free}; use libc; @@ -372,12 +373,12 @@ pub unsafe fn is_ip6_addr(addr: *sockaddr) -> bool { } pub unsafe fn malloc_ip4_addr(ip: &str, port: int) -> *sockaddr_in { - do ip.as_c_str |ip_buf| { + do ip.to_c_str().with_ref |ip_buf| { rust_uv_ip4_addrp(ip_buf as *u8, port as libc::c_int) } } pub unsafe fn malloc_ip6_addr(ip: &str, port: int) -> *sockaddr_in6 { - do ip.as_c_str |ip_buf| { + do ip.to_c_str().with_ref |ip_buf| { rust_uv_ip6_addrp(ip_buf as *u8, port as libc::c_int) } } @@ -448,13 +449,6 @@ pub unsafe fn get_base_from_buf(buf: uv_buf_t) -> *u8 { pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t { return rust_uv_get_len_from_buf(buf); } -pub unsafe fn malloc_buf_base_of(suggested_size: size_t) -> *u8 { - return rust_uv_malloc_buf_base_of(suggested_size); -} -pub unsafe fn free_base_of_buf(buf: uv_buf_t) { - rust_uv_free_base_of_buf(buf); -} - pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str { let err = last_error(uv_loop); let err_ptr = ptr::to_unsafe_ptr(&err); @@ -558,8 +552,6 @@ extern { repeat: libc::uint64_t) -> c_int; fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int; - fn rust_uv_malloc_buf_base_of(sug_size: size_t) -> *u8; - fn rust_uv_free_base_of_buf(buf: uv_buf_t); fn rust_uv_get_stream_handle_from_connect_req(connect_req: *uv_connect_t) -> *uv_stream_t; fn rust_uv_get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t; fn rust_uv_get_loop_for_uv_handle(handle: *c_void) -> *c_void; diff --git a/src/libstd/run.rs b/src/libstd/run.rs index ef3d881c5fe..31e317604c7 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -12,6 +12,7 @@ #[allow(missing_doc)]; +use c_str::ToCStr; use cast; use clone::Clone; use comm::{stream, SharedChan, GenericChan, GenericPort}; @@ -505,7 +506,7 @@ fn spawn_process_os(prog: &str, args: &[~str], do with_envp(env) |envp| { do with_dirp(dir) |dirp| { - do cmd.as_c_str |cmdp| { + do cmd.to_c_str().with_ref |cmdp| { let created = CreateProcessA(ptr::null(), cast::transmute(cmdp), ptr::mut_null(), ptr::mut_null(), TRUE, 0, envp, dirp, &mut si, &mut pi); @@ -632,7 +633,6 @@ fn spawn_process_os(prog: &str, args: &[~str], use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; use libc::funcs::bsd44::getdtablesize; - use int; mod rustrt { use libc::c_void; @@ -665,10 +665,9 @@ fn spawn_process_os(prog: &str, args: &[~str], fail!("failure in dup3(err_fd, 2): %s", os::last_os_error()); } // close all other fds - do int::range_rev(getdtablesize() as int, 3) |fd| { + for fd in range(3, getdtablesize()).invert() { close(fd as c_int); - true - }; + } do with_dirp(dir) |dirp| { if !dirp.is_null() && chdir(dirp) == -1 { @@ -690,46 +689,62 @@ fn spawn_process_os(prog: &str, args: &[~str], } #[cfg(unix)] -fn with_argv<T>(prog: &str, args: &[~str], - cb: &fn(**libc::c_char) -> T) -> T { - let mut argptrs = ~[prog.as_c_str(|b| b)]; - let mut tmps = ~[]; +fn with_argv<T>(prog: &str, args: &[~str], cb: &fn(**libc::c_char) -> T) -> T { + use vec; + + // We can't directly convert `str`s into `*char`s, as someone needs to hold + // a reference to the intermediary byte buffers. So first build an array to + // hold all the ~[u8] byte strings. + let mut tmps = vec::with_capacity(args.len() + 1); + + tmps.push(prog.to_c_str()); + for arg in args.iter() { - let t = @(*arg).clone(); - tmps.push(t); - argptrs.push(t.as_c_str(|b| b)); + tmps.push(arg.to_c_str()); } - argptrs.push(ptr::null()); - argptrs.as_imm_buf(|buf, _len| cb(buf)) + + // Next, convert each of the byte strings into a pointer. This is + // technically unsafe as the caller could leak these pointers out of our + // scope. + let mut ptrs = do tmps.map |tmp| { + tmp.with_ref(|buf| buf) + }; + + // Finally, make sure we add a null pointer. + ptrs.push(ptr::null()); + + ptrs.as_imm_buf(|buf, _| cb(buf)) } #[cfg(unix)] fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T { - // On posixy systems we can pass a char** for envp, which is - // a null-terminated array of "k=v\n" strings. + use vec; + + // On posixy systems we can pass a char** for envp, which is a + // null-terminated array of "k=v\n" strings. Like `with_argv`, we have to + // have a temporary buffer to hold the intermediary `~[u8]` byte strings. match env { - Some(es) => { - let mut tmps = ~[]; - let mut ptrs = ~[]; - - for pair in es.iter() { - // Use of match here is just to workaround limitations - // in the stage0 irrefutable pattern impl. - match pair { - &(ref k, ref v) => { - let kv = @fmt!("%s=%s", *k, *v); - tmps.push(kv); - ptrs.push(kv.as_c_str(|b| b)); - } + Some(env) => { + let mut tmps = vec::with_capacity(env.len()); + + for pair in env.iter() { + // Use of match here is just to workaround limitations + // in the stage0 irrefutable pattern impl. + let kv = fmt!("%s=%s", pair.first(), pair.second()); + tmps.push(kv.to_c_str()); } - } - ptrs.push(ptr::null()); - ptrs.as_imm_buf(|p, _len| - unsafe { cb(::cast::transmute(p)) } - ) - } - _ => cb(ptr::null()) + // Once again, this is unsafe. + let mut ptrs = do tmps.map |tmp| { + tmp.with_ref(|buf| buf) + }; + ptrs.push(ptr::null()); + + do ptrs.as_imm_buf |buf, _| { + unsafe { cb(cast::transmute(buf)) } + } + } + _ => cb(ptr::null()) } } @@ -739,38 +754,41 @@ fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T { // rather a concatenation of null-terminated k=v\0 sequences, with a final // \0 to terminate. match env { - Some(es) => { - let mut blk = ~[]; - for pair in es.iter() { - let kv = fmt!("%s=%s", pair.first(), pair.second()); - blk.push_all(kv.to_bytes_with_null()); + Some(env) => { + let mut blk = ~[]; + + for pair in env.iter() { + let kv = fmt!("%s=%s", pair.first(), pair.second()); + blk.push_all(kv.as_bytes()); + blk.push(0); + } + + blk.push(0); + + do blk.as_imm_buf |p, _len| { + unsafe { cb(cast::transmute(p)) } + } } - blk.push(0); - blk.as_imm_buf(|p, _len| - unsafe { cb(::cast::transmute(p)) } - ) - } - _ => cb(ptr::mut_null()) + _ => cb(ptr::mut_null()) } } -fn with_dirp<T>(d: Option<&Path>, - cb: &fn(*libc::c_char) -> T) -> T { +fn with_dirp<T>(d: Option<&Path>, cb: &fn(*libc::c_char) -> T) -> T { match d { - Some(dir) => dir.to_str().as_c_str(cb), + Some(dir) => dir.to_c_str().with_ref(|buf| cb(buf)), None => cb(ptr::null()) } } #[cfg(windows)] -priv fn free_handle(handle: *()) { +fn free_handle(handle: *()) { unsafe { libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle)); } } #[cfg(unix)] -priv fn free_handle(_handle: *()) { +fn free_handle(_handle: *()) { // unix has no process handle object, just a pid } @@ -825,7 +843,7 @@ pub fn process_output(prog: &str, args: &[~str]) -> ProcessOutput { * operate on a none-existant process or, even worse, on a newer process * with the same id. */ -priv fn waitpid(pid: pid_t) -> int { +fn waitpid(pid: pid_t) -> int { return waitpid_os(pid); #[cfg(windows)] @@ -1311,11 +1329,11 @@ mod tests { let output = str::from_bytes(prog.finish_with_output().output); let r = os::env(); - for &(k, v) in r.iter() { + for &(ref k, ref v) in r.iter() { // don't check android RANDOM variables - if k != ~"RANDOM" { - assert!(output.contains(fmt!("%s=%s", k, v)) || - output.contains(fmt!("%s=\'%s\'", k, v))); + if *k != ~"RANDOM" { + assert!(output.contains(fmt!("%s=%s", *k, *v)) || + output.contains(fmt!("%s=\'%s\'", *k, *v))); } } } diff --git a/src/libstd/std.rs b/src/libstd/std.rs index 7000b56069d..aa0bb905e9a 100644 --- a/src/libstd/std.rs +++ b/src/libstd/std.rs @@ -164,13 +164,13 @@ pub mod trie; pub mod task; pub mod comm; -pub mod pipes; pub mod local_data; /* Runtime and platform support */ pub mod libc; +pub mod c_str; pub mod os; pub mod path; pub mod rand; @@ -213,7 +213,6 @@ mod std { pub use kinds; pub use local_data; pub use sys; - pub use pipes; pub use unstable; pub use str; pub use os; diff --git a/src/libstd/str.rs b/src/libstd/str.rs index c4bd2c5435a..26a00cca4c8 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -23,9 +23,9 @@ use char::Char; use clone::Clone; use container::{Container, Mutable}; use iter::Times; -use iterator::{Iterator, FromIterator, Extendable, IteratorUtil}; +use iterator::{Iterator, FromIterator, Extendable}; use iterator::{Filter, AdditiveIterator, Map}; -use iterator::{Invert, DoubleEndedIterator, DoubleEndedIteratorUtil}; +use iterator::{Invert, DoubleEndedIterator}; use libc; use num::Zero; use option::{None, Option, Some}; @@ -33,6 +33,7 @@ use ptr; use ptr::RawPtr; use to_str::ToStr; use uint; +#[cfg(stage0)] use unstable::raw::Repr; use vec; use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector, MutableVector}; @@ -58,7 +59,7 @@ pub fn from_bytes(vv: &[u8]) -> ~str { use str::not_utf8::cond; if !is_utf8(vv) { - let first_bad_byte = *vv.iter().find_(|&b| !is_utf8([*b])).unwrap(); + let first_bad_byte = *vv.iter().find(|&b| !is_utf8([*b])).unwrap(); cond.raise(fmt!("from_bytes: input is not UTF-8; first bad byte is %u", first_bad_byte as uint)) } else { @@ -75,7 +76,7 @@ pub fn from_bytes_owned(vv: ~[u8]) -> ~str { use str::not_utf8::cond; if !is_utf8(vv) { - let first_bad_byte = *vv.iter().find_(|&b| !is_utf8([*b])).unwrap(); + let first_bad_byte = *vv.iter().find(|&b| !is_utf8([*b])).unwrap(); cond.raise(fmt!("from_bytes: input is not UTF-8; first bad byte is %u", first_bad_byte as uint)) } else { @@ -83,21 +84,6 @@ pub fn from_bytes_owned(vv: ~[u8]) -> ~str { } } -/// Convert a vector of bytes to a UTF-8 string. -/// The vector needs to be one byte longer than the string, and end with a 0 byte. -/// -/// Compared to `from_bytes()`, this fn doesn't need to allocate a new owned str. -/// -/// # Failure -/// -/// Fails if invalid UTF-8 -/// Fails if not null terminated -pub fn from_bytes_with_null<'a>(vv: &'a [u8]) -> &'a str { - assert_eq!(vv[vv.len() - 1], 0); - assert!(is_utf8(vv)); - return unsafe { raw::from_bytes_with_null(vv) }; -} - /// Converts a vector to a string slice without performing any allocations. /// /// Once the slice has been validated as utf-8, it is transmuted in-place and @@ -106,6 +92,7 @@ pub fn from_bytes_with_null<'a>(vv: &'a [u8]) -> &'a str { /// # Failure /// /// Fails if invalid UTF-8 +#[cfg(stage0)] pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str { unsafe { assert!(is_utf8(vector)); @@ -115,6 +102,20 @@ pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str { } } +/// Converts a vector to a string slice without performing any allocations. +/// +/// Once the slice has been validated as utf-8, it is transmuted in-place and +/// returned as a '&str' instead of a '&[u8]' +/// +/// # Failure +/// +/// Fails if invalid UTF-8 +#[cfg(not(stage0))] +pub fn from_bytes_slice<'a>(v: &'a [u8]) -> &'a str { + assert!(is_utf8(v)); + unsafe { cast::transmute(v) } +} + impl ToStr for ~str { #[inline] fn to_str(&self) -> ~str { self.to_owned() } @@ -133,11 +134,23 @@ impl ToStr for @str { /// # Failure /// /// Fails if invalid UTF-8 +#[cfg(stage0)] pub fn from_byte(b: u8) -> ~str { assert!(b < 128u8); unsafe { cast::transmute(~[b, 0u8]) } } +/// Convert a byte to a UTF-8 string +/// +/// # Failure +/// +/// Fails if invalid UTF-8 +#[cfg(not(stage0))] +pub fn from_byte(b: u8) -> ~str { + assert!(b < 128u8); + unsafe { ::cast::transmute(~[b]) } +} + /// Convert a char to a string pub fn from_char(ch: char) -> ~str { let mut buf = ~""; @@ -168,10 +181,11 @@ pub trait StrVector { impl<'self, S: Str> StrVector for &'self [S] { /// Concatenate a vector of strings. + #[cfg(stage0)] pub fn concat(&self) -> ~str { if self.is_empty() { return ~""; } - let len = self.iter().transform(|s| s.as_slice().len()).sum(); + let len = self.iter().map(|s| s.as_slice().len()).sum(); let mut s = with_capacity(len); @@ -191,7 +205,32 @@ impl<'self, S: Str> StrVector for &'self [S] { s } + /// Concatenate a vector of strings. + #[cfg(not(stage0))] + pub fn concat(&self) -> ~str { + if self.is_empty() { return ~""; } + + let len = self.iter().map(|s| s.as_slice().len()).sum(); + + let mut s = with_capacity(len); + + unsafe { + do s.as_mut_buf |buf, _| { + let mut buf = buf; + for ss in self.iter() { + do ss.as_slice().as_imm_buf |ssbuf, sslen| { + ptr::copy_memory(buf, ssbuf, sslen); + buf = buf.offset(sslen as int); + } + } + } + raw::set_len(&mut s, len); + } + s + } + /// Concatenate a vector of strings, placing a given separator between each. + #[cfg(stage0)] pub fn connect(&self, sep: &str) -> ~str { if self.is_empty() { return ~""; } @@ -200,7 +239,7 @@ impl<'self, S: Str> StrVector for &'self [S] { // this is wrong without the guarantee that `self` is non-empty let len = sep.len() * (self.len() - 1) - + self.iter().transform(|s| s.as_slice().len()).sum(); + + self.iter().map(|s| s.as_slice().len()).sum(); let mut s = ~""; let mut first = true; @@ -230,6 +269,45 @@ impl<'self, S: Str> StrVector for &'self [S] { } s } + + /// Concatenate a vector of strings, placing a given separator between each. + #[cfg(not(stage0))] + pub fn connect(&self, sep: &str) -> ~str { + if self.is_empty() { return ~""; } + + // concat is faster + if sep.is_empty() { return self.concat(); } + + // this is wrong without the guarantee that `self` is non-empty + let len = sep.len() * (self.len() - 1) + + self.iter().map(|s| s.as_slice().len()).sum(); + let mut s = ~""; + let mut first = true; + + s.reserve(len); + + unsafe { + do s.as_mut_buf |buf, _| { + do sep.as_imm_buf |sepbuf, seplen| { + let mut buf = buf; + for ss in self.iter() { + do ss.as_slice().as_imm_buf |ssbuf, sslen| { + if first { + first = false; + } else { + ptr::copy_memory(buf, sepbuf, seplen); + buf = buf.offset(seplen as int); + } + ptr::copy_memory(buf, ssbuf, sslen); + buf = buf.offset(sslen as int); + } + } + } + } + raw::set_len(&mut s, len); + } + s + } } /// Something that can be used to compare against a character @@ -500,7 +578,7 @@ Section: Comparing strings */ /// Bytewise slice equality -#[cfg(not(test))] +#[cfg(not(test), stage0)] #[lang="str_eq"] #[inline] pub fn eq_slice(a: &str, b: &str) -> bool { @@ -518,7 +596,28 @@ pub fn eq_slice(a: &str, b: &str) -> bool { } } -#[cfg(test)] +/// Bytewise slice equality +#[cfg(not(test), not(stage0))] +#[lang="str_eq"] +#[inline] +pub fn eq_slice(a: &str, b: &str) -> bool { + do a.as_imm_buf |ap, alen| { + do b.as_imm_buf |bp, blen| { + if (alen != blen) { false } + else { + unsafe { + libc::memcmp(ap as *libc::c_void, + bp as *libc::c_void, + alen as libc::size_t) == 0 + } + } + } + } +} + +/// Bytewise slice equality +#[cfg(test, stage0)] +#[lang="str_eq"] #[inline] pub fn eq_slice(a: &str, b: &str) -> bool { do a.as_imm_buf |ap, alen| { @@ -535,6 +634,24 @@ pub fn eq_slice(a: &str, b: &str) -> bool { } } +/// Bytewise slice equality +#[cfg(test, not(stage0))] +#[inline] +pub fn eq_slice(a: &str, b: &str) -> bool { + do a.as_imm_buf |ap, alen| { + do b.as_imm_buf |bp, blen| { + if (alen != blen) { false } + else { + unsafe { + libc::memcmp(ap as *libc::c_void, + bp as *libc::c_void, + alen as libc::size_t) == 0 + } + } + } + } +} + /// Bytewise string equality #[cfg(not(test))] #[lang="uniq_str_eq"] @@ -738,7 +855,7 @@ pub fn count_bytes<'b>(s: &'b str, start: uint, n: uint) -> uint { } // https://tools.ietf.org/html/rfc3629 -priv static UTF8_CHAR_WIDTH: [u8, ..256] = [ +static UTF8_CHAR_WIDTH: [u8, ..256] = [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, @@ -781,15 +898,15 @@ macro_rules! utf8_acc_cont_byte( ) // UTF-8 tags and ranges -priv static TAG_CONT_U8: u8 = 128u8; -priv static TAG_CONT: uint = 128u; -priv static MAX_ONE_B: uint = 128u; -priv static TAG_TWO_B: uint = 192u; -priv static MAX_TWO_B: uint = 2048u; -priv static TAG_THREE_B: uint = 224u; -priv static MAX_THREE_B: uint = 65536u; -priv static TAG_FOUR_B: uint = 240u; -priv static MAX_UNICODE: uint = 1114112u; +static TAG_CONT_U8: u8 = 128u8; +static TAG_CONT: uint = 128u; +static MAX_ONE_B: uint = 128u; +static TAG_TWO_B: uint = 192u; +static MAX_TWO_B: uint = 2048u; +static TAG_THREE_B: uint = 224u; +static MAX_THREE_B: uint = 65536u; +static TAG_FOUR_B: uint = 240u; +static MAX_UNICODE: uint = 1114112u; /// Unsafe operations pub mod raw { @@ -800,20 +917,12 @@ pub mod raw { use str::is_utf8; use vec; use vec::MutableVector; - use unstable::raw::{Slice, String}; - - /// Create a Rust string from a null-terminated *u8 buffer - pub unsafe fn from_buf(buf: *u8) -> ~str { - let mut curr = buf; - let mut i = 0u; - while *curr != 0u8 { - i += 1u; - curr = ptr::offset(buf, i as int); - } - return from_buf_len(buf, i); - } + use unstable::raw::Slice; + #[cfg(stage0)] + use unstable::raw::String; /// Create a Rust string from a *u8 buffer of the given length + #[cfg(stage0)] pub unsafe fn from_buf_len(buf: *u8, len: uint) -> ~str { let mut v: ~[u8] = vec::with_capacity(len + 1); v.as_mut_buf(|vbuf, _len| { @@ -823,17 +932,31 @@ pub mod raw { v.push(0u8); assert!(is_utf8(v)); - return cast::transmute(v); + cast::transmute(v) } - /// Create a Rust string from a null-terminated C string - pub unsafe fn from_c_str(c_str: *libc::c_char) -> ~str { - from_buf(c_str as *u8) + /// Create a Rust string from a *u8 buffer of the given length + #[cfg(not(stage0))] + pub unsafe fn from_buf_len(buf: *u8, len: uint) -> ~str { + let mut v: ~[u8] = vec::with_capacity(len); + do v.as_mut_buf |vbuf, _len| { + ptr::copy_memory(vbuf, buf as *u8, len) + }; + vec::raw::set_len(&mut v, len); + + assert!(is_utf8(v)); + ::cast::transmute(v) } - /// Create a Rust string from a `*c_char` buffer of the given length - pub unsafe fn from_c_str_len(c_str: *libc::c_char, len: uint) -> ~str { - from_buf_len(c_str as *u8, len) + /// Create a Rust string from a null-terminated C string + pub unsafe fn from_c_str(buf: *libc::c_char) -> ~str { + let mut curr = buf; + let mut i = 0; + while *curr != 0 { + i += 1; + curr = ptr::offset(buf, i); + } + from_buf_len(buf as *u8, i as uint) } /// Converts a vector of bytes to a new owned string. @@ -845,15 +968,17 @@ pub mod raw { /// Converts an owned vector of bytes to a new owned string. This assumes /// that the utf-8-ness of the vector has already been validated + #[cfg(stage0)] pub unsafe fn from_bytes_owned(mut v: ~[u8]) -> ~str { v.push(0u8); cast::transmute(v) } - /// Converts a vector of bytes to a string. - /// The byte slice needs to contain valid utf8 and needs to be one byte longer than - /// the string, if possible ending in a 0 byte. - pub unsafe fn from_bytes_with_null<'a>(v: &'a [u8]) -> &'a str { + /// Converts an owned vector of bytes to a new owned string. This assumes + /// that the utf-8-ness of the vector has already been validated + #[cfg(not(stage0))] + #[inline] + pub unsafe fn from_bytes_owned(v: ~[u8]) -> ~str { cast::transmute(v) } @@ -863,6 +988,7 @@ pub mod raw { /// Form a slice from a C string. Unsafe because the caller must ensure the /// C string has the static lifetime, or else the return value may be /// invalidated later. + #[cfg(stage0)] pub unsafe fn c_str_to_static_slice(s: *libc::c_char) -> &'static str { let s = s as *u8; let mut curr = s; @@ -876,6 +1002,23 @@ pub mod raw { cast::transmute(v) } + /// Form a slice from a C string. Unsafe because the caller must ensure the + /// C string has the static lifetime, or else the return value may be + /// invalidated later. + #[cfg(not(stage0))] + pub unsafe fn c_str_to_static_slice(s: *libc::c_char) -> &'static str { + let s = s as *u8; + let mut curr = s; + let mut len = 0u; + while *curr != 0u8 { + len += 1u; + curr = ptr::offset(s, len as int); + } + let v = Slice { data: s, len: len }; + assert!(is_utf8(::cast::transmute(v))); + ::cast::transmute(v) + } + /// Takes a bytewise (not UTF-8) slice from a string. /// /// Returns the substring from [`begin`..`end`). @@ -884,6 +1027,7 @@ pub mod raw { /// /// If begin is greater than end. /// If end is greater than the length of the string. + #[cfg(stage0)] #[inline] pub unsafe fn slice_bytes<'a>(s: &'a str, begin: uint, end: uint) -> &'a str { do s.as_imm_buf |sbuf, n| { @@ -897,16 +1041,47 @@ pub mod raw { } } + /// Takes a bytewise (not UTF-8) slice from a string. + /// + /// Returns the substring from [`begin`..`end`). + /// + /// # Failure + /// + /// If begin is greater than end. + /// If end is greater than the length of the string. + #[cfg(not(stage0))] + #[inline] + pub unsafe fn slice_bytes<'a>(s: &'a str, begin: uint, end: uint) -> &'a str { + do s.as_imm_buf |sbuf, n| { + assert!((begin <= end)); + assert!((end <= n)); + + cast::transmute(Slice { + data: ptr::offset(sbuf, begin as int), + len: end - begin, + }) + } + } + /// Appends a byte to a string. (Not UTF-8 safe). + #[cfg(stage0)] pub unsafe fn push_byte(s: &mut ~str, b: u8) { let new_len = s.len() + 1; s.reserve_at_least(new_len); do s.as_mut_buf |buf, len| { - *ptr::mut_offset(buf, (len-1) as int) = b; + *ptr::mut_offset(buf, len as int) = b; } set_len(&mut *s, new_len); } + /// Appends a byte to a string. (Not UTF-8 safe). + #[cfg(not(stage0))] + #[inline] + pub unsafe fn push_byte(s: &mut ~str, b: u8) { + let v: &mut ~[u8] = cast::transmute(s); + v.push(b); + } + /// Appends a vector of bytes to a string. (Not UTF-8 safe). unsafe fn push_bytes(s: &mut ~str, bytes: &[u8]) { let new_len = s.len() + bytes.len(); @@ -933,6 +1108,7 @@ pub mod raw { } /// Sets the length of the string and adds the null terminator + #[cfg(stage0)] #[inline] pub unsafe fn set_len(v: &mut ~str, new_len: uint) { let v: **mut String = cast::transmute(v); @@ -942,6 +1118,23 @@ pub mod raw { *null = 0u8; } + /// Sets the length of a string + /// + /// This will explicitly set the size of the string, without actually + /// modifing its buffers, so it is up to the caller to ensure that + /// the string is actually the specified size. + #[cfg(not(stage0))] + #[inline] + pub unsafe fn set_len(s: &mut ~str, new_len: uint) { + let v: &mut ~[u8] = cast::transmute(s); + vec::raw::set_len(v, new_len) + } + + /// Sets the length of a string + /// + /// This will explicitly set the size of the string, without actually + /// modifing its buffers, so it is up to the caller to ensure that + /// the string is actually the specified size. #[test] fn test_from_buf_len() { unsafe { @@ -1050,34 +1243,16 @@ pub mod traits { impl<'self> Ord for &'self str { #[inline] fn lt(&self, other: & &'self str) -> bool { self.cmp(other) == Less } - #[inline] - fn le(&self, other: & &'self str) -> bool { self.cmp(other) != Greater } - #[inline] - fn ge(&self, other: & &'self str) -> bool { self.cmp(other) != Less } - #[inline] - fn gt(&self, other: & &'self str) -> bool { self.cmp(other) == Greater } } impl Ord for ~str { #[inline] fn lt(&self, other: &~str) -> bool { self.cmp(other) == Less } - #[inline] - fn le(&self, other: &~str) -> bool { self.cmp(other) != Greater } - #[inline] - fn ge(&self, other: &~str) -> bool { self.cmp(other) != Less } - #[inline] - fn gt(&self, other: &~str) -> bool { self.cmp(other) == Greater } } impl Ord for @str { #[inline] fn lt(&self, other: &@str) -> bool { self.cmp(other) == Less } - #[inline] - fn le(&self, other: &@str) -> bool { self.cmp(other) != Greater } - #[inline] - fn ge(&self, other: &@str) -> bool { self.cmp(other) != Less } - #[inline] - fn gt(&self, other: &@str) -> bool { self.cmp(other) == Greater } } impl<'self, S: Str> Equiv<S> for &'self str { @@ -1137,10 +1312,17 @@ impl<'self> Str for @str { } impl<'self> Container for &'self str { + #[cfg(stage0)] #[inline] fn len(&self) -> uint { do self.as_imm_buf |_p, n| { n - 1u } } + + #[cfg(not(stage0))] + #[inline] + fn len(&self) -> uint { + do self.as_imm_buf |_p, n| { n } + } } impl Container for ~str { @@ -1228,7 +1410,6 @@ pub trait StrSlice<'self> { fn subslice_offset(&self, inner: &str) -> uint; fn as_imm_buf<T>(&self, f: &fn(*u8, uint) -> T) -> T; - fn as_c_str<T>(&self, f: &fn(*libc::c_char) -> T) -> T; } /// Extension methods for strings @@ -1264,7 +1445,7 @@ impl<'self> StrSlice<'self> for &'self str { /// ~~~ #[inline] fn iter(&self) -> CharIterator<'self> { - self.char_offset_iter().transform(|(_, c)| c) + self.char_offset_iter().map(|(_, c)| c) } /// An iterator over the characters of `self`, in reverse order. @@ -1276,7 +1457,7 @@ impl<'self> StrSlice<'self> for &'self str { /// An iterator over the bytes of `self` #[inline] fn byte_iter(&self) -> ByteIterator<'self> { - self.as_bytes().iter().transform(|&b| b) + self.as_bytes().iter().map(|&b| b) } /// An iterator over the bytes of `self`, in reverse order @@ -1384,7 +1565,7 @@ impl<'self> StrSlice<'self> for &'self str { /// An iterator over the lines of a string, separated by either /// `\n` or (`\r\n`). fn any_line_iter(&self) -> AnyLineIterator<'self> { - do self.line_iter().transform |line| { + do self.line_iter().map |line| { let l = line.len(); if l > 0 && line[l - 1] == '\r' as u8 { line.slice(0, l - 1) } else { line } @@ -1412,7 +1593,7 @@ impl<'self> StrSlice<'self> for &'self str { /// Returns the number of characters that a string holds #[inline] - fn char_len(&self) -> uint { self.iter().len_() } + fn char_len(&self) -> uint { self.iter().len() } /// Returns a slice of the given string from the byte range /// [`begin`..`end`) @@ -1615,6 +1796,7 @@ impl<'self> StrSlice<'self> for &'self str { } /// Copy a slice into a new unique str + #[cfg(stage0)] #[inline] fn to_owned(&self) -> ~str { do self.as_imm_buf |src, len| { @@ -1632,6 +1814,24 @@ impl<'self> StrSlice<'self> for &'self str { } } + /// Copy a slice into a new unique str + #[cfg(not(stage0))] + #[inline] + fn to_owned(&self) -> ~str { + do self.as_imm_buf |src, len| { + unsafe { + let mut v = vec::with_capacity(len); + + do v.as_mut_buf |dst, _| { + ptr::copy_memory(dst, src, len); + } + vec::raw::set_len(&mut v, len); + ::cast::transmute(v) + } + } + } + + #[cfg(stage0)] #[inline] fn to_managed(&self) -> @str { let v = at_vec::from_fn(self.len() + 1, |i| { @@ -1640,6 +1840,15 @@ impl<'self> StrSlice<'self> for &'self str { unsafe { cast::transmute(v) } } + #[cfg(not(stage0))] + #[inline] + fn to_managed(&self) -> @str { + unsafe { + let v: *&[u8] = cast::transmute(self); + cast::transmute(at_vec::to_managed(*v)) + } + } + /// Converts to a vector of `u16` encoded as UTF-16. fn to_utf16(&self) -> ~[u16] { let mut u = ~[]; @@ -1780,6 +1989,7 @@ impl<'self> StrSlice<'self> for &'self str { /// Work with the byte buffer of a string as a byte slice. /// /// The byte slice does not include the null terminator. + #[cfg(stage0)] fn as_bytes(&self) -> &'self [u8] { unsafe { let mut slice = self.repr(); @@ -1788,6 +1998,14 @@ impl<'self> StrSlice<'self> for &'self str { } } + /// Work with the byte buffer of a string as a byte slice. + /// + /// The byte slice does not include the null terminator. + #[cfg(not(stage0))] + fn as_bytes(&self) -> &'self [u8] { + unsafe { cast::transmute(*self) } + } + /// Returns the byte index of the first character of `self` that matches `search` /// /// # Return value @@ -1854,6 +2072,7 @@ impl<'self> StrSlice<'self> for &'self str { } /// Given a string, make a new string with repeated copies of it. + #[cfg(stage0)] fn repeat(&self, nn: uint) -> ~str { do self.as_imm_buf |buf, len| { // ignore the NULL terminator @@ -1875,6 +2094,27 @@ impl<'self> StrSlice<'self> for &'self str { } } + /// Given a string, make a new string with repeated copies of it. + #[cfg(not(stage0))] + fn repeat(&self, nn: uint) -> ~str { + do self.as_imm_buf |buf, len| { + let mut ret = with_capacity(nn * len); + + unsafe { + do ret.as_mut_buf |rbuf, _len| { + let mut rbuf = rbuf; + + do nn.times { + ptr::copy_memory(rbuf, buf, len); + rbuf = rbuf.offset(len as int); + } + } + raw::set_len(&mut ret, nn * len); + } + ret + } + } + /// Retrieves the first character from a string slice and returns /// it. This does not allocate a new string; instead, it returns a /// slice that point one character beyond the character that was @@ -1977,61 +2217,6 @@ impl<'self> StrSlice<'self> for &'self str { let v: &[u8] = unsafe { cast::transmute(*self) }; v.as_imm_buf(f) } - - /// Work with the byte buffer of a string as a null-terminated C string. - /// - /// Allows for unsafe manipulation of strings, which is useful for foreign - /// interop. This is similar to `str::as_buf`, but guarantees null-termination. - /// If the given slice is not already null-terminated, this function will - /// allocate a temporary, copy the slice, null terminate it, and pass - /// that instead. - /// - /// # Example - /// - /// ~~~ {.rust} - /// let s = "PATH".as_c_str(|path| libc::getenv(path)); - /// ~~~ - #[inline] - fn as_c_str<T>(&self, f: &fn(*libc::c_char) -> T) -> T { - do self.as_imm_buf |buf, len| { - // NB: len includes the trailing null. - assert!(len > 0); - if unsafe { *(ptr::offset(buf, (len - 1) as int)) != 0 } { - self.to_owned().as_c_str(|s| f(s)) - } else { - f(buf as *libc::c_char) - } - } - } -} - -#[allow(missing_doc)] -pub trait NullTerminatedStr { - fn as_bytes_with_null<'a>(&'a self) -> &'a [u8]; -} - -impl NullTerminatedStr for ~str { - /// Work with the byte buffer of a string as a byte slice. - /// - /// The byte slice does include the null terminator. - #[inline] - fn as_bytes_with_null<'a>(&'a self) -> &'a [u8] { - let ptr: &'a ~[u8] = unsafe { cast::transmute(self) }; - let slice: &'a [u8] = *ptr; - slice - } -} - -impl NullTerminatedStr for @str { - /// Work with the byte buffer of a string as a byte slice. - /// - /// The byte slice does include the null terminator. - #[inline] - fn as_bytes_with_null<'a>(&'a self) -> &'a [u8] { - let ptr: &'a @[u8] = unsafe { cast::transmute(self) }; - let slice: &'a [u8] = *ptr; - slice - } } #[allow(missing_doc)] @@ -2046,6 +2231,7 @@ pub trait OwnedStr { fn reserve(&mut self, n: uint); fn reserve_at_least(&mut self, n: uint); fn capacity(&self) -> uint; + #[cfg(stage0)] fn to_bytes_with_null(self) -> ~[u8]; /// Work with the mutable byte buffer and length of a slice. @@ -2192,6 +2378,7 @@ impl OwnedStr for ~str { /// /// * s - A string /// * n - The number of bytes to reserve space for + #[cfg(stage0)] #[inline] pub fn reserve(&mut self, n: uint) { unsafe { @@ -2200,6 +2387,29 @@ impl OwnedStr for ~str { } } + /// Reserves capacity for exactly `n` bytes in the given string, not including + /// the null terminator. + /// + /// Assuming single-byte characters, the resulting string will be large + /// enough to hold a string of length `n`. To account for the null terminator, + /// the underlying buffer will have the size `n` + 1. + /// + /// If the capacity for `s` is already equal to or greater than the requested + /// capacity, then no action is taken. + /// + /// # Arguments + /// + /// * s - A string + /// * n - The number of bytes to reserve space for + #[cfg(not(stage0))] + #[inline] + pub fn reserve(&mut self, n: uint) { + unsafe { + let v: &mut ~[u8] = cast::transmute(self); + (*v).reserve(n); + } + } + /// Reserves capacity for at least `n` bytes in the given string, not including /// the null terminator. /// @@ -2218,13 +2428,38 @@ impl OwnedStr for ~str { /// /// * s - A string /// * n - The number of bytes to reserve space for + #[cfg(stage0)] #[inline] fn reserve_at_least(&mut self, n: uint) { self.reserve(uint::next_power_of_two(n + 1u) - 1u) } + /// Reserves capacity for at least `n` bytes in the given string. + /// + /// Assuming single-byte characters, the resulting string will be large + /// enough to hold a string of length `n`. To account for the null terminator, + /// the underlying buffer will have the size `n` + 1. + /// + /// This function will over-allocate in order to amortize the allocation costs + /// in scenarios where the caller may need to repeatedly reserve additional + /// space. + /// + /// If the capacity for `s` is already equal to or greater than the requested + /// capacity, then no action is taken. + /// + /// # Arguments + /// + /// * s - A string + /// * n - The number of bytes to reserve space for + #[cfg(not(stage0))] + #[inline] + fn reserve_at_least(&mut self, n: uint) { + self.reserve(uint::next_power_of_two(n)) + } + /// Returns the number of single-byte characters the string can hold without /// reallocating + #[cfg(stage0)] fn capacity(&self) -> uint { let buf: &~[u8] = unsafe { cast::transmute(self) }; let vcap = buf.capacity(); @@ -2232,8 +2467,19 @@ impl OwnedStr for ~str { vcap - 1u } + /// Returns the number of single-byte characters the string can hold without + /// reallocating + #[cfg(not(stage0))] + fn capacity(&self) -> uint { + unsafe { + let buf: &~[u8] = cast::transmute(self); + buf.capacity() + } + } + /// Convert to a vector of bytes. This does not allocate a new /// string, and includes the null terminator. + #[cfg(stage0)] #[inline] fn to_bytes_with_null(self) -> ~[u8] { unsafe { cast::transmute(self) } @@ -2300,7 +2546,6 @@ impl Zero for @str { #[cfg(test)] mod tests { - use iterator::IteratorUtil; use container::Container; use option::Some; use libc::c_char; @@ -2922,71 +3167,11 @@ mod tests { } #[test] - fn test_unsafe_from_bytes_with_null() { - let a = [65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 0u8]; - let b = unsafe { raw::from_bytes_with_null(a) }; - assert_eq!(b, "AAAAAAA"); - } - - #[test] - fn test_from_bytes_with_null() { - let ss = "ศไทย中华Việt Nam"; - let bb = [0xe0_u8, 0xb8_u8, 0xa8_u8, - 0xe0_u8, 0xb9_u8, 0x84_u8, - 0xe0_u8, 0xb8_u8, 0x97_u8, - 0xe0_u8, 0xb8_u8, 0xa2_u8, - 0xe4_u8, 0xb8_u8, 0xad_u8, - 0xe5_u8, 0x8d_u8, 0x8e_u8, - 0x56_u8, 0x69_u8, 0xe1_u8, - 0xbb_u8, 0x87_u8, 0x74_u8, - 0x20_u8, 0x4e_u8, 0x61_u8, - 0x6d_u8, 0x0_u8]; - - assert_eq!(ss, from_bytes_with_null(bb)); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_from_bytes_with_null_fail() { - let bb = [0xff_u8, 0xb8_u8, 0xa8_u8, - 0xe0_u8, 0xb9_u8, 0x84_u8, - 0xe0_u8, 0xb8_u8, 0x97_u8, - 0xe0_u8, 0xb8_u8, 0xa2_u8, - 0xe4_u8, 0xb8_u8, 0xad_u8, - 0xe5_u8, 0x8d_u8, 0x8e_u8, - 0x56_u8, 0x69_u8, 0xe1_u8, - 0xbb_u8, 0x87_u8, 0x74_u8, - 0x20_u8, 0x4e_u8, 0x61_u8, - 0x6d_u8, 0x0_u8]; - - let _x = from_bytes_with_null(bb); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_from_bytes_with_null_fail_2() { - let bb = [0xff_u8, 0xb8_u8, 0xa8_u8, - 0xe0_u8, 0xb9_u8, 0x84_u8, - 0xe0_u8, 0xb8_u8, 0x97_u8, - 0xe0_u8, 0xb8_u8, 0xa2_u8, - 0xe4_u8, 0xb8_u8, 0xad_u8, - 0xe5_u8, 0x8d_u8, 0x8e_u8, - 0x56_u8, 0x69_u8, 0xe1_u8, - 0xbb_u8, 0x87_u8, 0x74_u8, - 0x20_u8, 0x4e_u8, 0x61_u8, - 0x6d_u8, 0x60_u8]; - - let _x = from_bytes_with_null(bb); - } - - #[test] - fn test_from_buf() { + fn test_raw_from_c_str() { unsafe { - let a = ~[65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 0u8]; + let a = ~[65, 65, 65, 65, 65, 65, 65, 0]; let b = vec::raw::to_ptr(a); - let c = raw::from_buf(b); + let c = raw::from_c_str(b); assert_eq!(c, ~"AAAAAAA"); } } @@ -3004,30 +3189,31 @@ mod tests { assert_eq!("ศไทย中华Việt Nam".as_bytes(), v); } + #[cfg(stage0)] #[test] - fn test_as_bytes_with_null() { - // has null - let v = [ - 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, - 184, 173, 229, 141, 142, 86, 105, 225, 187, 135, 116, 32, 78, 97, - 109, 0 - ]; - - let s1 = @""; - let s2 = @"abc"; - let s3 = @"ศไทย中华Việt Nam"; - assert_eq!(s1.as_bytes_with_null(), &[0]); - assert_eq!(s2.as_bytes_with_null(), &['a' as u8, 'b' as u8, 'c' as u8, 0]); - assert_eq!(s3.as_bytes_with_null(), v); + #[ignore(cfg(windows))] + #[should_fail] + fn test_as_bytes_fail() { + // Don't double free. (I'm not sure if this exercises the + // original problem code path anymore.) + let s = ~""; + let _bytes = s.as_bytes(); + fail!(); + } - let s1 = ~""; - let s2 = ~"abc"; - let s3 = ~"ศไทย中华Việt Nam"; - assert_eq!(s1.as_bytes_with_null(), &[0]); - assert_eq!(s2.as_bytes_with_null(), &['a' as u8, 'b' as u8, 'c' as u8, 0]); - assert_eq!(s3.as_bytes_with_null(), v); + #[cfg(stage0)] + #[test] + #[ignore(cfg(windows))] + #[should_fail] + fn test_as_bytes_fail() { + // Don't double free. (I'm not sure if this exercises the + // original problem code path anymore.) + let s = ~""; + let _bytes = s.as_bytes_with_null(); + fail!(); } + #[cfg(stage0)] #[test] fn test_to_bytes_with_null() { let s = ~"ศไทย中华Việt Nam"; @@ -3049,50 +3235,24 @@ mod tests { // Don't double free. (I'm not sure if this exercises the // original problem code path anymore.) let s = ~""; - let _bytes = s.as_bytes_with_null(); + let _bytes = s.as_bytes(); fail!(); } #[test] fn test_as_imm_buf() { - do "".as_imm_buf |buf, len| { - assert_eq!(len, 1); - unsafe { - assert_eq!(*ptr::offset(buf, 0), 0); - } + do "".as_imm_buf |_, len| { + assert_eq!(len, 0); } do "hello".as_imm_buf |buf, len| { - assert_eq!(len, 6); + assert_eq!(len, 5); unsafe { assert_eq!(*ptr::offset(buf, 0), 'h' as u8); assert_eq!(*ptr::offset(buf, 1), 'e' as u8); assert_eq!(*ptr::offset(buf, 2), 'l' as u8); assert_eq!(*ptr::offset(buf, 3), 'l' as u8); assert_eq!(*ptr::offset(buf, 4), 'o' as u8); - assert_eq!(*ptr::offset(buf, 5), 0); - } - } - } - - #[test] - fn test_as_c_str() { - let a = ~""; - do a.as_c_str |buf| { - unsafe { - assert_eq!(*ptr::offset(buf, 0), 0); - } - } - - let a = ~"hello"; - do a.as_c_str |buf| { - unsafe { - assert_eq!(*ptr::offset(buf, 0), 'h' as libc::c_char); - assert_eq!(*ptr::offset(buf, 1), 'e' as libc::c_char); - assert_eq!(*ptr::offset(buf, 2), 'l' as libc::c_char); - assert_eq!(*ptr::offset(buf, 3), 'l' as libc::c_char); - assert_eq!(*ptr::offset(buf, 4), 'o' as libc::c_char); - assert_eq!(*ptr::offset(buf, 5), 0); } } } @@ -3526,7 +3686,7 @@ mod tests { #[test] fn test_str_container() { fn sum_len<S: Container>(v: &[S]) -> uint { - v.iter().transform(|x| x.len()).sum() + v.iter().map(|x| x.len()).sum() } let s = ~"01234"; diff --git a/src/libstd/str/ascii.rs b/src/libstd/str/ascii.rs index 1be4d07dfa4..c6ae535c19a 100644 --- a/src/libstd/str/ascii.rs +++ b/src/libstd/str/ascii.rs @@ -17,8 +17,10 @@ use str::OwnedStr; use container::Container; use cast; use ptr; -use iterator::{Iterator, IteratorUtil}; -use vec::{CopyableVector, ImmutableVector, OwnedVector}; +use iterator::Iterator; +use vec::{CopyableVector, ImmutableVector}; +#[cfg(stage0)] +use vec::OwnedVector; use to_bytes::IterBytes; use option::{Some, None}; @@ -96,19 +98,26 @@ impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] { } } -impl<'self> AsciiCast<&'self[Ascii]> for &'self str { +impl<'self> AsciiCast<&'self [Ascii]> for &'self str { #[inline] - fn to_ascii(&self) -> &'self[Ascii] { + fn to_ascii(&self) -> &'self [Ascii] { assert!(self.is_ascii()); - unsafe {self.to_ascii_nocheck()} + unsafe { self.to_ascii_nocheck() } } + #[cfg(stage0)] #[inline] - unsafe fn to_ascii_nocheck(&self) -> &'self[Ascii] { + unsafe fn to_ascii_nocheck(&self) -> &'self [Ascii] { let (p,len): (*u8, uint) = cast::transmute(*self); cast::transmute((p, len - 1)) } + #[cfg(not(stage0))] + #[inline] + unsafe fn to_ascii_nocheck(&self) -> &'self [Ascii] { + cast::transmute(*self) + } + #[inline] fn is_ascii(&self) -> bool { self.byte_iter().all(|b| b.is_ascii()) @@ -181,12 +190,19 @@ impl OwnedAsciiCast for ~str { unsafe {self.into_ascii_nocheck()} } + #[cfg(stage0)] #[inline] unsafe fn into_ascii_nocheck(self) -> ~[Ascii] { let mut r: ~[Ascii] = cast::transmute(self); r.pop(); r } + + #[cfg(not(stage0))] + #[inline] + unsafe fn into_ascii_nocheck(self) -> ~[Ascii] { + cast::transmute(self) + } } /// Trait for converting an ascii type to a string. Needed to convert `&[Ascii]` to `~str` @@ -205,11 +221,19 @@ pub trait AsciiStr { } impl<'self> AsciiStr for &'self [Ascii] { + #[cfg(stage0)] #[inline] fn to_str_ascii(&self) -> ~str { let mut cpy = self.to_owned(); cpy.push(0u8.to_ascii()); - unsafe {cast::transmute(cpy)} + unsafe { cast::transmute(cpy) } + } + + #[cfg(not(stage0))] + #[inline] + fn to_str_ascii(&self) -> ~str { + let cpy = self.to_owned(); + unsafe { cast::transmute(cpy) } } #[inline] @@ -229,11 +253,18 @@ impl<'self> AsciiStr for &'self [Ascii] { } impl ToStrConsume for ~[Ascii] { + #[cfg(stage0)] #[inline] fn into_str(self) -> ~str { let mut cpy = self; cpy.push(0u8.to_ascii()); - unsafe {cast::transmute(cpy)} + unsafe { cast::transmute(cpy) } + } + + #[cfg(not(stage0))] + #[inline] + fn into_str(self) -> ~str { + unsafe { cast::transmute(self) } } } @@ -252,7 +283,7 @@ pub trait ToBytesConsume { impl ToBytesConsume for ~[Ascii] { fn into_bytes(self) -> ~[u8] { - unsafe {cast::transmute(self)} + unsafe { cast::transmute(self) } } } @@ -274,7 +305,7 @@ pub fn to_ascii_lower(string: &str) -> ~str { } #[inline] -priv fn map_bytes(string: &str, map: &'static [u8]) -> ~str { +fn map_bytes(string: &str, map: &'static [u8]) -> ~str { let len = string.len(); let mut result = str::with_capacity(len); unsafe { @@ -298,7 +329,7 @@ pub fn eq_ignore_ascii_case(a: &str, b: &str) -> bool { |(byte_a, byte_b)| ASCII_LOWER_MAP[*byte_a] == ASCII_LOWER_MAP[*byte_b]) } -priv static ASCII_LOWER_MAP: &'static [u8] = &[ +static ASCII_LOWER_MAP: &'static [u8] = &[ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, @@ -333,7 +364,7 @@ priv static ASCII_LOWER_MAP: &'static [u8] = &[ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, ]; -priv static ASCII_UPPER_MAP: &'static [u8] = &[ +static ASCII_UPPER_MAP: &'static [u8] = &[ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs index 9d853087123..03e6412fcb8 100644 --- a/src/libstd/sys.rs +++ b/src/libstd/sys.rs @@ -12,24 +12,15 @@ #[allow(missing_doc)]; +use c_str::ToCStr; use cast; use io; use libc; use libc::{c_char, size_t}; use repr; -use str::StrSlice; use str; use unstable::intrinsics; -pub mod rustrt { - use libc::{c_char, size_t}; - - extern { - #[rust_stack] - pub fn rust_upcall_fail(expr: *c_char, file: *c_char, line: size_t); - } -} - /// Returns the size of a type #[inline] pub fn size_of<T>() -> uint { @@ -114,8 +105,8 @@ pub trait FailWithCause { impl FailWithCause for ~str { fn fail_with(cause: ~str, file: &'static str, line: uint) -> ! { - do cause.as_c_str |msg_buf| { - do file.as_c_str |file_buf| { + do cause.to_c_str().with_ref |msg_buf| { + do file.to_c_str().with_ref |file_buf| { begin_unwind_(msg_buf, file_buf, line as libc::size_t) } } @@ -124,8 +115,8 @@ impl FailWithCause for ~str { impl FailWithCause for &'static str { fn fail_with(cause: &'static str, file: &'static str, line: uint) -> ! { - do cause.as_c_str |msg_buf| { - do file.as_c_str |file_buf| { + do cause.to_c_str().with_ref |msg_buf| { + do file.to_c_str().with_ref |file_buf| { begin_unwind_(msg_buf, file_buf, line as libc::size_t) } } @@ -136,55 +127,44 @@ impl FailWithCause for &'static str { pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { use either::Left; use option::{Some, None}; - use rt::{context, OldTaskContext, TaskContext}; + use rt::in_green_task_context; use rt::task::Task; use rt::local::Local; use rt::logging::Logger; use str::Str; - let context = context(); - match context { - OldTaskContext => { - unsafe { - rustrt::rust_upcall_fail(msg, file, line); - cast::transmute(()) + unsafe { + // XXX: Bad re-allocations. fail! needs some refactoring + let msg = str::raw::from_c_str(msg); + let file = str::raw::from_c_str(file); + + // XXX: Logging doesn't work correctly in non-task context because it + // invokes the local heap + if in_green_task_context() { + // XXX: Logging doesn't work here - the check to call the log + // function never passes - so calling the log function directly. + do Local::borrow::<Task, ()> |task| { + let msg = match task.name { + Some(ref name) => + fmt!("task '%s' failed at '%s', %s:%i", + name.as_slice(), msg, file, line as int), + None => + fmt!("task <unnamed> failed at '%s', %s:%i", + msg, file, line as int) + }; + + task.logger.log(Left(msg)); } + } else { + rterrln!("failed in non-task context at '%s', %s:%i", + msg, file, line as int); } - _ => { - unsafe { - // XXX: Bad re-allocations. fail! needs some refactoring - let msg = str::raw::from_c_str(msg); - let file = str::raw::from_c_str(file); - - // XXX: Logging doesn't work correctly in non-task context because it - // invokes the local heap - if context == TaskContext { - // XXX: Logging doesn't work here - the check to call the log - // function never passes - so calling the log function directly. - do Local::borrow::<Task, ()> |task| { - let msg = match task.name { - Some(ref name) => - fmt!("task '%s' failed at '%s', %s:%i", - name.as_slice(), msg, file, line as int), - None => - fmt!("task <unnamed> failed at '%s', %s:%i", - msg, file, line as int) - }; - - task.logger.log(Left(msg)); - } - } else { - rterrln!("failed in non-task context at '%s', %s:%i", - msg, file, line as int); - } - - let task = Local::unsafe_borrow::<Task>(); - if (*task).unwinder.unwinding { - rtabort!("unwinding again"); - } - (*task).unwinder.begin_unwind(); - } + + let task = Local::unsafe_borrow::<Task>(); + if (*task).unwinder.unwinding { + rtabort!("unwinding again"); } + (*task).unwinder.begin_unwind(); } } diff --git a/src/libstd/task/local_data_priv.rs b/src/libstd/task/local_data_priv.rs index 95d3cbaf89b..3a11dee3138 100644 --- a/src/libstd/task/local_data_priv.rs +++ b/src/libstd/task/local_data_priv.rs @@ -15,32 +15,21 @@ use libc; use local_data; use prelude::*; use ptr; -use task::rt; use unstable::raw; use util; -use super::rt::rust_task; use rt::task::{Task, LocalStorage}; pub enum Handle { - OldHandle(*rust_task), NewHandle(*mut LocalStorage) } impl Handle { pub fn new() -> Handle { - use rt::{context, OldTaskContext}; use rt::local::Local; unsafe { - match context() { - OldTaskContext => { - OldHandle(rt::rust_get_task()) - } - _ => { - let task = Local::unsafe_borrow::<Task>(); - NewHandle(&mut (*task).storage) - } - } + let task = Local::unsafe_borrow::<Task>(); + NewHandle(&mut (*task).storage) } } } @@ -109,26 +98,6 @@ fn cleanup_task_local_map(map_ptr: *libc::c_void) { // Gets the map from the runtime. Lazily initialises if not done so already. unsafe fn get_local_map(handle: Handle) -> &mut TaskLocalMap { - unsafe fn oldsched_map(task: *rust_task) -> &mut TaskLocalMap { - extern fn cleanup_extern_cb(map_ptr: *libc::c_void) { - cleanup_task_local_map(map_ptr); - } - - // Relies on the runtime initialising the pointer to null. - // Note: the map is an owned pointer and is "owned" by TLS. It is moved - // into the tls slot for this task, and then mutable loans are taken - // from this slot to modify the map. - let map_ptr = rt::rust_get_task_local_data(task); - if (*map_ptr).is_null() { - // First time TLS is used, create a new map and set up the necessary - // TLS information for its safe destruction - let map: TaskLocalMap = ~[]; - *map_ptr = cast::transmute(map); - rt::rust_task_local_data_atexit(task, cleanup_extern_cb); - } - return cast::transmute(map_ptr); - } - unsafe fn newsched_map(local: *mut LocalStorage) -> &mut TaskLocalMap { // This is based on the same idea as the oldsched code above. match &mut *local { @@ -152,7 +121,6 @@ unsafe fn get_local_map(handle: Handle) -> &mut TaskLocalMap { } match handle { - OldHandle(task) => oldsched_map(task), NewHandle(local_storage) => newsched_map(local_storage) } } diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs index 2e0c9c1d1ad..09431c05e22 100644 --- a/src/libstd/task/mod.rs +++ b/src/libstd/task/mod.rs @@ -42,7 +42,7 @@ use cmp::Eq; use comm::{stream, Chan, GenericChan, GenericPort, Port}; use result::Result; use result; -use rt::{context, OldTaskContext, TaskContext}; +use rt::in_green_task_context; use rt::local::Local; use unstable::finally::Finally; use util; @@ -54,7 +54,6 @@ use util; #[cfg(test)] use task; mod local_data_priv; -pub mod rt; pub mod spawn; /** @@ -527,42 +526,29 @@ pub fn try<T:Send>(f: ~fn() -> T) -> Result<T,()> { pub fn with_task_name<U>(blk: &fn(Option<&str>) -> U) -> U { use rt::task::Task; - match context() { - TaskContext => do Local::borrow::<Task, U> |task| { + if in_green_task_context() { + do Local::borrow::<Task, U> |task| { match task.name { Some(ref name) => blk(Some(name.as_slice())), None => blk(None) } - }, - _ => fail!("no task name exists in %?", context()), + } + } else { + fail!("no task name exists in non-green task context") } } pub fn yield() { //! Yield control to the task scheduler - use rt::{context, OldTaskContext}; use rt::local::Local; use rt::sched::Scheduler; - unsafe { - match context() { - OldTaskContext => { - let task_ = rt::rust_get_task(); - let killed = rt::rust_task_yield(task_); - if killed && !failing() { - fail!("killed"); - } - } - _ => { - // XXX: What does yield really mean in newsched? - // FIXME(#7544): Optimize this, since we know we won't block. - let sched = Local::take::<Scheduler>(); - do sched.deschedule_running_task_and_then |sched, task| { - sched.enqueue_blocked_task(task); - } - } - } + // XXX: What does yield really mean in newsched? + // FIXME(#7544): Optimize this, since we know we won't block. + let sched = Local::take::<Scheduler>(); + do sched.deschedule_running_task_and_then |sched, task| { + sched.enqueue_blocked_task(task); } } @@ -571,17 +557,8 @@ pub fn failing() -> bool { use rt::task::Task; - match context() { - OldTaskContext => { - unsafe { - rt::rust_task_is_unwinding(rt::rust_get_task()) - } - } - _ => { - do Local::borrow::<Task, bool> |local| { - local.unwinder.unwinding - } - } + do Local::borrow::<Task, bool> |local| { + local.unwinder.unwinding } } @@ -604,29 +581,19 @@ pub fn unkillable<U>(f: &fn() -> U) -> U { use rt::task::Task; unsafe { - match context() { - OldTaskContext => { - let t = rt::rust_get_task(); - do (|| { - rt::rust_task_inhibit_kill(t); - f() - }).finally { - rt::rust_task_allow_kill(t); - } - } - TaskContext => { - // The inhibits/allows might fail and need to borrow the task. - let t = Local::unsafe_borrow::<Task>(); - do (|| { - (*t).death.inhibit_kill((*t).unwinder.unwinding); - f() - }).finally { - (*t).death.allow_kill((*t).unwinder.unwinding); - } + if in_green_task_context() { + // The inhibits/allows might fail and need to borrow the task. + let t = Local::unsafe_borrow::<Task>(); + do (|| { + (*t).death.inhibit_kill((*t).unwinder.unwinding); + f() + }).finally { + (*t).death.allow_kill((*t).unwinder.unwinding); } + } else { // FIXME(#3095): This should be an rtabort as soon as the scheduler // no longer uses a workqueue implemented with an Exclusive. - _ => f() + f() } } } @@ -635,27 +602,17 @@ pub fn unkillable<U>(f: &fn() -> U) -> U { pub unsafe fn rekillable<U>(f: &fn() -> U) -> U { use rt::task::Task; - match context() { - OldTaskContext => { - let t = rt::rust_get_task(); - do (|| { - rt::rust_task_allow_kill(t); - f() - }).finally { - rt::rust_task_inhibit_kill(t); - } - } - TaskContext => { - let t = Local::unsafe_borrow::<Task>(); - do (|| { - (*t).death.allow_kill((*t).unwinder.unwinding); - f() - }).finally { - (*t).death.inhibit_kill((*t).unwinder.unwinding); - } + if in_green_task_context() { + let t = Local::unsafe_borrow::<Task>(); + do (|| { + (*t).death.allow_kill((*t).unwinder.unwinding); + f() + }).finally { + (*t).death.inhibit_kill((*t).unwinder.unwinding); } + } else { // FIXME(#3095): As in unkillable(). - _ => f() + f() } } @@ -1033,14 +990,8 @@ fn test_try_fail() { #[cfg(test)] fn get_sched_id() -> int { - if context() == OldTaskContext { - unsafe { - rt::rust_get_sched_id() as int - } - } else { - do Local::borrow::<::rt::sched::Scheduler, int> |sched| { - sched.sched_id() as int - } + do Local::borrow::<::rt::sched::Scheduler, int> |sched| { + sched.sched_id() as int } } diff --git a/src/libstd/task/rt.rs b/src/libstd/task/rt.rs deleted file mode 100644 index 13c51230dc2..00000000000 --- a/src/libstd/task/rt.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -The task interface to the runtime - -*/ - -#[doc(hidden)]; - -use libc; - -#[allow(non_camel_case_types)] // runtime type -pub type sched_id = int; -#[allow(non_camel_case_types)] // runtime type -pub type task_id = int; - -// These are both opaque runtime/compiler types that we don't know the -// structure of and should only deal with via unsafe pointer -#[allow(non_camel_case_types)] // runtime type -pub type rust_task = libc::c_void; -#[allow(non_camel_case_types)] // runtime type -pub type rust_closure = libc::c_void; - -extern { - #[rust_stack] - pub fn rust_task_yield(task: *rust_task) -> bool; - - pub fn rust_get_sched_id() -> sched_id; - pub fn rust_new_sched(num_threads: libc::uintptr_t) -> sched_id; - - pub fn get_task_id() -> task_id; - #[rust_stack] - pub fn rust_get_task() -> *rust_task; - - pub fn new_task() -> *rust_task; - pub fn rust_new_task_in_sched(id: sched_id) -> *rust_task; - - pub fn start_task(task: *rust_task, closure: *rust_closure); - - pub fn rust_task_is_unwinding(task: *rust_task) -> bool; - pub fn rust_osmain_sched_id() -> sched_id; - #[rust_stack] - pub fn rust_task_inhibit_kill(t: *rust_task); - #[rust_stack] - pub fn rust_task_allow_kill(t: *rust_task); - #[rust_stack] - pub fn rust_task_inhibit_yield(t: *rust_task); - #[rust_stack] - pub fn rust_task_allow_yield(t: *rust_task); - pub fn rust_task_kill_other(task: *rust_task); - pub fn rust_task_kill_all(task: *rust_task); - - #[rust_stack] - pub fn rust_get_task_local_data(task: *rust_task) -> *mut *libc::c_void; - #[rust_stack] - pub fn rust_task_local_data_atexit(task: *rust_task, cleanup_fn: *u8); -} diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 2d0a2d98e9f..10bac9325ab 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -79,11 +79,8 @@ use cast; use cell::Cell; use container::MutableMap; use comm::{Chan, GenericChan, oneshot}; -use hashmap::{HashSet, HashSetConsumeIterator}; +use hashmap::{HashSet, HashSetMoveIterator}; use local_data; -use task::local_data_priv::{local_get, local_set, OldHandle}; -use task::rt::rust_task; -use task::rt; use task::{Failure, SingleThreaded}; use task::{Success, TaskOpts, TaskResult}; use task::unkillable; @@ -91,13 +88,14 @@ use to_bytes::IterBytes; use uint; use util; use unstable::sync::Exclusive; -use rt::{OldTaskContext, TaskContext, SchedulerContext, GlobalContext, context}; +use rt::in_green_task_context; use rt::local::Local; use rt::task::{Task, Sched}; use rt::kill::KillHandle; use rt::sched::Scheduler; use rt::uv::uvio::UvEventLoop; use rt::thread::Thread; +use rt::work_queue::WorkQueue; #[cfg(test)] use task::default_task_opts; #[cfg(test)] use comm; @@ -106,14 +104,12 @@ use rt::thread::Thread; // Transitionary. #[deriving(Eq)] enum TaskHandle { - OldTask(*rust_task), NewTask(KillHandle), } impl Clone for TaskHandle { fn clone(&self) -> TaskHandle { match *self { - OldTask(x) => OldTask(x), NewTask(ref x) => NewTask(x.clone()), } } @@ -122,7 +118,6 @@ impl Clone for TaskHandle { impl IterBytes for TaskHandle { fn iter_bytes(&self, lsb0: bool, f: &fn(buf: &[u8]) -> bool) -> bool { match *self { - OldTask(ref x) => x.iter_bytes(lsb0, f), NewTask(ref x) => x.iter_bytes(lsb0, f), } } @@ -146,8 +141,8 @@ impl TaskSet { assert!(was_present); } #[inline] - fn consume(self) -> HashSetConsumeIterator<TaskHandle> { - (*self).consume() + fn move_iter(self) -> HashSetMoveIterator<TaskHandle> { + (*self).move_iter() } } @@ -465,13 +460,13 @@ fn kill_taskgroup(state: TaskGroupInner, me: &TaskHandle, is_main: bool) { if newstate.is_some() { let TaskGroupData { members: members, descendants: descendants } = newstate.unwrap(); - for sibling in members.consume() { + for sibling in members.move_iter() { // Skip self - killing ourself won't do much good. if &sibling != me { RuntimeGlue::kill_task(sibling); } } - for child in descendants.consume() { + for child in descendants.move_iter() { assert!(&child != me); RuntimeGlue::kill_task(child); } @@ -497,7 +492,6 @@ struct RuntimeGlue; impl RuntimeGlue { unsafe fn kill_task(task: TaskHandle) { match task { - OldTask(ptr) => rt::rust_task_kill_other(ptr), NewTask(handle) => { let mut handle = handle; do handle.kill().map_move |killed_task| { @@ -512,7 +506,6 @@ impl RuntimeGlue { unsafe fn kill_all_tasks(task: &TaskHandle) { match *task { - OldTask(ptr) => rt::rust_task_kill_all(ptr), // FIXME(#7544): Remove the kill_all feature entirely once the // oldsched goes away. NewTask(ref _handle) => rtabort!("can't kill_all in newsched"), @@ -520,12 +513,8 @@ impl RuntimeGlue { } fn with_task_handle_and_failing(blk: &fn(TaskHandle, bool)) { - match context() { - OldTaskContext => unsafe { - let me = rt::rust_get_task(); - blk(OldTask(me), rt::rust_task_is_unwinding(me)) - }, - TaskContext => unsafe { + if in_green_task_context() { + unsafe { // Can't use safe borrow, because the taskgroup destructor needs to // access the scheduler again to send kill signals to other tasks. let me = Local::unsafe_borrow::<Task>(); @@ -533,36 +522,15 @@ impl RuntimeGlue { // Will probably have to wait until the old rt is gone. blk(NewTask((*me).death.kill_handle.get_ref().clone()), (*me).unwinder.unwinding) - }, - SchedulerContext | GlobalContext => rtabort!("task dying in bad context"), + } + } else { + rtabort!("task dying in bad context") } } fn with_my_taskgroup<U>(blk: &fn(&Taskgroup) -> U) -> U { - match context() { - OldTaskContext => unsafe { - let me = rt::rust_get_task(); - do local_get(OldHandle(me), taskgroup_key()) |g| { - match g { - None => { - // Main task, doing first spawn ever. Lazily initialise here. - let mut members = TaskSet::new(); - members.insert(OldTask(me)); - let tasks = Exclusive::new(Some(TaskGroupData { - members: members, - descendants: TaskSet::new(), - })); - // Main task/group has no ancestors, no notifier, etc. - let group = @@mut Taskgroup(tasks, AncestorList(None), - true, None); - local_set(OldHandle(me), taskgroup_key(), group); - blk(&**group) - } - Some(&group) => blk(&**group) - } - } - }, - TaskContext => unsafe { + if in_green_task_context() { + unsafe { // Can't use safe borrow, because creating new hashmaps for the // tasksets requires an rng, which needs to borrow the sched. let me = Local::unsafe_borrow::<Task>(); @@ -586,8 +554,9 @@ impl RuntimeGlue { } Some(ref group) => group, }) - }, - SchedulerContext | GlobalContext => rtabort!("spawning in bad context"), + } + } else { + rtabort!("spawning in bad context") } } } @@ -597,7 +566,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) -> Option<(TaskGroupArc, AncestorList, bool)> { // FIXME(#7544): Not safe to lazily initialize in the old runtime. Remove // this context check once 'spawn_raw_oldsched' is gone. - if context() == OldTaskContext || linked || supervised { + if linked || supervised { // with_my_taskgroup will lazily initialize the parent's taskgroup if // it doesn't yet exist. We don't want to call it in the unlinked case. do RuntimeGlue::with_my_taskgroup |spawner_group| { @@ -664,11 +633,10 @@ fn enlist_many(child: TaskHandle, child_arc: &TaskGroupArc, } pub fn spawn_raw(opts: TaskOpts, f: ~fn()) { - match context() { - OldTaskContext => spawn_raw_oldsched(opts, f), - TaskContext => spawn_raw_newsched(opts, f), - SchedulerContext => fail!("can't spawn from scheduler context"), - GlobalContext => fail!("can't spawn from global context"), + if in_green_task_context() { + spawn_raw_newsched(opts, f) + } else { + fail!("can't spawn from this context") } } @@ -722,10 +690,16 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { let sched = Local::unsafe_borrow::<Scheduler>(); let sched_handle = (*sched).make_handle(); + // Since this is a 1:1 scheduler we create a queue not in + // the stealee set. The run_anything flag is set false + // which will disable stealing. + let work_queue = WorkQueue::new(); + // Create a new scheduler to hold the new task let new_loop = ~UvEventLoop::new(); let mut new_sched = ~Scheduler::new_special(new_loop, - (*sched).work_queue.clone(), + work_queue, + (*sched).work_queues.clone(), (*sched).sleeper_list.clone(), false, Some(sched_handle)); @@ -804,85 +778,6 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { } -fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) { - - let (child_tg, ancestors, is_main) = - gen_child_taskgroup(opts.linked, opts.supervised).expect("old runtime needs TG"); - - unsafe { - let child_data = Cell::new((child_tg, ancestors, f)); - // Being killed with the unsafe task/closure pointers would leak them. - do unkillable { - let (child_tg, ancestors, f) = child_data.take(); // :( - // Create child task. - let new_task = match opts.sched.mode { - DefaultScheduler => rt::new_task(), - _ => new_task_in_sched() - }; - assert!(!new_task.is_null()); - // Getting killed after here would leak the task. - let child_wrapper = make_child_wrapper(new_task, child_tg, - ancestors, is_main, opts.notify_chan.take(), f); - - let closure = cast::transmute(&child_wrapper); - - // Getting killed between these two calls would free the child's - // closure. (Reordering them wouldn't help - then getting killed - // between them would leak.) - rt::start_task(new_task, closure); - cast::forget(child_wrapper); - } - } - - // This function returns a closure-wrapper that we pass to the child task. - // (1) It sets up the notification channel. - // (2) It attempts to enlist in the child's group and all ancestor groups. - // (3a) If any of those fails, it leaves all groups, and does nothing. - // (3b) Otherwise it builds a task control structure and puts it in TLS, - // (4) ...and runs the provided body function. - fn make_child_wrapper(child: *rust_task, child_arc: TaskGroupArc, - ancestors: AncestorList, is_main: bool, - notify_chan: Option<Chan<TaskResult>>, - f: ~fn()) - -> ~fn() { - let child_data = Cell::new((notify_chan, child_arc, ancestors)); - let result: ~fn() = || { - let (notify_chan, child_arc, ancestors) = child_data.take(); // :( - let mut ancestors = ancestors; - // Child task runs this code. - - // Even if the below code fails to kick the child off, we must - // send Something on the notify channel. - - let notifier = notify_chan.map_move(|c| AutoNotify(c)); - - if enlist_many(OldTask(child), &child_arc, &mut ancestors) { - let group = @@mut Taskgroup(child_arc, ancestors, is_main, notifier); - unsafe { - local_set(OldHandle(child), taskgroup_key(), group); - } - - // Run the child's body. - f(); - - // TLS cleanup code will exit the taskgroup. - } - - // Run the box annihilator. - // FIXME #4428: Crashy. - // unsafe { cleanup::annihilate(); } - }; - return result; - } - - fn new_task_in_sched() -> *rust_task { - unsafe { - let sched_id = rt::rust_new_sched(1); - rt::rust_new_task_in_sched(sched_id) - } - } -} - #[test] fn test_spawn_raw_simple() { let (po, ch) = stream(); diff --git a/src/libstd/to_bytes.rs b/src/libstd/to_bytes.rs index 5ad7969c8d2..f871f4ef6d6 100644 --- a/src/libstd/to_bytes.rs +++ b/src/libstd/to_bytes.rs @@ -17,7 +17,7 @@ The `ToBytes` and `IterBytes` traits use cast; use io; use io::Writer; -use iterator::IteratorUtil; +use iterator::Iterator; use option::{None, Option, Some}; use str::StrSlice; use vec::ImmutableVector; diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index 6f61d29780f..da1fb9abaee 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -11,7 +11,7 @@ //! An ordered map and set for integer keys implemented as a radix trie use prelude::*; -use iterator::{IteratorUtil, FromIterator, Extendable}; +use iterator::{FromIterator, Extendable}; use uint; use util::{swap, replace}; use vec; @@ -156,6 +156,53 @@ impl<T> TrieMap<T> { remaining_max: self.length } } + + // If `upper` is true then returns upper_bound else returns lower_bound. + #[inline] + fn bound_iter<'a>(&'a self, key: uint, upper: bool) -> TrieMapIterator<'a, T> { + let mut node: &'a TrieNode<T> = &self.root; + let mut idx = 0; + let mut it = TrieMapIterator { + stack: ~[], + remaining_min: 0, + remaining_max: self.length + }; + loop { + let children = &node.children; + let child_id = chunk(key, idx); + match children[child_id] { + Internal(ref n) => { + node = &**n; + it.stack.push(children.slice_from(child_id + 1).iter()); + } + External(stored, _) => { + if stored < key || (upper && stored == key) { + it.stack.push(children.slice_from(child_id + 1).iter()); + } else { + it.stack.push(children.slice_from(child_id).iter()); + } + return it; + } + Nothing => { + it.stack.push(children.slice_from(child_id + 1).iter()); + return it + } + } + idx += 1; + } + } + + /// Get an iterator pointing to the first key-value pair whose key is not less than `key`. + /// If all keys in the map are less than `key` an empty iterator is returned. + pub fn lower_bound_iter<'a>(&'a self, key: uint) -> TrieMapIterator<'a, T> { + self.bound_iter(key, false) + } + + /// Get an iterator pointing to the first key-value pair whose key is greater than `key`. + /// If all keys in the map are not greater than `key` an empty iterator is returned. + pub fn upper_bound_iter<'a>(&'a self, key: uint) -> TrieMapIterator<'a, T> { + self.bound_iter(key, true) + } } impl<T, Iter: Iterator<(uint, T)>> FromIterator<(uint, T), Iter> for TrieMap<T> { @@ -233,6 +280,18 @@ impl TrieSet { pub fn iter<'a>(&'a self) -> TrieSetIterator<'a> { TrieSetIterator{iter: self.map.iter()} } + + /// Get an iterator pointing to the first value that is not less than `val`. + /// If all values in the set are less than `val` an empty iterator is returned. + pub fn lower_bound_iter<'a>(&'a self, val: uint) -> TrieSetIterator<'a> { + TrieSetIterator{iter: self.map.lower_bound_iter(val)} + } + + /// Get an iterator pointing to the first value that key is greater than `val`. + /// If all values in the set are not greater than `val` an empty iterator is returned. + pub fn upper_bound_iter<'a>(&'a self, val: uint) -> TrieSetIterator<'a> { + TrieSetIterator{iter: self.map.upper_bound_iter(val)} + } } impl<Iter: Iterator<uint>> FromIterator<uint, Iter> for TrieSet { @@ -271,8 +330,8 @@ impl<T> TrieNode<T> { impl<T> TrieNode<T> { fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { - for idx in range(0u, self.children.len()) { - match self.children[idx] { + for elt in self.children.iter() { + match *elt { Internal(ref x) => if !x.each(|i,t| f(i,t)) { return false }, External(k, ref v) => if !f(&k, v) { return false }, Nothing => () @@ -282,13 +341,14 @@ impl<T> TrieNode<T> { } fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { - do uint::range_rev(self.children.len(), 0) |idx| { - match self.children[idx] { - Internal(ref x) => x.each_reverse(|i,t| f(i,t)), - External(k, ref v) => f(&k, v), - Nothing => true + for elt in self.children.rev_iter() { + match *elt { + Internal(ref x) => if !x.each_reverse(|i,t| f(i,t)) { return false }, + External(k, ref v) => if !f(&k, v) { return false }, + Nothing => () } } + true } fn mutate_values<'a>(&'a mut self, f: &fn(&uint, &mut T) -> bool) -> bool { @@ -539,10 +599,9 @@ mod test_map { fn test_each_break() { let mut m = TrieMap::new(); - do uint::range_rev(uint::max_value, uint::max_value - 10000) |x| { + for x in range(uint::max_value - 10000, uint::max_value).invert() { m.insert(x, x / 2); - true - }; + } let mut n = uint::max_value - 10000; do m.each |k, v| { @@ -580,10 +639,9 @@ mod test_map { fn test_each_reverse_break() { let mut m = TrieMap::new(); - do uint::range_rev(uint::max_value, uint::max_value - 10000) |x| { + for x in range(uint::max_value - 10000, uint::max_value).invert() { m.insert(x, x / 2); - true - }; + } let mut n = uint::max_value - 1; do m.each_reverse |k, v| { @@ -618,7 +676,7 @@ mod test_map { fn test_from_iter() { let xs = ~[(1u, 1i), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - let map: TrieMap<int> = xs.iter().transform(|&x| x).collect(); + let map: TrieMap<int> = xs.iter().map(|&x| x).collect(); for &(k, v) in xs.iter() { assert_eq!(map.find(&k), Some(&v)); @@ -634,10 +692,9 @@ mod test_map { let last = uint::max_value; let mut map = TrieMap::new(); - do uint::range_rev(last, first) |x| { + for x in range(first, last).invert() { map.insert(x, x / 2); - true - }; + } let mut i = 0; for (k, &v) in map.iter() { @@ -647,6 +704,49 @@ mod test_map { } assert_eq!(i, last - first); } + + #[test] + fn test_bound_iter() { + let empty_map : TrieMap<uint> = TrieMap::new(); + assert_eq!(empty_map.lower_bound_iter(0).next(), None); + assert_eq!(empty_map.upper_bound_iter(0).next(), None); + + let last = 999u; + let step = 3u; + let value = 42u; + + let mut map : TrieMap<uint> = TrieMap::new(); + do uint::range_step(0u, last, step as int) |x| { + assert!(x % step == 0); + map.insert(x, value); + true + }; + + for i in range(0u, last - step) { + let mut lb = map.lower_bound_iter(i); + let mut ub = map.upper_bound_iter(i); + let next_key = i - i % step + step; + let next_pair = (next_key, &value); + if (i % step == 0) { + assert_eq!(lb.next(), Some((i, &value))); + } else { + assert_eq!(lb.next(), Some(next_pair)); + } + assert_eq!(ub.next(), Some(next_pair)); + } + + let mut lb = map.lower_bound_iter(last - step); + assert_eq!(lb.next(), Some((last - step, &value))); + let mut ub = map.upper_bound_iter(last - step); + assert_eq!(ub.next(), None); + + for i in range(last - step + 1, last) { + let mut lb = map.lower_bound_iter(i); + assert_eq!(lb.next(), None); + let mut ub = map.upper_bound_iter(i); + assert_eq!(ub.next(), None); + } + } } #[cfg(test)] @@ -682,7 +782,7 @@ mod test_set { fn test_from_iter() { let xs = ~[9u, 8, 7, 6, 5, 4, 3, 2, 1]; - let set: TrieSet = xs.iter().transform(|&x| x).collect(); + let set: TrieSet = xs.iter().map(|&x| x).collect(); for x in xs.iter() { assert!(set.contains(x)); diff --git a/src/libstd/tuple.rs b/src/libstd/tuple.rs index 41af29022a6..80d1626c084 100644 --- a/src/libstd/tuple.rs +++ b/src/libstd/tuple.rs @@ -15,7 +15,7 @@ use clone::Clone; use vec; use vec::ImmutableVector; -use iterator::IteratorUtil; +use iterator::Iterator; pub use self::inner::*; @@ -102,7 +102,7 @@ impl<'self, fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C] { match *self { (ref a, ref b) => { - a.iter().zip(b.iter()).transform(|(aa, bb)| f(aa, bb)).collect() + a.iter().zip(b.iter()).map(|(aa, bb)| f(aa, bb)).collect() } } } @@ -122,7 +122,7 @@ impl<A:Clone, B:Clone> ExtendedTupleOps<A,B> for (~[A], ~[B]) { fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C] { match *self { (ref a, ref b) => { - a.iter().zip(b.iter()).transform(|(aa, bb)| f(aa, bb)).collect() + a.iter().zip(b.iter()).map(|(aa, bb)| f(aa, bb)).collect() } } } diff --git a/src/libstd/unstable/dynamic_lib.rs b/src/libstd/unstable/dynamic_lib.rs index 8d5654255f1..49e3e0777df 100644 --- a/src/libstd/unstable/dynamic_lib.rs +++ b/src/libstd/unstable/dynamic_lib.rs @@ -15,6 +15,7 @@ Dynamic library facilities. A simple wrapper over the platforms dynamic library facilities */ +use c_str::ToCStr; use cast; use path; use libc; @@ -65,7 +66,7 @@ impl DynamicLibrary { // T but that feature is still unimplemented let maybe_symbol_value = do dl::check_for_errors_in { - do symbol.as_c_str |raw_string| { + do symbol.to_c_str().with_ref |raw_string| { dl::symbol(self.handle, raw_string) } }; @@ -135,6 +136,7 @@ mod test { #[cfg(target_os = "macos")] #[cfg(target_os = "freebsd")] mod dl { + use c_str::ToCStr; use libc; use path; use ptr; @@ -143,7 +145,7 @@ mod dl { use result::*; pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void { - do filename.to_str().as_c_str |raw_name| { + do filename.to_c_str().with_ref |raw_name| { dlopen(raw_name, Lazy as libc::c_int) } } diff --git a/src/libstd/unstable/extfmt.rs b/src/libstd/unstable/extfmt.rs index 7b05515f74a..7b1f0e8ced8 100644 --- a/src/libstd/unstable/extfmt.rs +++ b/src/libstd/unstable/extfmt.rs @@ -526,7 +526,7 @@ pub mod rt { TyHexLower => uint_to_str_prec(u, 16, prec), // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use - // to_ascii_consume and to_str_consume to not do a unnecessary copy. + // to_ascii_move and to_str_move to not do a unnecessary copy. TyHexUpper => { let s = uint_to_str_prec(u, 16, prec); s.to_ascii().to_upper().to_str_ascii() @@ -549,12 +549,14 @@ pub mod rt { // For strings, precision is the maximum characters // displayed let unpadded = match cv.precision { - CountImplied => s, - CountIs(max) => if (max as uint) < s.char_len() { - s.slice(0, max as uint) - } else { - s - } + CountImplied => s, + CountIs(max) => { + if (max as uint) < s.char_len() { + s.slice(0, max as uint) + } else { + s + } + } }; pad(cv, unpadded, None, PadNozero, buf); } diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index 98c0fe254b6..9e7ac1fd7db 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -10,35 +10,15 @@ //! Runtime calls emitted by the compiler. +use c_str::ToCStr; use cast::transmute; -use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int}; +use libc::{c_char, c_uchar, c_void, size_t, uintptr_t}; use str; use sys; -use rt::{context, OldTaskContext}; use rt::task::Task; use rt::local::Local; use rt::borrowck; -#[allow(non_camel_case_types)] -pub type rust_task = c_void; - -pub mod rustrt { - use unstable::lang::rust_task; - use libc::{c_char, uintptr_t}; - - extern { - #[rust_stack] - pub fn rust_upcall_malloc(td: *c_char, size: uintptr_t) -> *c_char; - #[rust_stack] - pub fn rust_upcall_free(ptr: *c_char); - #[fast_ffi] - pub fn rust_upcall_malloc_noswitch(td: *c_char, size: uintptr_t) - -> *c_char; - #[rust_stack] - pub fn rust_try_get_task() -> *rust_task; - } -} - #[lang="fail_"] pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! { sys::begin_unwind_(expr, file, line); @@ -49,25 +29,21 @@ pub fn fail_bounds_check(file: *c_char, line: size_t, index: size_t, len: size_t) { let msg = fmt!("index out of bounds: the len is %d but the index is %d", len as int, index as int); - do msg.as_c_str |buf| { + do msg.to_c_str().with_ref |buf| { fail_(buf, file, line); } } #[lang="malloc"] pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { - match context() { - OldTaskContext => { - return rustrt::rust_upcall_malloc_noswitch(td, size); - } - _ => { - let mut alloc = ::ptr::null(); - do Local::borrow::<Task,()> |task| { - alloc = task.heap.alloc(td as *c_void, size as uint) as *c_char; - } - return alloc; - } + let mut alloc = ::ptr::null(); + do Local::borrow::<Task,()> |task| { + rtdebug!("task pointer: %x, heap pointer: %x", + ::borrow::to_uint(task), + ::borrow::to_uint(&task.heap)); + alloc = task.heap.alloc(td as *c_void, size as uint) as *c_char; } + return alloc; } // NB: Calls to free CANNOT be allowed to fail, as throwing an exception from @@ -132,23 +108,11 @@ pub unsafe fn annihilate() { pub fn start(main: *u8, argc: int, argv: **c_char, crate_map: *u8) -> int { use rt; - use os; unsafe { - let use_old_rt = os::getenv("RUST_OLDRT").is_some(); - if use_old_rt { - return rust_start(main as *c_void, argc as c_int, argv, - crate_map as *c_void) as int; - } else { - return do rt::start(argc, argv as **u8, crate_map) { - let main: extern "Rust" fn() = transmute(main); - main(); - }; - } - } - - extern { - fn rust_start(main: *c_void, argc: c_int, argv: **c_char, - crate_map: *c_void) -> c_int; + return do rt::start(argc, argv as **u8, crate_map) { + let main: extern "Rust" fn() = transmute(main); + main(); + }; } } diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs index 225ac5c92ad..a9dded41683 100644 --- a/src/libstd/unstable/sync.rs +++ b/src/libstd/unstable/sync.rs @@ -280,33 +280,19 @@ impl<T> Drop for UnsafeAtomicRcBox<T>{ // FIXME(#8140) should not be pub pub unsafe fn atomically<U>(f: &fn() -> U) -> U { use rt::task::Task; - use task::rt; use rt::local::Local; - use rt::{context, OldTaskContext, TaskContext}; - - match context() { - OldTaskContext => { - let t = rt::rust_get_task(); - do (|| { - rt::rust_task_inhibit_kill(t); - rt::rust_task_inhibit_yield(t); - f() - }).finally { - rt::rust_task_allow_yield(t); - rt::rust_task_allow_kill(t); - } - } - TaskContext => { - let t = Local::unsafe_borrow::<Task>(); - do (|| { - (*t).death.inhibit_yield(); - f() - }).finally { - (*t).death.allow_yield(); - } + use rt::in_green_task_context; + + if in_green_task_context() { + let t = Local::unsafe_borrow::<Task>(); + do (|| { + (*t).death.inhibit_yield(); + f() + }).finally { + (*t).death.allow_yield(); } - // FIXME(#3095): As in unkillable(). - _ => f() + } else { + f() } } diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 36201dc5e82..c831dd70918 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -382,7 +382,7 @@ pub fn unzip_slice<T:Clone,U:Clone>(v: &[(T, U)]) -> (~[T], ~[U]) { pub fn unzip<T,U>(v: ~[(T, U)]) -> (~[T], ~[U]) { let mut ts = ~[]; let mut us = ~[]; - for p in v.consume_iter() { + for p in v.move_iter() { let (t, u) = p; ts.push(t); us.push(u); @@ -1068,10 +1068,10 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { } /// Deprecated, use iterators where possible - /// (`self.iter().transform(f)`). Apply a function to each element + /// (`self.iter().map(f)`). Apply a function to each element /// of a vector and return the results. fn map<U>(&self, f: &fn(t: &T) -> U) -> ~[U] { - self.iter().transform(f).collect() + self.iter().map(f).collect() } /** @@ -1174,8 +1174,8 @@ impl<'self,T:Clone> ImmutableCopyableVector<T> for &'self [T] { #[allow(missing_doc)] pub trait OwnedVector<T> { - fn consume_iter(self) -> ConsumeIterator<T>; - fn consume_rev_iter(self) -> ConsumeRevIterator<T>; + fn move_iter(self) -> MoveIterator<T>; + fn move_rev_iter(self) -> MoveRevIterator<T>; fn reserve(&mut self, n: uint); fn reserve_at_least(&mut self, n: uint); @@ -1204,26 +1204,26 @@ impl<T> OwnedVector<T> for ~[T] { /// value out of the vector (from start to end). The vector cannot /// be used after calling this. /// - /// Note that this performs O(n) swaps, and so `consume_rev_iter` + /// Note that this performs O(n) swaps, and so `move_rev_iter` /// (which just calls `pop` repeatedly) is more efficient. /// /// # Examples /// /// ~~~ {.rust} /// let v = ~[~"a", ~"b"]; - /// for s in v.consume_iter() { + /// for s in v.move_iter() { /// // s has type ~str, not &~str /// println(s); /// } /// ~~~ - fn consume_iter(self) -> ConsumeIterator<T> { - ConsumeIterator { v: self, idx: 0 } + fn move_iter(self) -> MoveIterator<T> { + MoveIterator { v: self, idx: 0 } } /// Creates a consuming iterator that moves out of the vector in - /// reverse order. Also see `consume_iter`, however note that this + /// reverse order. Also see `move_iter`, however note that this /// is more efficient. - fn consume_rev_iter(self) -> ConsumeRevIterator<T> { - ConsumeRevIterator { v: self } + fn move_rev_iter(self) -> MoveRevIterator<T> { + MoveRevIterator { v: self } } /** @@ -1540,7 +1540,7 @@ impl<T> OwnedVector<T> for ~[T] { let mut lefts = ~[]; let mut rights = ~[]; - for elt in self.consume_iter() { + for elt in self.move_iter() { if f(&elt) { lefts.push(elt); } else { @@ -1602,8 +1602,8 @@ impl<T:Clone> OwnedCopyableVector<T> for ~[T] { let new_len = self.len() + rhs.len(); self.reserve(new_len); - for i in range(0u, rhs.len()) { - self.push(unsafe { raw::get(rhs, i) }) + for elt in rhs.iter() { + self.push((*elt).clone()) } } @@ -2148,7 +2148,7 @@ pub mod bytes { impl<A:Clone> Clone for ~[A] { #[inline] fn clone(&self) -> ~[A] { - self.iter().transform(|item| item.clone()).collect() + self.iter().map(|item| item.clone()).collect() } } @@ -2281,12 +2281,12 @@ pub type MutRevIterator<'self, T> = Invert<VecMutIterator<'self, T>>; /// An iterator that moves out of a vector. #[deriving(Clone)] -pub struct ConsumeIterator<T> { +pub struct MoveIterator<T> { priv v: ~[T], priv idx: uint, } -impl<T> Iterator<T> for ConsumeIterator<T> { +impl<T> Iterator<T> for MoveIterator<T> { fn next(&mut self) -> Option<T> { // this is peculiar, but is required for safety with respect // to dtors. It traverses the first half of the vec, and @@ -2308,11 +2308,11 @@ impl<T> Iterator<T> for ConsumeIterator<T> { /// An iterator that moves out of a vector in reverse order. #[deriving(Clone)] -pub struct ConsumeRevIterator<T> { +pub struct MoveRevIterator<T> { priv v: ~[T] } -impl<T> Iterator<T> for ConsumeRevIterator<T> { +impl<T> Iterator<T> for MoveRevIterator<T> { fn next(&mut self) -> Option<T> { self.v.pop_opt() } @@ -3323,17 +3323,17 @@ mod tests { } #[test] - fn test_consume_iterator() { + fn test_move_iterator() { use iterator::*; let xs = ~[1u,2,3,4,5]; - assert_eq!(xs.consume_iter().fold(0, |a: uint, b: uint| 10*a + b), 12345); + assert_eq!(xs.move_iter().fold(0, |a: uint, b: uint| 10*a + b), 12345); } #[test] - fn test_consume_rev_iterator() { + fn test_move_rev_iterator() { use iterator::*; let xs = ~[1u,2,3,4,5]; - assert_eq!(xs.consume_rev_iter().fold(0, |a: uint, b: uint| 10*a + b), 54321); + assert_eq!(xs.move_rev_iter().fold(0, |a: uint, b: uint| 10*a + b), 54321); } #[test] @@ -3608,7 +3608,7 @@ mod tests { } assert_eq!(cnt, 8); - for f in v.consume_iter() { + for f in v.move_iter() { assert!(f == Foo); cnt += 1; } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 435be3c71af..17247222c3f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -951,7 +951,11 @@ pub struct view_item { #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)] pub enum view_item_ { - view_item_extern_mod(ident, ~[@MetaItem], NodeId), + // ident: name used to refer to this crate in the code + // optional @str: if present, this is a location (containing + // arbitrary characters) from which to fetch the crate sources + // For example, extern mod whatever = "github.com/mozilla/rust" + view_item_extern_mod(ident, Option<@str>, ~[@MetaItem], NodeId), view_item_use(~[@view_path]), } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index ba167fe6714..0005180ef50 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -247,7 +247,7 @@ pub fn unguarded_pat(a: &arm) -> Option<~[@pat]> { } pub fn public_methods(ms: ~[@method]) -> ~[@method] { - do ms.consume_iter().filter |m| { + do ms.move_iter().filter |m| { match m.vis { public => true, _ => false @@ -419,7 +419,7 @@ impl Visitor<()> for IdVisitor { fn visit_view_item(@mut self, view_item: &view_item, env: ()) { match view_item.node { - view_item_extern_mod(_, _, node_id) => { + view_item_extern_mod(_, _, _, node_id) => { (self.visit_callback)(node_id) } view_item_use(ref view_paths) => { diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 9edd41152f7..b0dda2b7dc8 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -186,13 +186,13 @@ pub fn contains_name<AM: AttrMetaMethods>(metas: &[AM], name: &str) -> bool { pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) -> Option<@str> { attrs.iter() - .find_(|at| name == at.name()) + .find(|at| name == at.name()) .chain(|at| at.value_str()) } pub fn last_meta_item_value_str_by_name(items: &[@MetaItem], name: &str) -> Option<@str> { - items.rev_iter().find_(|mi| name == mi.name()).chain(|i| i.value_str()) + items.rev_iter().find(|mi| name == mi.name()).chain(|i| i.value_str()) } /* Higher-level applications */ @@ -201,7 +201,7 @@ pub fn sort_meta_items(items: &[@MetaItem]) -> ~[@MetaItem] { // This is sort of stupid here, but we need to sort by // human-readable strings. let mut v = items.iter() - .transform(|&mi| (mi.name(), mi)) + .map(|&mi| (mi.name(), mi)) .collect::<~[(@str, @MetaItem)]>(); do extra::sort::quick_sort(v) |&(a, _), &(b, _)| { @@ -209,7 +209,7 @@ pub fn sort_meta_items(items: &[@MetaItem]) -> ~[@MetaItem] { } // There doesn't seem to be a more optimal way to do this - do v.consume_iter().transform |(_, m)| { + do v.move_iter().map |(_, m)| { match m.node { MetaList(n, ref mis) => { @spanned { diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index ee0ec664e1b..b5d97427baf 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.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. // @@ -59,7 +59,7 @@ pub fn expand_asm(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) match state { Asm => { asm = expr_to_str(cx, p.parse_expr(), - ~"inline assembly must be a string literal."); + "inline assembly must be a string literal."); } Outputs => { while *p.token != token::EOF && diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index dc20994b49f..dfaffa0c275 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -148,7 +148,9 @@ pub fn syntax_expander_table() -> SyntaxEnv { intern(&"auto_decode"), @SE(ItemDecorator(ext::auto_encode::expand_auto_decode))); syntax_expanders.insert(intern(&"env"), - builtin_normal_tt(ext::env::expand_syntax_ext)); + builtin_normal_tt(ext::env::expand_env)); + syntax_expanders.insert(intern(&"option_env"), + builtin_normal_tt(ext::env::expand_option_env)); syntax_expanders.insert(intern("bytes"), builtin_normal_tt(ext::bytes::expand_syntax_ext)); syntax_expanders.insert(intern("concat_idents"), @@ -313,7 +315,7 @@ impl ExtCtxt { } } -pub fn expr_to_str(cx: @ExtCtxt, expr: @ast::expr, err_msg: ~str) -> @str { +pub fn expr_to_str(cx: @ExtCtxt, expr: @ast::expr, err_msg: &str) -> @str { match expr.node { ast::expr_lit(l) => match l.node { ast::lit_str(s) => s, @@ -419,12 +421,12 @@ pub enum MapChain<K,V> { // get the map from an env frame impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{ // Constructor. I don't think we need a zero-arg one. - fn new(init: ~HashMap<K,@V>) -> @mut MapChain<K,V> { + pub fn new(init: ~HashMap<K,@V>) -> @mut MapChain<K,V> { @mut BaseMapChain(init) } // add a new frame to the environment (functionally) - fn push_frame (@mut self) -> @mut MapChain<K,V> { + pub fn push_frame (@mut self) -> @mut MapChain<K,V> { @mut ConsMapChain(~HashMap::new() ,self) } @@ -434,7 +436,7 @@ impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{ // ugh: can't get this to compile with mut because of the // lack of flow sensitivity. - fn get_map<'a>(&'a self) -> &'a HashMap<K,@V> { + pub fn get_map<'a>(&'a self) -> &'a HashMap<K,@V> { match *self { BaseMapChain (~ref map) => map, ConsMapChain (~ref map,_) => map @@ -444,7 +446,7 @@ impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{ // traits just don't work anywhere...? //impl Map<Name,SyntaxExtension> for MapChain { - fn contains_key (&self, key: &K) -> bool { + pub fn contains_key (&self, key: &K) -> bool { match *self { BaseMapChain (ref map) => map.contains_key(key), ConsMapChain (ref map,ref rest) => @@ -455,17 +457,17 @@ impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{ // should each_key and each_value operate on shadowed // names? I think not. // delaying implementing this.... - fn each_key (&self, _f: &fn (&K)->bool) { + pub fn each_key (&self, _f: &fn (&K)->bool) { fail!("unimplemented 2013-02-15T10:01"); } - fn each_value (&self, _f: &fn (&V) -> bool) { + pub fn each_value (&self, _f: &fn (&V) -> bool) { fail!("unimplemented 2013-02-15T10:02"); } // Returns a copy of the value that the name maps to. // Goes down the chain 'til it finds one (or bottom out). - fn find (&self, key: &K) -> Option<@V> { + pub fn find (&self, key: &K) -> Option<@V> { match self.get_map().find (key) { Some(ref v) => Some(**v), None => match *self { @@ -475,7 +477,7 @@ impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{ } } - fn find_in_topmost_frame(&self, key: &K) -> Option<@V> { + pub fn find_in_topmost_frame(&self, key: &K) -> Option<@V> { let map = match *self { BaseMapChain(ref map) => map, ConsMapChain(ref map,_) => map @@ -485,7 +487,7 @@ impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{ } // insert the binding into the top-level map - fn insert (&mut self, key: K, ext: @V) -> bool { + pub fn insert (&mut self, key: K, ext: @V) -> bool { // can't abstract over get_map because of flow sensitivity... match *self { BaseMapChain (~ref mut map) => map.insert(key, ext), @@ -497,7 +499,7 @@ impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{ // ... there are definitely some opportunities for abstraction // here that I'm ignoring. (e.g., manufacturing a predicate on // the maps in the chain, and using an abstract "find". - fn insert_into_frame(&mut self, key: K, ext: @V, n: K, pred: &fn(&@V)->bool) { + pub fn insert_into_frame(&mut self, key: K, ext: @V, n: K, pred: &fn(&@V)->bool) { match *self { BaseMapChain (~ref mut map) => { if satisfies_pred(map,&n,pred) { @@ -538,8 +540,8 @@ mod test { a.insert (@"abc",@15); let m = MapChain::new(~a); m.insert (@"def",@16); - // FIXME: #4492 (ICE) assert_eq!(m.find(&@"abc"),Some(@15)); - // .... assert_eq!(m.find(&@"def"),Some(@16)); + assert_eq!(m.find(&@"abc"),Some(@15)); + assert_eq!(m.find(&@"def"),Some(@16)); assert_eq!(*(m.find(&@"abc").unwrap()),15); assert_eq!(*(m.find(&@"def").unwrap()),16); let n = m.push_frame(); @@ -551,8 +553,8 @@ mod test { assert_eq!(*(n.find(&@"abc").unwrap()),15); assert_eq!(*(n.find(&@"def").unwrap()),17); // ... but m still has the old ones - // FIXME: #4492: assert_eq!(m.find(&@"abc"),Some(@15)); - // FIXME: #4492: assert_eq!(m.find(&@"def"),Some(@16)); + assert_eq!(m.find(&@"abc"),Some(@15)); + assert_eq!(m.find(&@"def"),Some(@16)); assert_eq!(*(m.find(&@"abc").unwrap()),15); assert_eq!(*(m.find(&@"def").unwrap()),16); } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index d81dca005b0..65032642fda 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -702,7 +702,7 @@ impl AstBuilder for @ExtCtxt { } fn variant(&self, span: span, name: ident, tys: ~[ast::Ty]) -> ast::variant { - let args = tys.consume_iter().transform(|ty| { + let args = tys.move_iter().map(|ty| { ast::variant_arg { ty: ty, id: self.next_id() } }).collect(); diff --git a/src/libsyntax/ext/cfg.rs b/src/libsyntax/ext/cfg.rs index 069cac01036..5f9437fd253 100644 --- a/src/libsyntax/ext/cfg.rs +++ b/src/libsyntax/ext/cfg.rs @@ -39,7 +39,7 @@ pub fn expand_cfg(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) -> base::MacR // test_cfg searches for meta items looking like `cfg(foo, ...)` let in_cfg = &[cx.meta_list(sp, @"cfg", cfgs)]; - let matches_cfg = attr::test_cfg(cx.cfg(), in_cfg.iter().transform(|&x| x)); + let matches_cfg = attr::test_cfg(cx.cfg(), in_cfg.iter().map(|&x| x)); let e = cx.expr_bool(sp, matches_cfg); MRExpr(e) } diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 59b7da16c2b..1abfe246f9d 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -90,7 +90,7 @@ fn decodable_substructure(cx: @ExtCtxt, span: span, } } Right(ref fields) => { - let fields = do fields.iter().enumerate().transform |(i, f)| { + let fields = do fields.iter().enumerate().map |(i, f)| { cx.field_imm(span, *f, getarg(cx.str_of(*f), i)) }.collect(); cx.expr_struct_ident(span, substr.type_ident, fields) @@ -132,7 +132,7 @@ fn decodable_substructure(cx: @ExtCtxt, span: span, } } Right(ref fields) => { - let fields = do fields.iter().enumerate().transform |(i, f)| { + let fields = do fields.iter().enumerate().map |(i, f)| { cx.field_imm(span, *f, getarg(i)) }.collect(); cx.expr_struct_ident(span, name, fields) diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index fb1e6bf1913..a1abe47e090 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -590,7 +590,7 @@ impl<'self> MethodDef<'self> { // transpose raw_fields let fields = match raw_fields { [ref self_arg, .. rest] => { - do self_arg.iter().enumerate().transform |(i, &(opt_id, field))| { + do self_arg.iter().enumerate().map |(i, &(opt_id, field))| { let other_fields = do rest.map |l| { match &l[i] { &(_, ex) => ex @@ -750,7 +750,7 @@ impl<'self> MethodDef<'self> { let field_tuples = do self_vec.iter() .zip(enum_matching_fields.iter()) - .transform |(&(id, self_f), other)| { + .map |(&(id, self_f), other)| { (id, self_f, (*other).clone()) }.collect(); substructure = EnumMatching(variant_index, variant, field_tuples); diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 2966a8c114d..e55a96f77ff 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -95,7 +95,7 @@ fn rand_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr { let rand_variant = cx.expr_binary(span, ast::rem, rv_call, variant_count); - let mut arms = do variants.iter().enumerate().transform |(i, id_sum)| { + let mut arms = do variants.iter().enumerate().map |(i, id_sum)| { let i_expr = cx.expr_uint(span, i); let pat = cx.pat_lit(span, i_expr); diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index a6cb6155878..c9e01b0f0d5 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.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. // @@ -22,17 +22,35 @@ use ext::build::AstBuilder; use std::os; -pub fn expand_syntax_ext(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) +pub fn expand_option_env(ext_cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) -> base::MacResult { + let var = get_single_str_from_tts(ext_cx, sp, tts, "option_env!"); - let var = get_single_str_from_tts(cx, sp, tts, "env!"); + let e = match os::getenv(var) { + None => quote_expr!(::std::option::None), + Some(s) => quote_expr!(::std::option::Some($s)) + }; + MRExpr(e) +} - // FIXME (#2248): if this was more thorough it would manufacture an - // Option<str> rather than just an maybe-empty string. +pub fn expand_env(ext_cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) + -> base::MacResult { + let exprs = get_exprs_from_tts(ext_cx, sp, tts); + + if exprs.len() == 0 { + ext_cx.span_fatal(sp, "env! takes 1 or 2 arguments"); + } + + let var = expr_to_str(ext_cx, exprs[0], "expected string literal"); + let msg = match exprs.len() { + 1 => fmt!("Environment variable %s not defined", var).to_managed(), + 2 => expr_to_str(ext_cx, exprs[1], "expected string literal"), + _ => ext_cx.span_fatal(sp, "env! takes 1 or 2 arguments") + }; let e = match os::getenv(var) { - None => cx.expr_str(sp, @""), - Some(s) => cx.expr_str(sp, s.to_managed()) + None => ext_cx.span_fatal(sp, msg), + Some(s) => ext_cx.expr_str(sp, s.to_managed()) }; MRExpr(e) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index a928680e093..1963f3aef49 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1075,7 +1075,6 @@ mod test { use parse::token::{intern, get_ident_interner}; use print::pprust; use util::parser_testing::{string_to_item, string_to_pat, strs_to_idents}; - use oldvisit::{mk_vt}; // make sure that fail! is present #[test] fn fail_exists_test () { diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs index 2dbf6887a21..10f2055b5fb 100644 --- a/src/libsyntax/ext/fmt.rs +++ b/src/libsyntax/ext/fmt.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. // @@ -32,7 +32,7 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) } let fmt = expr_to_str(cx, args[0], - ~"first argument to fmt! must be a string literal."); + "first argument to fmt! must be a string literal."); let fmtspan = args[0].span; debug!("Format string: %s", fmt); fn parse_fmt_err_(cx: @ExtCtxt, sp: span, msg: &str) -> ! { @@ -269,7 +269,7 @@ fn pieces_to_expr(cx: @ExtCtxt, sp: span, corresponding function in std::unstable::extfmt. Each function takes a buffer to insert data into along with the data being formatted. */ let npieces = pieces.len(); - for (i, pc) in pieces.consume_iter().enumerate() { + for (i, pc) in pieces.move_iter().enumerate() { match pc { /* Raw strings get appended via str::push_str */ PieceString(s) => { diff --git a/src/libsyntax/ext/ifmt.rs b/src/libsyntax/ext/ifmt.rs index 5cf5fdba632..a3adb42425a 100644 --- a/src/libsyntax/ext/ifmt.rs +++ b/src/libsyntax/ext/ifmt.rs @@ -353,9 +353,9 @@ impl Context { let trans_method = |method: &parse::Method| { let method = match *method { parse::Select(ref arms, ref default) => { - let arms = arms.iter().transform(|arm| { + let arms = arms.iter().map(|arm| { let p = self.ecx.path_global(sp, rtpath("SelectArm")); - let result = arm.result.iter().transform(|p| { + let result = arm.result.iter().map(|p| { self.trans_piece(p) }).collect(); let s = arm.selector.to_managed(); @@ -368,7 +368,7 @@ impl Context { self.ecx.expr_vec_slice(sp, result)), ]) }).collect(); - let default = default.iter().transform(|p| { + let default = default.iter().map(|p| { self.trans_piece(p) }).collect(); self.ecx.expr_call_global(sp, rtpath("Select"), ~[ @@ -381,9 +381,9 @@ impl Context { Some(i) => { some(self.ecx.expr_uint(sp, i)) } None => { none() } }; - let arms = arms.iter().transform(|arm| { + let arms = arms.iter().map(|arm| { let p = self.ecx.path_global(sp, rtpath("PluralArm")); - let result = arm.result.iter().transform(|p| { + let result = arm.result.iter().map(|p| { self.trans_piece(p) }).collect(); let (lr, selarg) = match arm.selector { @@ -408,7 +408,7 @@ impl Context { self.ecx.expr_vec_slice(sp, result)), ]) }).collect(); - let default = default.iter().transform(|p| { + let default = default.iter().map(|p| { self.trans_piece(p) }).collect(); self.ecx.expr_call_global(sp, rtpath("Plural"), ~[ @@ -575,8 +575,8 @@ impl Context { Some(self.format_arg(e.span, Right(name), lname)); } - let args = names.consume_iter().transform(|a| a.unwrap()); - let mut args = locals.consume_iter().chain_(args); + let args = names.move_iter().map(|a| a.unwrap()); + let mut args = locals.move_iter().chain(args); // Next, build up the actual call to the sprintf function. let result = self.ecx.expr_call_global(self.fmtsp, ~[ @@ -685,7 +685,7 @@ pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span, }; cx.fmtsp = efmt.span; let fmt = expr_to_str(ecx, efmt, - ~"first argument to ifmt! must be a string literal."); + "first argument to ifmt! must be a string literal."); let mut err = false; do parse::parse_error::cond.trap(|m| { diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 71903b9aa02..031f0fb4199 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -105,7 +105,7 @@ pub fn expand_include_bin(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) let file = get_single_str_from_tts(cx, sp, tts, "include_bin!"); match io::read_whole_file(&res_rel_file(cx, sp, &Path(file))) { result::Ok(src) => { - let u8_exprs: ~[@ast::expr] = src.iter().transform(|char| cx.expr_u8(sp, *char)).collect(); + let u8_exprs: ~[@ast::expr] = src.iter().map(|char| cx.expr_u8(sp, *char)).collect(); base::MRExpr(cx.expr_vec(sp, u8_exprs)) } result::Err(ref e) => { diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 5a1317034b2..918949113ad 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -17,6 +17,7 @@ use codemap; use parse::lexer::*; //resolve bug? use parse::ParseSess; use parse::parser::Parser; +use parse::attr::parser_attr; use parse::token::{Token, EOF, to_str, nonterminal, get_ident_interner, ident_to_str}; use parse::token; @@ -430,6 +431,7 @@ pub fn parse_nt(p: &Parser, name: &str) -> nonterminal { + token::to_str(get_ident_interner(), p.token)) }, "path" => token::nt_path(p.parse_path_with_tps(false)), + "attr" => token::nt_attr(@p.parse_attribute(false)), "tt" => { *p.quote_depth += 1u; //but in theory, non-quoted tts might be useful let res = token::nt_tt(@p.parse_token_tree()); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 0a5bc000720..65694f013f7 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -176,7 +176,7 @@ pub fn fold_ty_param(tp: TyParam, pub fn fold_ty_params(tps: &OptVec<TyParam>, fld: @ast_fold) -> OptVec<TyParam> { let tps = /*bad*/ (*tps).clone(); - tps.map_consume(|tp| fold_ty_param(tp, fld)) + tps.map_move(|tp| fold_ty_param(tp, fld)) } pub fn fold_lifetime(l: &Lifetime, @@ -704,7 +704,7 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ { // ...nor do modules pub fn noop_fold_mod(m: &_mod, fld: @ast_fold) -> _mod { ast::_mod { - view_items: m.view_items.iter().transform(|x| fld.fold_view_item(x)).collect(), + view_items: m.view_items.iter().map(|x| fld.fold_view_item(x)).collect(), items: m.items.iter().filter_map(|x| fld.fold_item(*x)).collect(), } } @@ -713,8 +713,8 @@ fn noop_fold_foreign_mod(nm: &foreign_mod, fld: @ast_fold) -> foreign_mod { ast::foreign_mod { sort: nm.sort, abis: nm.abis, - view_items: nm.view_items.iter().transform(|x| fld.fold_view_item(x)).collect(), - items: nm.items.iter().transform(|x| fld.fold_foreign_item(*x)).collect(), + view_items: nm.view_items.iter().map(|x| fld.fold_view_item(x)).collect(), + items: nm.items.iter().map(|x| fld.fold_foreign_item(*x)).collect(), } } @@ -734,7 +734,7 @@ fn noop_fold_variant(v: &variant_, fld: @ast_fold) -> variant_ { struct_variant_kind(ref struct_def) => { kind = struct_variant_kind(@ast::struct_def { fields: struct_def.fields.iter() - .transform(|f| fld.fold_struct_field(*f)).collect(), + .map(|f| fld.fold_struct_field(*f)).collect(), ctor_id: struct_def.ctor_id.map(|c| fld.new_id(*c)) }) } @@ -828,7 +828,7 @@ impl ast_fold for AstFoldFns { fn fold_view_item(@self, x: &view_item) -> view_item { ast::view_item { node: (self.fold_view_item)(&x.node, self as @ast_fold), - attrs: x.attrs.iter().transform(|a| fold_attribute_(*a, self as @ast_fold)).collect(), + attrs: x.attrs.iter().map(|a| fold_attribute_(*a, self as @ast_fold)).collect(), vis: x.vis, span: (self.new_span)(x.span), } diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index 10603751a06..3a10206b513 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -36,7 +36,7 @@ pub fn from<T>(t: ~[T]) -> OptVec<T> { } impl<T> OptVec<T> { - fn push(&mut self, t: T) { + pub fn push(&mut self, t: T) { match *self { Vec(ref mut v) => { v.push(t); @@ -50,32 +50,32 @@ impl<T> OptVec<T> { *self = Vec(~[t]); } - fn map<U>(&self, op: &fn(&T) -> U) -> OptVec<U> { + pub fn map<U>(&self, op: &fn(&T) -> U) -> OptVec<U> { match *self { Empty => Empty, Vec(ref v) => Vec(v.map(op)) } } - fn map_consume<U>(self, op: &fn(T) -> U) -> OptVec<U> { + pub fn map_move<U>(self, op: &fn(T) -> U) -> OptVec<U> { match self { Empty => Empty, - Vec(v) => Vec(v.consume_iter().transform(op).collect()) + Vec(v) => Vec(v.move_iter().map(op).collect()) } } - fn get<'a>(&'a self, i: uint) -> &'a T { + pub fn get<'a>(&'a self, i: uint) -> &'a T { match *self { Empty => fail!("Invalid index %u", i), Vec(ref v) => &v[i] } } - fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { self.len() == 0 } - fn len(&self) -> uint { + pub fn len(&self) -> uint { match *self { Empty => 0, Vec(ref v) => v.len() @@ -83,7 +83,7 @@ impl<T> OptVec<T> { } #[inline] - fn iter<'r>(&'r self) -> OptVecIterator<'r, T> { + pub fn iter<'r>(&'r self) -> OptVecIterator<'r, T> { match *self { Empty => OptVecIterator{iter: None}, Vec(ref v) => OptVecIterator{iter: Some(v.iter())} @@ -91,11 +91,11 @@ impl<T> OptVec<T> { } #[inline] - fn map_to_vec<B>(&self, op: &fn(&T) -> B) -> ~[B] { - self.iter().transform(op).collect() + pub fn map_to_vec<B>(&self, op: &fn(&T) -> B) -> ~[B] { + self.iter().map(op).collect() } - fn mapi_to_vec<B>(&self, op: &fn(uint, &T) -> B) -> ~[B] { + pub fn mapi_to_vec<B>(&self, op: &fn(uint, &T) -> B) -> ~[B] { let mut index = 0; self.map_to_vec(|a| { let i = index; @@ -113,7 +113,7 @@ pub fn take_vec<T>(v: OptVec<T>) -> ~[T] { } impl<T:Clone> OptVec<T> { - fn prepend(&self, t: T) -> OptVec<T> { + pub fn prepend(&self, t: T) -> OptVec<T> { let mut v0 = ~[t]; match *self { Empty => {} @@ -124,7 +124,7 @@ impl<T:Clone> OptVec<T> { } impl<A:Eq> Eq for OptVec<A> { - fn eq(&self, other: &OptVec<A>) -> bool { + pub fn eq(&self, other: &OptVec<A>) -> bool { // Note: cannot use #[deriving(Eq)] here because // (Empty, Vec(~[])) ought to be equal. match (self, other) { @@ -135,7 +135,7 @@ impl<A:Eq> Eq for OptVec<A> { } } - fn ne(&self, other: &OptVec<A>) -> bool { + pub fn ne(&self, other: &OptVec<A>) -> bool { !self.eq(other) } } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 8cce5f15e67..f2489d80e1e 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -9,21 +9,17 @@ // except according to those terms. use ast; -use codemap::spanned; +use codemap::{spanned, mk_sp}; use codemap::BytePos; use parse::common::*; //resolve bug? use parse::token; use parse::parser::Parser; +use parse::token::INTERPOLATED; // a parser that can parse attributes. pub trait parser_attr { fn parse_outer_attributes(&self) -> ~[ast::Attribute]; - fn parse_attribute(&self, style: ast::AttrStyle) -> ast::Attribute; - fn parse_attribute_naked( - &self, - style: ast::AttrStyle, - lo: BytePos - ) -> ast::Attribute; + fn parse_attribute(&self, permit_inner: bool) -> ast::Attribute; fn parse_inner_attrs_and_next(&self) -> (~[ast::Attribute], ~[ast::Attribute]); fn parse_meta_item(&self) -> @ast::MetaItem; @@ -37,12 +33,17 @@ impl parser_attr for Parser { fn parse_outer_attributes(&self) -> ~[ast::Attribute] { let mut attrs: ~[ast::Attribute] = ~[]; loop { + debug!("parse_outer_attributes: self.token=%?", + self.token); match *self.token { + token::INTERPOLATED(token::nt_attr(*)) => { + attrs.push(self.parse_attribute(false)); + } token::POUND => { if self.look_ahead(1, |t| *t != token::LBRACKET) { break; } - attrs.push(self.parse_attribute(ast::AttrOuter)); + attrs.push(self.parse_attribute(false)); } token::DOC_COMMENT(s) => { let attr = ::attr::mk_sugared_doc_attr( @@ -62,23 +63,49 @@ impl parser_attr for Parser { return attrs; } - // matches attribute = # attribute_naked - fn parse_attribute(&self, style: ast::AttrStyle) -> ast::Attribute { - let lo = self.span.lo; - self.expect(&token::POUND); - return self.parse_attribute_naked(style, lo); + // matches attribute = # [ meta_item ] + // + // if permit_inner is true, then a trailing `;` indicates an inner + // attribute + fn parse_attribute(&self, permit_inner: bool) -> ast::Attribute { + debug!("parse_attributes: permit_inner=%? self.token=%?", + permit_inner, self.token); + let (span, value) = match *self.token { + INTERPOLATED(token::nt_attr(attr)) => { + assert!(attr.node.style == ast::AttrOuter); + self.bump(); + (attr.span, attr.node.value) + } + token::POUND => { + let lo = self.span.lo; + self.bump(); + self.expect(&token::LBRACKET); + let meta_item = self.parse_meta_item(); + self.expect(&token::RBRACKET); + let hi = self.span.hi; + (mk_sp(lo, hi), meta_item) + } + _ => { + self.fatal(fmt!("expected `#` but found `%s`", + self.this_token_to_str())); + } + }; + let style = if permit_inner && *self.token == token::SEMI { + self.bump(); + ast::AttrInner + } else { + ast::AttrOuter + }; + return spanned { + span: span, + node: ast::Attribute_ { + style: style, + value: value, + is_sugared_doc: false + } + }; } - // matches attribute_naked = [ meta_item ] - fn parse_attribute_naked(&self, style: ast::AttrStyle, lo: BytePos) -> - ast::Attribute { - self.expect(&token::LBRACKET); - let meta_item = self.parse_meta_item(); - self.expect(&token::RBRACKET); - let hi = self.span.hi; - return spanned(lo, hi, ast::Attribute_ { style: style, - value: meta_item, is_sugared_doc: false }); } - // Parse attributes that appear after the opening of an item, each // terminated by a semicolon. In addition to a vector of inner attributes, // this function also returns a vector that may contain the first outer @@ -89,47 +116,37 @@ impl parser_attr for Parser { // matches inner_attrs* outer_attr? // you can make the 'next' field an Option, but the result is going to be // more useful as a vector. - fn parse_inner_attrs_and_next(&self) -> - (~[ast::Attribute], ~[ast::Attribute]) { + fn parse_inner_attrs_and_next(&self) + -> (~[ast::Attribute], ~[ast::Attribute]) { let mut inner_attrs: ~[ast::Attribute] = ~[]; let mut next_outer_attrs: ~[ast::Attribute] = ~[]; loop { - match *self.token { - token::POUND => { - if self.look_ahead(1, |t| *t != token::LBRACKET) { - // This is an extension - break; + let attr = match *self.token { + token::INTERPOLATED(token::nt_attr(*)) => { + self.parse_attribute(true) + } + token::POUND => { + if self.look_ahead(1, |t| *t != token::LBRACKET) { + // This is an extension + break; + } + self.parse_attribute(true) } - let attr = self.parse_attribute(ast::AttrInner); - if *self.token == token::SEMI { + token::DOC_COMMENT(s) => { self.bump(); - inner_attrs.push(attr); - } else { - // It's not really an inner attribute - let outer_attr = - spanned(attr.span.lo, attr.span.hi, - ast::Attribute_ { style: ast::AttrOuter, - value: attr.node.value, - is_sugared_doc: false }); - next_outer_attrs.push(outer_attr); - break; + ::attr::mk_sugared_doc_attr(self.id_to_str(s), + self.span.lo, + self.span.hi) } - } - token::DOC_COMMENT(s) => { - let attr = ::attr::mk_sugared_doc_attr( - self.id_to_str(s), - self.span.lo, - self.span.hi - ); - self.bump(); - if attr.node.style == ast::AttrInner { - inner_attrs.push(attr); - } else { - next_outer_attrs.push(attr); - break; + _ => { + break; } - } - _ => break + }; + if attr.node.style == ast::AttrInner { + inner_attrs.push(attr); + } else { + next_outer_attrs.push(attr); + break; } } (inner_attrs, next_outer_attrs) diff --git a/src/libsyntax/parse/comments.rs b/src/libsyntax/parse/comments.rs index 41379e6599c..5b9725ec6a0 100644 --- a/src/libsyntax/parse/comments.rs +++ b/src/libsyntax/parse/comments.rs @@ -115,7 +115,7 @@ pub fn strip_doc_comment_decoration(comment: &str) -> ~str { if comment.starts_with("/*") { let lines = comment.slice(3u, comment.len() - 2u) .any_line_iter() - .transform(|s| s.to_owned()) + .map(|s| s.to_owned()) .collect::<~[~str]>(); let lines = vertical_trim(lines); diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 49deafeda40..bde568b2610 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -129,7 +129,11 @@ impl reader for StringReader { impl reader for TtReader { fn is_eof(@mut self) -> bool { self.cur_tok == token::EOF } - fn next_token(@mut self) -> TokenAndSpan { tt_next_token(self) } + fn next_token(@mut self) -> TokenAndSpan { + let r = tt_next_token(self); + debug!("TtReader: r=%?", r); + return r; + } fn fatal(@mut self, m: ~str) -> ! { self.sp_diag.span_fatal(self.cur_span, m); } diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index ec956f61863..dda5e990221 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -64,6 +64,7 @@ pub enum ObsoleteSyntax { ObsoleteMutWithMultipleBindings, ObsoleteExternVisibility, ObsoleteUnsafeExternFn, + ObsoletePrivVisibility, } impl to_bytes::IterBytes for ObsoleteSyntax { @@ -253,6 +254,10 @@ impl ParserObsoleteMethods for Parser { "external functions are always unsafe; remove the `unsafe` \ keyword" ), + ObsoletePrivVisibility => ( + "`priv` not necessary", + "an item without a visibility qualifier is private by default" + ), }; self.report(sp, kind, kind_str, desc); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4902c4587ac..77c50a779c0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[macro_escape]; + use abi; use abi::AbiSet; use ast::{Sigil, BorrowedSigil, ManagedSigil, OwnedSigil}; @@ -85,7 +87,7 @@ use parse::obsolete::{ObsoleteConstItem, ObsoleteFixedLengthVectorType}; use parse::obsolete::{ObsoleteNamedExternModule, ObsoleteMultipleLocalDecl}; use parse::obsolete::{ObsoleteMutWithMultipleBindings}; use parse::obsolete::{ObsoleteExternVisibility, ObsoleteUnsafeExternFn}; -use parse::obsolete::{ParserObsoleteMethods}; +use parse::obsolete::{ParserObsoleteMethods, ObsoletePrivVisibility}; use parse::token::{can_begin_expr, get_ident_interner, ident_to_str, is_ident}; use parse::token::{is_ident_or_path}; use parse::token::{is_plain_ident, INTERPOLATED, keywords, special_idents}; @@ -814,7 +816,7 @@ impl Parser { let attrs = p.parse_outer_attributes(); let lo = p.span.lo; - let vis = p.parse_visibility(); + let vis = p.parse_non_priv_visibility(); let pur = p.parse_fn_purity(); // NB: at the moment, trait methods are public by default; this // could change. @@ -3608,7 +3610,7 @@ impl Parser { let attrs = self.parse_outer_attributes(); let lo = self.span.lo; - let visa = self.parse_visibility(); + let visa = self.parse_non_priv_visibility(); let pur = self.parse_fn_purity(); let ident = self.parse_ident(); let generics = self.parse_generics(); @@ -3871,6 +3873,18 @@ impl Parser { else { inherited } } + // parse visibility, but emits an obsolete error if it's private + fn parse_non_priv_visibility(&self) -> visibility { + match self.parse_visibility() { + public => public, + inherited => inherited, + private => { + self.obsolete(*self.last_span, ObsoletePrivVisibility); + inherited + } + } + } + fn parse_staticness(&self) -> bool { if self.eat_keyword(keywords::Static) { self.obsolete(*self.last_span, ObsoleteStaticMethod); @@ -4063,7 +4077,7 @@ impl Parser { // parse a function declaration from a foreign module fn parse_item_foreign_fn(&self, attrs: ~[Attribute]) -> @foreign_item { let lo = self.span.lo; - let vis = self.parse_visibility(); + let vis = self.parse_non_priv_visibility(); // Parse obsolete purity. let purity = self.parse_fn_purity(); @@ -4169,8 +4183,16 @@ impl Parser { self.this_token_to_str())); } - let (sort, ident) = match *self.token { - token::IDENT(*) => (ast::named, self.parse_ident()), + let (sort, maybe_path, ident) = match *self.token { + token::IDENT(*) => { + let the_ident = self.parse_ident(); + let path = if *self.token == token::EQ { + self.bump(); + Some(self.parse_str()) + } + else { None }; + (ast::named, path, the_ident) + } _ => { if must_be_named_mod { self.span_fatal(*self.span, @@ -4179,7 +4201,7 @@ impl Parser { self.this_token_to_str())); } - (ast::anonymous, + (ast::anonymous, None, special_idents::clownshoes_foreign_mod) } }; @@ -4218,7 +4240,7 @@ impl Parser { let metadata = self.parse_optional_meta(); self.expect(&token::SEMI); iovi_view_item(ast::view_item { - node: view_item_extern_mod(ident, metadata, self.get_id()), + node: view_item_extern_mod(ident, maybe_path, metadata, self.get_id()), attrs: attrs, vis: visibility, span: mk_sp(lo, self.last_span.hi) @@ -4290,7 +4312,7 @@ impl Parser { seq_sep_trailing_disallowed(token::COMMA), |p| p.parse_ty(false) ); - for ty in arg_tys.consume_iter() { + for ty in arg_tys.move_iter() { args.push(ast::variant_arg { ty: ty, id: self.get_id(), @@ -4440,10 +4462,20 @@ impl Parser { attrs: ~[Attribute], macros_allowed: bool) -> item_or_view_item { - maybe_whole!(iovi self, nt_item); + match *self.token { + INTERPOLATED(token::nt_item(item)) => { + self.bump(); + let new_attrs = vec::append(attrs, item.attrs); + return iovi_item(@ast::item { + attrs: new_attrs, + ..(*item).clone()}); + } + _ => {} + } + let lo = self.span.lo; - let visibility = self.parse_visibility(); + let visibility = self.parse_non_priv_visibility(); // must be a view item: if self.eat_keyword(keywords::Use) { @@ -4575,7 +4607,7 @@ impl Parser { maybe_whole!(iovi self, nt_item); let lo = self.span.lo; - let visibility = self.parse_visibility(); + let visibility = self.parse_non_priv_visibility(); if (self.is_keyword(keywords::Const) || self.is_keyword(keywords::Static)) { // FOREIGN CONST ITEM @@ -4800,8 +4832,13 @@ impl Parser { } else if self.eat_keyword(keywords::Extern) { self.expect_keyword(keywords::Mod); let ident = self.parse_ident(); + let path = if *self.token == token::EQ { + self.bump(); + Some(self.parse_str()) + } + else { None }; let metadata = self.parse_optional_meta(); - view_item_extern_mod(ident, metadata, self.get_id()) + view_item_extern_mod(ident, path, metadata, self.get_id()) } else { self.bug("expected view item"); }; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index fd491c1e890..c554f111bf9 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -105,6 +105,7 @@ pub enum nonterminal { nt_expr(@ast::expr), nt_ty( ast::Ty), nt_ident(ast::ident, bool), + nt_attr(@ast::Attribute), // #[foo] nt_path( ast::Path), nt_tt( @ast::token_tree), //needs @ed to break a circularity nt_matchers(~[ast::matcher]) @@ -205,6 +206,7 @@ pub fn to_str(input: @ident_interner, t: &Token) -> ~str { INTERPOLATED(ref nt) => { match nt { &nt_expr(e) => ::print::pprust::expr_to_str(e, input), + &nt_attr(e) => ::print::pprust::attribute_to_str(e, input), _ => { ~"an interpolated " + match (*nt) { @@ -212,6 +214,7 @@ pub fn to_str(input: @ident_interner, t: &Token) -> ~str { nt_block(*) => ~"block", nt_stmt(*) => ~"statement", nt_pat(*) => ~"pattern", + nt_attr(*) => fail!("should have been handled"), nt_expr(*) => fail!("should have been handled above"), nt_ty(*) => ~"type", nt_ident(*) => ~"identifier", diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f517179f603..ffe9575a864 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1856,9 +1856,13 @@ pub fn print_view_item(s: @ps, item: &ast::view_item) { print_outer_attributes(s, item.attrs); print_visibility(s, item.vis); match item.node { - ast::view_item_extern_mod(id, ref mta, _) => { + ast::view_item_extern_mod(id, ref optional_path, ref mta, _) => { head(s, "extern mod"); print_ident(s, id); + for p in optional_path.iter() { + word(s.s, "="); + print_string(s, *p); + } if !mta.is_empty() { popen(s); commasep(s, consistent, *mta, |p, &i| print_meta_item(p, i)); diff --git a/src/rt/boxed_region.cpp b/src/rt/boxed_region.cpp index 012333b931e..0d3d6c019f8 100644 --- a/src/rt/boxed_region.cpp +++ b/src/rt/boxed_region.cpp @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#include "memory_region.h" #include "boxed_region.h" #include "rust_globals.h" -#include "rust_task.h" #include "rust_env.h" #include "rust_util.h" diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp deleted file mode 100644 index 803da32cbc8..00000000000 --- a/src/rt/rust.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/** - * Main entry point into the Rust runtime. Here we initialize the kernel, - * create the initial scheduler and run the main task. - */ - -#include "rust_globals.h" -#include "rust_kernel.h" -#include "rust_util.h" -#include "rust_scheduler.h" -#include "rust_gc_metadata.h" - -void* global_crate_map = NULL; - -/** - The runtime entrypoint. The (C ABI) main function generated by rustc calls - `rust_start`, providing the address of the Rust ABI main function, the - platform argument vector, and a `crate_map` the provides some logging - metadata. -*/ -extern "C" CDECL int -rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) { - - // Load runtime configuration options from the environment. - // FIXME #1497: Should provide a way to get these from the command - // line as well. - rust_env *env = load_env(argc, argv); - - global_crate_map = crate_map; - - update_gc_metadata(crate_map); - - update_log_settings(crate_map, env->logspec); - - rust_kernel *kernel = new rust_kernel(env); - - // Create the main task - rust_sched_id sched_id = kernel->main_sched_id(); - rust_scheduler *sched = kernel->get_scheduler_by_id(sched_id); - assert(sched != NULL); - rust_task *root_task = sched->create_task(NULL, "main"); - - // Schedule the main Rust task - root_task->start((spawn_fn)main_fn, NULL, NULL); - - // At this point the task lifecycle is responsible for it - // and our pointer may not be valid - root_task = NULL; - - // Run the kernel until all schedulers exit - int ret = kernel->run(); - - delete kernel; - free_env(env); - - return ret; -} - -// -// Local Variables: -// mode: C++ -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index d77a9f58a38..ddd452deef2 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -10,14 +10,16 @@ /* Foreign builtins. */ -#include "rust_sched_loop.h" -#include "rust_task.h" #include "rust_util.h" -#include "rust_scheduler.h" #include "sync/timer.h" #include "sync/rust_thread.h" +#include "sync/lock_and_signal.h" +#include "memory_region.h" +#include "boxed_region.h" #include "rust_abi.h" +#include "rust_rng.h" #include "vg/valgrind.h" +#include "sp.h" #include <time.h> @@ -68,12 +70,6 @@ rust_env_pairs() { } #endif -extern "C" CDECL void * -rust_local_realloc(rust_opaque_box *ptr, size_t size) { - rust_task *task = rust_get_current_task(); - return task->boxed.realloc(ptr, size); -} - extern "C" CDECL size_t rand_seed_size() { return rng_seed_size(); @@ -150,12 +146,6 @@ debug_static_mut_check_four() { assert(debug_static_mut == 4); } -extern "C" CDECL void * -debug_get_stk_seg() { - rust_task *task = rust_get_current_task(); - return task->stk; -} - extern "C" CDECL char* #if defined(__WIN32__) rust_list_dir_val(WIN32_FIND_DATA* entry_ptr) { @@ -302,10 +292,9 @@ void tm_to_rust_tm(tm* in_tm, rust_tm* out_tm, int32_t gmtoff, if (zone != NULL) { size_t size = strlen(zone); - reserve_vec_exact(&out_tm->tm_zone, size + 1); + reserve_vec_exact(&out_tm->tm_zone, size); memcpy(out_tm->tm_zone->data, zone, size); - out_tm->tm_zone->fill = size + 1; - out_tm->tm_zone->data[size] = '\0'; + out_tm->tm_zone->fill = size; } } @@ -383,162 +372,25 @@ rust_mktime(rust_tm* timeptr) { return mktime(&t); } -extern "C" CDECL rust_sched_id -rust_get_sched_id() { - rust_task *task = rust_get_current_task(); - return task->sched->get_id(); -} - -extern "C" CDECL int -rust_get_argc() { - rust_task *task = rust_get_current_task(); - return task->kernel->env->argc; -} - -extern "C" CDECL char** -rust_get_argv() { - rust_task *task = rust_get_current_task(); - return task->kernel->env->argv; -} - -extern "C" CDECL rust_sched_id -rust_new_sched(uintptr_t threads) { - rust_task *task = rust_get_current_task(); - assert(threads > 0 && "Can't create a scheduler with no threads, silly!"); - return task->kernel->create_scheduler(threads); -} - -extern "C" CDECL rust_task_id -get_task_id() { - rust_task *task = rust_get_current_task(); - return task->id; -} - -static rust_task* -new_task_common(rust_scheduler *sched, rust_task *parent) { - return sched->create_task(parent, NULL); -} - -extern "C" CDECL rust_task* -new_task() { - rust_task *task = rust_get_current_task(); - rust_sched_id sched_id = task->kernel->main_sched_id(); - rust_scheduler *sched = task->kernel->get_scheduler_by_id(sched_id); - assert(sched != NULL && "should always have a main scheduler"); - return new_task_common(sched, task); -} - -extern "C" CDECL rust_task* -rust_new_task_in_sched(rust_sched_id id) { - rust_task *task = rust_get_current_task(); - rust_scheduler *sched = task->kernel->get_scheduler_by_id(id); - if (sched == NULL) - return NULL; - return new_task_common(sched, task); -} - -extern "C" rust_task * -rust_get_task() { - return rust_get_current_task(); -} - -extern "C" rust_task * -rust_try_get_task() { - return rust_try_get_current_task(); -} - -extern "C" CDECL stk_seg * -rust_get_stack_segment() { - return rust_get_current_task()->stk; -} - -extern "C" CDECL stk_seg * -rust_get_c_stack() { - return rust_get_current_task()->get_c_stack(); -} - -extern "C" CDECL void -start_task(rust_task *target, fn_env_pair *f) { - target->start(f->f, f->env, NULL); -} - -// This is called by an intrinsic on the Rust stack and must run -// entirely in the red zone. Do not call on the C stack. -extern "C" CDECL MUST_CHECK bool -rust_task_yield(rust_task *task, bool *killed) { - return task->yield(); -} - -extern "C" CDECL void -rust_set_exit_status(intptr_t code) { - rust_task *task = rust_get_current_task(); - task->kernel->set_exit_status((int)code); -} - -extern void log_console_on(); +static lock_and_signal log_lock; +static bool log_to_console = true; extern "C" CDECL void rust_log_console_on() { - log_console_on(); + scoped_lock with(log_lock); + log_to_console = true; } -extern void log_console_off(); - extern "C" CDECL void rust_log_console_off() { - log_console_off(); + scoped_lock with(log_lock); + log_to_console = false; } -extern bool should_log_console(); - extern "C" CDECL uintptr_t rust_should_log_console() { - return (uintptr_t)should_log_console(); -} - -extern "C" CDECL rust_sched_id -rust_osmain_sched_id() { - rust_task *task = rust_get_current_task(); - return task->kernel->osmain_sched_id(); -} - -extern "C" void -rust_task_inhibit_kill(rust_task *task) { - task->inhibit_kill(); -} - -extern "C" void -rust_task_allow_kill(rust_task *task) { - task->allow_kill(); -} - -extern "C" void -rust_task_inhibit_yield(rust_task *task) { - task->inhibit_yield(); -} - -extern "C" void -rust_task_allow_yield(rust_task *task) { - task->allow_yield(); -} - -extern "C" void -rust_task_kill_other(rust_task *task) { /* Used for linked failure */ - task->kill(); -} - -extern "C" void -rust_task_kill_all(rust_task *task) { /* Used for linked failure */ - task->fail_sched_loop(); - // This must not happen twice. - static bool main_taskgroup_failed = false; - assert(!main_taskgroup_failed); - main_taskgroup_failed = true; -} - -extern "C" CDECL -bool rust_task_is_unwinding(rust_task *rt) { - return rt->unwinding; + scoped_lock with(log_lock); + return log_to_console; } extern "C" lock_and_signal* @@ -561,71 +413,6 @@ rust_unlock_little_lock(lock_and_signal *lock) { lock->unlock(); } -// get/atexit task_local_data can run on the rust stack for speed. -extern "C" void ** -rust_get_task_local_data(rust_task *task) { - return &task->task_local_data; -} -extern "C" void -rust_task_local_data_atexit(rust_task *task, void (*cleanup_fn)(void *data)) { - task->task_local_data_cleanup = cleanup_fn; -} - -// set/get/atexit task_borrow_list can run on the rust stack for speed. -extern "C" void * -rust_take_task_borrow_list(rust_task *task) { - void *r = task->borrow_list; - task->borrow_list = NULL; - return r; -} -extern "C" void -rust_set_task_borrow_list(rust_task *task, void *data) { - assert(task->borrow_list == NULL); - assert(data != NULL); - task->borrow_list = data; -} - -extern "C" void -task_clear_event_reject(rust_task *task) { - task->clear_event_reject(); -} - -// Waits on an event, returning the pointer to the event that unblocked this -// task. -extern "C" MUST_CHECK bool -task_wait_event(rust_task *task, void **result) { - // Maybe (if not too slow) assert that the passed in task is the currently - // running task. We wouldn't want to wait some other task. - - return task->wait_event(result); -} - -extern "C" void -task_signal_event(rust_task *target, void *event) { - target->signal_event(event); -} - -// Can safely run on the rust stack. -extern "C" void -rust_task_ref(rust_task *task) { - task->ref(); -} - -// Don't run on the rust stack! -extern "C" void -rust_task_deref(rust_task *task) { - task->deref(); -} - -// Don't run on the Rust stack! -extern "C" void -rust_log_str(uint32_t level, const char *str, size_t size) { - rust_task *task = rust_get_current_task(); - task->sched_loop->get_log().log(task, level, "%.*s", (int)size, str); -} - -extern "C" CDECL void record_sp_limit(void *limit); - class raw_thread: public rust_thread { public: fn_env_pair fn; @@ -684,12 +471,6 @@ rust_readdir() { #endif -extern "C" rust_env* -rust_get_rt_env() { - rust_task *task = rust_get_current_task(); - return task->kernel->env; -} - #ifndef _WIN32 pthread_key_t rt_key = -1; #else @@ -738,12 +519,6 @@ rust_delete_memory_region(memory_region *region) { } extern "C" CDECL boxed_region* -rust_current_boxed_region() { - rust_task *task = rust_get_current_task(); - return &task->boxed; -} - -extern "C" CDECL boxed_region* rust_new_boxed_region(memory_region *region, uintptr_t poison_on_free) { return new boxed_region(region, poison_on_free); @@ -848,6 +623,12 @@ rust_drop_change_dir_lock() { change_dir_lock.unlock(); } +// Used by i386 __morestack +extern "C" CDECL uintptr_t +rust_get_task() { + return 0; +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_crate_map.h b/src/rt/rust_crate_map.h index 64d17ebc3ad..80b969d6f6d 100644 --- a/src/rt/rust_crate_map.h +++ b/src/rt/rust_crate_map.h @@ -11,7 +11,7 @@ #ifndef RUST_CRATE_MAP_H #define RUST_CRATE_MAP_H -#include "rust_log.h" +#include "rust_globals.h" #include <stdint.h> struct mod_entry { diff --git a/src/rt/rust_debug.cpp b/src/rt/rust_debug.cpp deleted file mode 100644 index f403b0434b6..00000000000 --- a/src/rt/rust_debug.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Routines useful when debugging the Rust runtime. - -#include "rust_globals.h" -#include "rust_abi.h" -#include "rust_debug.h" -#include "rust_task.h" - -#include <iostream> -#include <string> -#include <sstream> - -namespace { - -debug::flag track_origins("RUST_TRACK_ORIGINS"); - -} // end anonymous namespace - -namespace debug { - -void -maybe_track_origin(rust_task *task, void *ptr) { - if (!*track_origins) - return; - task->debug.origins[ptr] = - stack_walk::symbolicate(stack_walk::backtrace()); -} - -void -maybe_untrack_origin(rust_task *task, void *ptr) { - if (!*track_origins) - return; - task->debug.origins.erase(ptr); -} - -// This function is intended to be called by the debugger. -void -dump_origin(rust_task *task, void *ptr) { - if (!*track_origins) { - std::cerr << "Try again with RUST_TRACK_ORIGINS=1." << std::endl; - } else if (task->debug.origins.find(ptr) == task->debug.origins.end()) { - std::cerr << "Pointer " << std::hex << (uintptr_t)ptr << - " does not have a tracked origin." << std::endl; - } else { - std::cerr << "Origin of pointer " << std::hex << (uintptr_t)ptr << - ":" << std::endl << task->debug.origins[ptr] << - std::endl; - } -} - -} // end namespace debug diff --git a/src/rt/rust_debug.h b/src/rt/rust_debug.h deleted file mode 100644 index 951d2c36cb8..00000000000 --- a/src/rt/rust_debug.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Routines useful when debugging the Rust runtime. - -#ifndef RUST_DEBUG_H -#define RUST_DEBUG_H - -#include <map> -#include <string> -#include <cstdlib> - -struct rust_task; - -namespace debug { - -class flag { -private: - const char *name; - bool valid; - bool value; - -public: - flag(const char *in_name) : name(in_name), valid(false) {} - - bool operator*() { - // FIXME (#2689): We ought to lock this. - if (!valid) { - char *ev = getenv(name); - value = ev && ev[0] != '\0' && ev[0] != '0'; - valid = true; - } - return value; - } -}; - -class task_debug_info { -public: - std::map<void *,std::string> origins; -}; - -std::string backtrace(); - -void maybe_track_origin(rust_task *task, void *ptr); -void maybe_untrack_origin(rust_task *task, void *ptr); - -// This function is intended to be called by the debugger. -void dump_origin(rust_task *task, void *ptr); - -} // end namespace debug - -#endif diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp deleted file mode 100644 index 814cfbb310a..00000000000 --- a/src/rt/rust_kernel.cpp +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - - -#include "rust_kernel.h" -#include "rust_util.h" -#include "rust_scheduler.h" -#include "rust_sched_launcher.h" -#include <algorithm> - -#define KLOG_(...) \ - KLOG(this, kern, __VA_ARGS__) -#define KLOG_ERR_(field, ...) \ - KLOG_LVL(this, field, log_err, __VA_ARGS__) - -rust_kernel::rust_kernel(rust_env *env) : - _log(NULL), - max_task_id(INIT_TASK_ID-1), // sync_add_and_fetch increments first - rval(0), - max_sched_id(1), - killed(false), - already_exiting(false), - sched_reaper(this), - osmain_driver(NULL), - non_weak_tasks(0), - env(env) -{ - // Create the single threaded scheduler that will run on the platform's - // main thread - rust_manual_sched_launcher_factory *osmain_launchfac = - new rust_manual_sched_launcher_factory(); - osmain_scheduler = create_scheduler(osmain_launchfac, 1, false); - osmain_driver = osmain_launchfac->get_driver(); - - // Create the primary scheduler - rust_thread_sched_launcher_factory *main_launchfac = - new rust_thread_sched_launcher_factory(); - main_scheduler = create_scheduler(main_launchfac, - env->num_sched_threads, - false); - - sched_reaper.start(); -} - -void -rust_kernel::log(uint32_t level, char const *fmt, ...) { - char buf[BUF_BYTES]; - va_list args; - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - _log.trace_ln(NULL, level, buf); - va_end(args); -} - -void -rust_kernel::fatal(char const *fmt, ...) { - char buf[BUF_BYTES]; - va_list args; - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - _log.trace_ln(NULL, (uint32_t)0, buf); - exit(1); - va_end(args); -} - -void * -rust_kernel::malloc(size_t size, const char *tag) { - return exchange_alloc.malloc(size); -} - -void * -rust_kernel::realloc(void *mem, size_t size) { - return exchange_alloc.realloc(mem, size); -} - -void rust_kernel::free(void *mem) { - exchange_alloc.free(mem); -} - -rust_sched_id -rust_kernel::create_scheduler(size_t num_threads) { - rust_thread_sched_launcher_factory *launchfac = - new rust_thread_sched_launcher_factory(); - return create_scheduler(launchfac, num_threads, true); -} - -rust_sched_id -rust_kernel::create_scheduler(rust_sched_launcher_factory *launchfac, - size_t num_threads, bool allow_exit) { - rust_sched_id id; - rust_scheduler *sched; - { - scoped_lock with(sched_lock); - - /*if (sched_table.size() == 2) { - // The main and OS main schedulers may not exit while there are - // other schedulers - KLOG_("Disallowing main scheduler to exit"); - rust_scheduler *main_sched = - get_scheduler_by_id_nolock(main_scheduler); - assert(main_sched != NULL); - main_sched->disallow_exit(); - } - if (sched_table.size() == 1) { - KLOG_("Disallowing osmain scheduler to exit"); - rust_scheduler *osmain_sched = - get_scheduler_by_id_nolock(osmain_scheduler); - assert(osmain_sched != NULL); - osmain_sched->disallow_exit(); - }*/ - - id = max_sched_id++; - assert(id != INTPTR_MAX && "Hit the maximum scheduler id"); - sched = new (this, "rust_scheduler") - rust_scheduler(this, num_threads, id, allow_exit, killed, - launchfac); - bool is_new = sched_table - .insert(std::pair<rust_sched_id, - rust_scheduler*>(id, sched)).second; - assert(is_new && "Reusing a sched id?"); - } - sched->start_task_threads(); - return id; -} - -rust_scheduler * -rust_kernel::get_scheduler_by_id(rust_sched_id id) { - scoped_lock with(sched_lock); - return get_scheduler_by_id_nolock(id); -} - -rust_scheduler * -rust_kernel::get_scheduler_by_id_nolock(rust_sched_id id) { - if (id == 0) { - return NULL; - } - sched_lock.must_have_lock(); - sched_map::iterator iter = sched_table.find(id); - if (iter != sched_table.end()) { - return iter->second; - } else { - return NULL; - } -} - -void -rust_kernel::release_scheduler_id(rust_sched_id id) { - scoped_lock with(sched_lock); - join_list.push_back(id); - sched_lock.signal(); -} - -/* -Called by rust_sched_reaper to join every terminating scheduler thread, -so that we can be sure they have completely exited before the process exits. -If we don't join them then we can see valgrind errors due to un-freed pthread -memory. - */ -void -rust_kernel::wait_for_schedulers() -{ - scoped_lock with(sched_lock); - while (!sched_table.empty()) { - while (!join_list.empty()) { - rust_sched_id id = join_list.back(); - KLOG_("Deleting scheduler %d", id); - join_list.pop_back(); - sched_map::iterator iter = sched_table.find(id); - assert(iter != sched_table.end()); - rust_scheduler *sched = iter->second; - sched_table.erase(iter); - sched->join_task_threads(); - sched->deref(); - /*if (sched_table.size() == 2) { - KLOG_("Allowing main scheduler to exit"); - // It's only the main schedulers left. Tell them to exit - rust_scheduler *main_sched = - get_scheduler_by_id_nolock(main_scheduler); - assert(main_sched != NULL); - main_sched->allow_exit(); - } - if (sched_table.size() == 1) { - KLOG_("Allowing osmain scheduler to exit"); - rust_scheduler *osmain_sched = - get_scheduler_by_id_nolock(osmain_scheduler); - assert(osmain_sched != NULL); - osmain_sched->allow_exit(); - }*/ - } - if (!sched_table.empty()) { - sched_lock.wait(); - } - } -} - -/* Called on the main thread to run the osmain scheduler to completion, - then wait for schedulers to exit */ -int -rust_kernel::run() { - assert(osmain_driver != NULL); - osmain_driver->start_main_loop(); - sched_reaper.join(); - return rval; -} - -void -rust_kernel::fail() { - // FIXME (#908): On windows we're getting "Application has - // requested the Runtime to terminate it in an unusual way" when - // trying to shutdown cleanly. - set_exit_status(PROC_FAIL_CODE); -#if defined(__WIN32__) - exit(rval); -#endif - // I think this only needs to be done by one task ever; as it is, - // multiple tasks invoking kill_all might get here. Currently libcore - // ensures only one task will ever invoke it, but this would really be - // fine either way, so I'm leaving it as it is. -- bblum - - // Copy the list of schedulers so that we don't hold the lock while - // running kill_all_tasks. Refcount to ensure they stay alive. - std::vector<rust_scheduler*> scheds; - { - scoped_lock with(sched_lock); - // All schedulers created after this flag is set will be doomed. - killed = true; - for (sched_map::iterator iter = sched_table.begin(); - iter != sched_table.end(); iter++) { - iter->second->ref(); - scheds.push_back(iter->second); - } - } - - for (std::vector<rust_scheduler*>::iterator iter = scheds.begin(); - iter != scheds.end(); iter++) { - (*iter)->kill_all_tasks(); - (*iter)->deref(); - } -} - -rust_task_id -rust_kernel::generate_task_id() { - rust_task_id id = sync::increment(max_task_id); - assert(id != INTPTR_MAX && "Hit the maximum task id"); - return id; -} - -void -rust_kernel::set_exit_status(int code) { - scoped_lock with(rval_lock); - // If we've already failed then that's the code we're going to use - if (rval != PROC_FAIL_CODE) { - rval = code; - } -} - -void -rust_kernel::inc_live_count() { - uintptr_t new_non_weak_tasks = sync::increment(non_weak_tasks); - KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); -} - -void -rust_kernel::dec_live_count() { - uintptr_t new_non_weak_tasks = sync::decrement(non_weak_tasks); - KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); - if (new_non_weak_tasks == 0) { - begin_shutdown(); - } -} - -void -rust_kernel::allow_scheduler_exit() { - scoped_lock with(sched_lock); - - KLOG_("Allowing main scheduler to exit"); - // It's only the main schedulers left. Tell them to exit - rust_scheduler *main_sched = - get_scheduler_by_id_nolock(main_scheduler); - assert(main_sched != NULL); - main_sched->allow_exit(); - - KLOG_("Allowing osmain scheduler to exit"); - rust_scheduler *osmain_sched = - get_scheduler_by_id_nolock(osmain_scheduler); - assert(osmain_sched != NULL); - osmain_sched->allow_exit(); -} - -void -rust_kernel::begin_shutdown() { - { - scoped_lock with(sched_lock); - // FIXME #4410: This shouldn't be necessary, but because of - // unweaken_task this may end up getting called multiple times. - if (already_exiting) { - return; - } else { - already_exiting = true; - } - } - - allow_scheduler_exit(); -} - -// -// Local Variables: -// mode: C++ -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h deleted file mode 100644 index 0fe3f761040..00000000000 --- a/src/rt/rust_kernel.h +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -/** - A single runtime instance. - - The kernel is primarily responsible for managing the lifetime of - schedulers, which in turn run rust tasks. It provides a memory - allocator and logging service for use by other runtime components, - it creates unique task ids. - - The kernel runs until there are no live schedulers. - - The kernel internally runs an additional, special scheduler called - the 'osmain' (or platform) scheduler, which schedules tasks on the - thread that is running the kernel (normally the thread on which the - C main function was called). This scheduler may be used by Rust - code for interacting with platform APIs that insist on being called - from the main thread. - - The requirements of the osmain scheduler has resulted in a complex - process for creating and running scheduler loops that involves - a thing called a 'rust_sched_launcher_factory' whose function I've - already forgotten. rust_scheduler is the main scheduler class, - and tasks are scheduled on individual threads by rust_sched_loop. - - Ideally all the in-memory Rust state is encapsulated by a kernel - instance, but there is still some truly global data in the runtime - (like the check claims flag). - */ - -#ifndef RUST_KERNEL_H -#define RUST_KERNEL_H - -#include "rust_globals.h" - -#include <map> -#include <vector> - -#include "rust_exchange_alloc.h" -#include "rust_log.h" -#include "rust_sched_reaper.h" -#include "rust_type.h" -#include "sync/lock_and_signal.h" - -class rust_scheduler; -class rust_sched_driver; -class rust_sched_launcher_factory; -struct rust_task_thread; - -// Scheduler, task handles. These uniquely identify within a -// single kernel instance the objects they represent. -typedef intptr_t rust_sched_id; -typedef intptr_t rust_task_id; - -typedef std::map<rust_sched_id, rust_scheduler*> sched_map; - -class rust_kernel { - rust_exchange_alloc exchange_alloc; - rust_log _log; - - // The next task id - rust_task_id max_task_id; - - lock_and_signal rval_lock; - int rval; - - // Protects max_sched_id and sched_table, join_list, killed, - // already_exiting - lock_and_signal sched_lock; - // The next scheduler id - rust_sched_id max_sched_id; - // A map from scheduler ids to schedulers. When this is empty - // the kernel terminates - sched_map sched_table; - // A list of scheduler ids that are ready to exit - std::vector<rust_sched_id> join_list; - // Whether or not the runtime has to die (triggered when the root/main - // task group fails). This propagates to all new schedulers and tasks - // created after it is set. - bool killed; - bool already_exiting; - - - rust_sched_reaper sched_reaper; - - // The primary scheduler - rust_sched_id main_scheduler; - // The single-threaded scheduler that uses the main thread - rust_sched_id osmain_scheduler; - // Runs the single-threaded scheduler that executes tasks - // on the main thread - rust_sched_driver *osmain_driver; - - // An atomically updated count of the live, 'non-weak' tasks - uintptr_t non_weak_tasks; - - rust_scheduler* get_scheduler_by_id_nolock(rust_sched_id id); - void allow_scheduler_exit(); - void begin_shutdown(); - -public: - struct rust_env *env; - - rust_kernel(rust_env *env); - - void log(uint32_t level, char const *fmt, ...); - void fatal(char const *fmt, ...); - - void *malloc(size_t size, const char *tag); - void *realloc(void *mem, size_t size); - void free(void *mem); - rust_exchange_alloc *region() { return &exchange_alloc; } - - void fail(); - - rust_sched_id create_scheduler(size_t num_threads); - rust_sched_id create_scheduler(rust_sched_launcher_factory *launchfac, - size_t num_threads, bool allow_exit); - rust_scheduler* get_scheduler_by_id(rust_sched_id id); - // Called by a scheduler to indicate that it is terminating - void release_scheduler_id(rust_sched_id id); - void wait_for_schedulers(); - int run(); - - rust_task_id generate_task_id(); - - void set_exit_status(int code); - - rust_sched_id main_sched_id() { return main_scheduler; } - rust_sched_id osmain_sched_id() { return osmain_scheduler; } - - void inc_live_count(); - void dec_live_count(); - -}; - -template <typename T> struct kernel_owned { - inline void *operator new(size_t size, rust_kernel *kernel, - const char *tag) { - return kernel->malloc(size, tag); - } - - void operator delete(void *ptr) { - ((T *)ptr)->kernel->free(ptr); - } -}; - -#endif /* RUST_KERNEL_H */ - -// -// Local Variables: -// mode: C++ -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/rt/rust_log.cpp b/src/rt/rust_log.cpp index f7b117a8cb1..25b246c69f5 100644 --- a/src/rt/rust_log.cpp +++ b/src/rt/rust_log.cpp @@ -17,161 +17,6 @@ #include "rust_crate_map.h" #include "util/array_list.h" #include "rust_util.h" -#include "rust_task.h" - -/** - * Synchronizes access to the underlying logging mechanism. - */ -static lock_and_signal _log_lock; -/** - * Indicates whether we are outputting to the console. - * Protected by _log_lock; - */ -static bool _log_to_console = true; - -/* - * Request that console logging be turned on. - */ -void -log_console_on() { - scoped_lock with(_log_lock); - _log_to_console = true; -} - -/* - * Request that console logging be turned off. Can be - * overridden by the environment. - */ -void -log_console_off() { - scoped_lock with(_log_lock); - _log_to_console = false; -} - -bool -should_log_console() { - scoped_lock with(_log_lock); - return _log_to_console; -} - -rust_log::rust_log(rust_sched_loop *sched_loop) : - _sched_loop(sched_loop) { -} - -rust_log::~rust_log() { - -} - -const uint16_t -hash(uintptr_t ptr) { -# if(ULONG_MAX == 0xFFFFFFFF) - // Robert Jenkins' 32 bit integer hash function - ptr = (ptr + 0x7ed55d16) + (ptr << 12); - ptr = (ptr ^ 0xc761c23c) ^ (ptr >> 19); - ptr = (ptr + 0x165667b1) + (ptr << 5); - ptr = (ptr + 0xd3a2646c) ^ (ptr << 9); - ptr = (ptr + 0xfd7046c5) + (ptr << 3); - ptr = (ptr ^ 0xb55a4f09) ^ (ptr >> 16); -# elif(ULONG_MAX == 0xFFFFFFFFFFFFFFFF) - // "hash64shift()" from http://www.concentric.net/~Ttwang/tech/inthash.htm - ptr = (~ptr) + (ptr << 21); // ptr = (ptr << 21) - ptr - 1; - ptr = ptr ^ (ptr >> 24); - ptr = (ptr + (ptr << 3)) + (ptr << 8); // ptr * 265 - ptr = ptr ^ (ptr >> 14); - ptr = (ptr + (ptr << 2)) + (ptr << 4); // ptr * 21 - ptr = ptr ^ (ptr >> 28); - ptr = ptr + (ptr << 31); -# else -# error "hash() not defined for this pointer size" -# endif - return (uint16_t) ptr; -} - -char * -copy_string(char *dst, const char *src, size_t length) { - return strncpy(dst, src, length) + length; -} - -char * -append_string(char *buffer, const char *format, ...) { - if (buffer != NULL && format) { - va_list args; - va_start(args, format); - size_t off = strlen(buffer); - vsnprintf(buffer + off, BUF_BYTES - off, format, args); - va_end(args); - } - return buffer; -} - -void -rust_log::log(rust_task* task, uint32_t level, char const *fmt, ...) { - char buf[BUF_BYTES]; - va_list args; - va_start(args, fmt); - int formattedbytes = vsnprintf(buf, sizeof(buf), fmt, args); - if( formattedbytes and (unsigned)formattedbytes > BUF_BYTES ){ - const char truncatedstr[] = "[...]"; - memcpy( &buf[BUF_BYTES-sizeof(truncatedstr)], - truncatedstr, - sizeof(truncatedstr)); - } - trace_ln(task, level, buf); - va_end(args); -} - -void -rust_log::trace_ln(char *prefix, char *message) { - char buffer[BUF_BYTES] = ""; - _log_lock.lock(); - append_string(buffer, "%s", prefix); - append_string(buffer, "%s", message); - if (_log_to_console) { - fprintf(stderr, "rust: %s\n", buffer); - fflush(stderr); - } - _log_lock.unlock(); -} - -void -rust_log::trace_ln(rust_task *task, uint32_t level, char *message) { - - if (task) { - // There is not enough room to be logging on the rust stack - assert(!task->on_rust_stack() && "logging on rust stack"); - } - - // FIXME (#2672): The scheduler and task names used to have meaning, - // but they are always equal to 'main' currently -#if 0 - -#if defined(__WIN32__) - uint32_t thread_id = 0; -#else - uint32_t thread_id = hash((uintptr_t) pthread_self()); -#endif - - char prefix[BUF_BYTES] = ""; - if (_sched_loop && _sched_loop-.name) { - append_string(prefix, "%04" PRIxPTR ":%.10s:", - thread_id, _sched_loop->name); - } else { - append_string(prefix, "%04" PRIxPTR ":0x%08" PRIxPTR ":", - thread_id, (uintptr_t) _sched_loop); - } - if (task) { - if (task->name) { - append_string(prefix, "%.10s:", task->name); - } else { - append_string(prefix, "0x%08" PRIxPTR ":", (uintptr_t) task); - } - } -#else - char prefix[BUF_BYTES] = ""; -#endif - - trace_ln(prefix, message); -} // Reading log directives and setting log level vars diff --git a/src/rt/rust_log.h b/src/rt/rust_log.h index b98d8477dbc..e3d61b8ab5d 100644 --- a/src/rt/rust_log.h +++ b/src/rt/rust_log.h @@ -18,53 +18,6 @@ const uint32_t log_warn = 2; const uint32_t log_info = 3; const uint32_t log_debug = 4; -#define LOG(task, field, ...) \ - DLOG_LVL(log_debug, task, task->sched_loop, field, __VA_ARGS__) -#define LOG_ERR(task, field, ...) \ - DLOG_LVL(log_err, task, task->sched_loop, field, __VA_ARGS__) -#define DLOG(sched_loop, field, ...) \ - DLOG_LVL(log_debug, NULL, sched_loop, field, __VA_ARGS__) -#define DLOG_ERR(sched_loop, field, ...) \ - DLOG_LVL(log_err, NULL, sched_loop, field, __VA_ARGS__) -#define LOGPTR(sched_loop, msg, ptrval) \ - DLOG_LVL(log_debug, NULL, sched_loop, mem, "%s 0x%" PRIxPTR, msg, ptrval) -#define DLOG_LVL(lvl, task, sched_loop, field, ...) \ - do { \ - rust_sched_loop* _d_ = sched_loop; \ - if (log_rt_##field >= lvl && _d_->log_lvl >= lvl) { \ - _d_->get_log().log(task, lvl, __VA_ARGS__); \ - } \ - } while (0) - -#define KLOG(k, field, ...) \ - KLOG_LVL(k, field, log_debug, __VA_ARGS__) -#define KLOG_LVL(k, field, lvl, ...) \ - do { \ - if (log_rt_##field >= lvl) { \ - (k)->log(lvl, __VA_ARGS__); \ - } \ - } while (0) - -struct rust_sched_loop; -struct rust_task; - -class rust_log { - -public: - rust_log(rust_sched_loop *sched_loop); - virtual ~rust_log(); - - void log(rust_task* task, uint32_t level, char const *fmt, ...); - void trace_ln(rust_task *task, uint32_t level, char *message); - void trace_ln(char *prefix, char *message); - bool is_tracing(uint32_t type_bits); - -private: - rust_sched_loop *_sched_loop; - bool _use_labels; - void trace_ln(rust_task *task, char *message); -}; - void update_log_settings(void* crate_map, char* settings); extern uint32_t log_rt_mem; diff --git a/src/rt/rust_run_program.cpp b/src/rt/rust_run_program.cpp index 0ba76078691..25cbaf822f0 100644 --- a/src/rt/rust_run_program.cpp +++ b/src/rt/rust_run_program.cpp @@ -9,7 +9,7 @@ // except according to those terms. -#include "rust_kernel.h" +#include "rust_globals.h" #ifdef __APPLE__ #include <crt_externs.h> diff --git a/src/rt/rust_sched_driver.cpp b/src/rt/rust_sched_driver.cpp deleted file mode 100644 index c8f59b11ff3..00000000000 --- a/src/rt/rust_sched_driver.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -#include "rust_globals.h" -#include "rust_sched_driver.h" -#include "rust_sched_loop.h" - -rust_sched_driver::rust_sched_driver(rust_sched_loop *sched_loop) - : sched_loop(sched_loop), - signalled(false) { - - assert(sched_loop != NULL); - sched_loop->on_pump_loop(this); -} - -/** - * Starts the main scheduler loop which performs task scheduling for this - * domain. - * - * Returns once no more tasks can be scheduled and all task ref_counts - * drop to zero. - */ -void -rust_sched_driver::start_main_loop() { - assert(sched_loop != NULL); - -#ifdef __APPLE__ - { - char buf[64]; - snprintf(buf, sizeof(buf), "scheduler loop %d", sched_loop->get_id()); - // pthread_setname_np seems to have a different signature and - // different behavior on different platforms. Thus, this is - // only for Mac at the moment. There are equivalent versions - // for Linux that we can add if needed. - pthread_setname_np(buf); - } -#endif - - rust_sched_loop_state state = sched_loop_state_keep_going; - while (state != sched_loop_state_exit) { - DLOG(sched_loop, dom, "pumping scheduler"); - state = sched_loop->run_single_turn(); - - if (state == sched_loop_state_block) { - scoped_lock with(lock); - if (!signalled) { - DLOG(sched_loop, dom, "blocking scheduler"); - lock.wait(); - } - signalled = false; - } - } -} - -void -rust_sched_driver::signal() { - scoped_lock with(lock); - signalled = true; - lock.signal(); -} diff --git a/src/rt/rust_sched_driver.h b/src/rt/rust_sched_driver.h deleted file mode 100644 index 9824c5ee3d2..00000000000 --- a/src/rt/rust_sched_driver.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#ifndef RUST_SCHED_DRIVER_H -#define RUST_SCHED_DRIVER_H - -#include "sync/lock_and_signal.h" -#include "rust_signal.h" - -struct rust_sched_loop; - -class rust_sched_driver : public rust_signal { -private: - rust_sched_loop *sched_loop; - lock_and_signal lock; - bool signalled; - -public: - rust_sched_driver(rust_sched_loop *sched_loop); - - void start_main_loop(); - - virtual void signal(); -}; - -#endif /* RUST_SCHED_DRIVER_H */ diff --git a/src/rt/rust_sched_launcher.cpp b/src/rt/rust_sched_launcher.cpp deleted file mode 100644 index a95145343d4..00000000000 --- a/src/rt/rust_sched_launcher.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -#include "rust_sched_launcher.h" -#include "rust_scheduler.h" - -const size_t SCHED_STACK_SIZE = 1024*100; - -rust_sched_launcher::rust_sched_launcher(rust_scheduler *sched, int id, - bool killed) - : kernel(sched->kernel), - sched_loop(sched, id, killed), - driver(&sched_loop) { -} - -rust_thread_sched_launcher::rust_thread_sched_launcher(rust_scheduler *sched, - int id, bool killed) - : rust_sched_launcher(sched, id, killed), - rust_thread(SCHED_STACK_SIZE) { -} - -rust_manual_sched_launcher::rust_manual_sched_launcher(rust_scheduler *sched, - int id, bool killed) - : rust_sched_launcher(sched, id, killed) { -} - -rust_sched_launcher * -rust_thread_sched_launcher_factory::create(rust_scheduler *sched, int id, - bool killed) { - return new(sched->kernel, "rust_thread_sched_launcher") - rust_thread_sched_launcher(sched, id, killed); -} - -rust_sched_launcher * -rust_manual_sched_launcher_factory::create(rust_scheduler *sched, int id, - bool killed) { - assert(launcher == NULL && "I can only track one sched_launcher"); - launcher = new(sched->kernel, "rust_manual_sched_launcher") - rust_manual_sched_launcher(sched, id, killed); - return launcher; -} diff --git a/src/rt/rust_sched_launcher.h b/src/rt/rust_sched_launcher.h deleted file mode 100644 index a981fad24f8..00000000000 --- a/src/rt/rust_sched_launcher.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#ifndef RUST_SCHED_LAUNCHER_H -#define RUST_SCHED_LAUNCHER_H - -#include "sync/rust_thread.h" -#include "rust_sched_driver.h" -#include "rust_kernel.h" -#include "rust_sched_loop.h" - -class rust_sched_launcher : public kernel_owned<rust_sched_launcher> { -public: - rust_kernel *kernel; - -private: - rust_sched_loop sched_loop; - -private: - // private and undefined to disable copying - rust_sched_launcher(const rust_sched_launcher& rhs); - rust_sched_launcher& operator=(const rust_sched_launcher& rhs); - -protected: - rust_sched_driver driver; - -public: - rust_sched_launcher(rust_scheduler *sched, int id, bool killed); - virtual ~rust_sched_launcher() { } - - virtual void start() = 0; - virtual void join() = 0; - rust_sched_loop *get_loop() { return &sched_loop; } -}; - -class rust_thread_sched_launcher - :public rust_sched_launcher, - private rust_thread { -public: - rust_thread_sched_launcher(rust_scheduler *sched, int id, bool killed); - virtual void start() { rust_thread::start(); } - virtual void join() { rust_thread::join(); } - virtual void run() { driver.start_main_loop(); } -}; - -class rust_manual_sched_launcher : public rust_sched_launcher { -public: - rust_manual_sched_launcher(rust_scheduler *sched, int id, bool killed); - virtual void start() { } - virtual void join() { } - rust_sched_driver *get_driver() { return &driver; }; -}; - -class rust_sched_launcher_factory { -public: - virtual ~rust_sched_launcher_factory() { } - virtual rust_sched_launcher * - create(rust_scheduler *sched, int id, bool killed) = 0; -}; - -class rust_thread_sched_launcher_factory - : public rust_sched_launcher_factory { -public: - virtual rust_sched_launcher *create(rust_scheduler *sched, int id, - bool killed); -}; - -class rust_manual_sched_launcher_factory - : public rust_sched_launcher_factory { -private: - rust_manual_sched_launcher *launcher; -public: - rust_manual_sched_launcher_factory() : launcher(NULL) { } - virtual rust_sched_launcher *create(rust_scheduler *sched, int id, - bool killed); - rust_sched_driver *get_driver() { - assert(launcher != NULL); - return launcher->get_driver(); - } -}; - -#endif // RUST_SCHED_LAUNCHER_H diff --git a/src/rt/rust_sched_loop.cpp b/src/rt/rust_sched_loop.cpp deleted file mode 100644 index 1f718df32aa..00000000000 --- a/src/rt/rust_sched_loop.cpp +++ /dev/null @@ -1,431 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -#include "rust_sched_loop.h" -#include "rust_util.h" -#include "rust_scheduler.h" - -#ifndef _WIN32 -pthread_key_t rust_sched_loop::task_key; -#else -DWORD rust_sched_loop::task_key; -#endif - -const size_t C_STACK_SIZE = 2*1024*1024; - -bool rust_sched_loop::tls_initialized = false; - -rust_sched_loop::rust_sched_loop(rust_scheduler *sched, int id, bool killed) : - _log(this), - id(id), - should_exit(false), - cached_c_stack(NULL), - extra_c_stack(NULL), - cached_big_stack(NULL), - extra_big_stack(NULL), - dead_task(NULL), - killed(killed), - pump_signal(NULL), - kernel(sched->kernel), - sched(sched), - log_lvl(log_debug), - min_stack_size(kernel->env->min_stack_size), - local_region(false, kernel->env->detailed_leaks, kernel->env->poison_on_free), - // FIXME #2891: calculate a per-scheduler name. - name("main") -{ - LOGPTR(this, "new dom", (uintptr_t)this); - rng_init(&rng, kernel->env->rust_seed, NULL, 0); - - if (!tls_initialized) - init_tls(); -} - -void -rust_sched_loop::activate(rust_task *task) { - lock.must_have_lock(); - task->ctx.next = &c_context; - DLOG(this, task, "descheduling..."); - lock.unlock(); - prepare_c_stack(task); - task->ctx.swap(c_context); - task->cleanup_after_turn(); - unprepare_c_stack(); - lock.lock(); - DLOG(this, task, "task has returned"); -} - - -void -rust_sched_loop::fail() { - _log.log(NULL, log_err, "domain %s @0x%" PRIxPTR " root task failed", - name, this); - kernel->fail(); -} - -void -rust_sched_loop::kill_all_tasks() { - std::vector<rust_task*> all_tasks; - - { - scoped_lock with(lock); - // Any task created after this will be killed. See transition, below. - killed = true; - - for (size_t i = 0; i < running_tasks.length(); i++) { - rust_task *t = running_tasks[i]; - t->ref(); - all_tasks.push_back(t); - } - - for (size_t i = 0; i < blocked_tasks.length(); i++) { - rust_task *t = blocked_tasks[i]; - t->ref(); - all_tasks.push_back(t); - } - } - - while (!all_tasks.empty()) { - rust_task *task = all_tasks.back(); - all_tasks.pop_back(); - task->kill(); - task->deref(); - } -} - -size_t -rust_sched_loop::number_of_live_tasks() { - lock.must_have_lock(); - return running_tasks.length() + blocked_tasks.length(); -} - -/** - * Delete any dead tasks. - */ -void -rust_sched_loop::reap_dead_tasks() { - lock.must_have_lock(); - - if (dead_task == NULL) { - return; - } - - // Dereferencing the task will probably cause it to be released - // from the scheduler, which may end up trying to take this lock - lock.unlock(); - - dead_task->delete_all_stacks(); - // Deref the task, which may cause it to request us to release it - dead_task->deref(); - dead_task = NULL; - - lock.lock(); -} - -void -rust_sched_loop::release_task(rust_task *task) { - // Nobody should have a ref to the task at this point - assert(task->get_ref_count() == 0); - // Now delete the task, which will require using this thread's - // memory region. - delete task; - // Now release the task from the scheduler, which may trigger this - // thread to exit - sched->release_task(); -} - -/** - * Schedules a running task for execution. Only running tasks can be - * activated. Blocked tasks have to be unblocked before they can be - * activated. - * - * Returns NULL if no tasks can be scheduled. - */ -rust_task * -rust_sched_loop::schedule_task() { - lock.must_have_lock(); - size_t tasks = running_tasks.length(); - if (tasks > 0) { - size_t i = (tasks > 1) ? (rng_gen_u32(&rng) % tasks) : 0; - return running_tasks[i]; - } - return NULL; -} - -void -rust_sched_loop::log_state() { - if (log_rt_task < log_debug) return; - - if (!running_tasks.is_empty()) { - _log.log(NULL, log_debug, "running tasks:"); - for (size_t i = 0; i < running_tasks.length(); i++) { - _log.log(NULL, log_debug, "\t task: %s @0x%" PRIxPTR, - running_tasks[i]->name, - running_tasks[i]); - } - } - - if (!blocked_tasks.is_empty()) { - _log.log(NULL, log_debug, "blocked tasks:"); - for (size_t i = 0; i < blocked_tasks.length(); i++) { - _log.log(NULL, log_debug, "\t task: %s @0x%" PRIxPTR - ", blocked on: 0x%" PRIxPTR " '%s'", - blocked_tasks[i]->name, blocked_tasks[i], - blocked_tasks[i]->get_cond(), - blocked_tasks[i]->get_cond_name()); - } - } -} - -void -rust_sched_loop::on_pump_loop(rust_signal *signal) { - assert(pump_signal == NULL); - assert(signal != NULL); - pump_signal = signal; -} - -void -rust_sched_loop::pump_loop() { - assert(pump_signal != NULL); - pump_signal->signal(); -} - -rust_sched_loop_state -rust_sched_loop::run_single_turn() { - DLOG(this, task, - "scheduler %d resuming ...", id); - - lock.lock(); - - if (!should_exit) { - assert(dead_task == NULL && "Tasks should only die after running"); - - DLOG(this, dom, "worker %d, number_of_live_tasks = %d", - id, number_of_live_tasks()); - - rust_task *scheduled_task = schedule_task(); - - if (scheduled_task == NULL) { - log_state(); - DLOG(this, task, - "all tasks are blocked, scheduler id %d yielding ...", - id); - - lock.unlock(); - return sched_loop_state_block; - } - - scheduled_task->assert_is_running(); - - DLOG(this, task, - "activating task %s 0x%" PRIxPTR - ", state: %s", - scheduled_task->name, - (uintptr_t)scheduled_task, - state_name(scheduled_task->get_state())); - - place_task_in_tls(scheduled_task); - - DLOG(this, task, - "Running task %p on worker %d", - scheduled_task, id); - activate(scheduled_task); - - DLOG(this, task, - "returned from task %s @0x%" PRIxPTR - " in state '%s', worker id=%d" PRIxPTR, - scheduled_task->name, - (uintptr_t)scheduled_task, - state_name(scheduled_task->get_state()), - id); - - reap_dead_tasks(); - - lock.unlock(); - return sched_loop_state_keep_going; - } else { - assert(running_tasks.is_empty() && "Should have no running tasks"); - assert(blocked_tasks.is_empty() && "Should have no blocked tasks"); - assert(dead_task == NULL && "Should have no dead tasks"); - - DLOG(this, dom, "finished main-loop %d", id); - - lock.unlock(); - - assert(!extra_c_stack); - if (cached_c_stack) { - destroy_exchange_stack(kernel->region(), cached_c_stack); - cached_c_stack = NULL; - } - assert(!extra_big_stack); - if (cached_big_stack) { - destroy_exchange_stack(kernel->region(), cached_big_stack); - cached_big_stack = NULL; - } - - sched->release_task_thread(); - return sched_loop_state_exit; - } -} - -rust_task * -rust_sched_loop::create_task(rust_task *spawner, const char *name) { - rust_task *task = - new (this->kernel, "rust_task") - rust_task(this, task_state_newborn, - name, kernel->env->min_stack_size); - DLOG(this, task, "created task: " PTR ", spawner: %s, name: %s", - task, spawner ? spawner->name : "(none)", name); - - task->id = kernel->generate_task_id(); - return task; -} - -rust_task_list * -rust_sched_loop::state_list(rust_task_state state) { - switch (state) { - case task_state_running: - return &running_tasks; - case task_state_blocked: - return &blocked_tasks; - default: - return NULL; - } -} - -const char * -rust_sched_loop::state_name(rust_task_state state) { - switch (state) { - case task_state_newborn: - return "newborn"; - case task_state_running: - return "running"; - case task_state_blocked: - return "blocked"; - case task_state_dead: - return "dead"; - default: - assert(false); - return ""; - } -} - -void -rust_sched_loop::transition(rust_task *task, - rust_task_state src, rust_task_state dst, - rust_cond *cond, const char* cond_name) { - scoped_lock with(lock); - DLOG(this, task, - "task %s " PTR " state change '%s' -> '%s' while in '%s'", - name, (uintptr_t)this, state_name(src), state_name(dst), - state_name(task->get_state())); - assert(task->get_state() == src); - rust_task_list *src_list = state_list(src); - if (src_list) { - src_list->remove(task); - } - rust_task_list *dst_list = state_list(dst); - if (dst_list) { - dst_list->append(task); - } - if (dst == task_state_dead) { - assert(dead_task == NULL); - dead_task = task; - } - task->set_state(dst, cond, cond_name); - - // If the entire runtime is failing, newborn tasks must be doomed. - if (src == task_state_newborn && killed) { - task->kill_inner(); - } - - pump_loop(); -} - -#ifndef _WIN32 -void -rust_sched_loop::init_tls() { - int result = pthread_key_create(&task_key, NULL); - assert(!result && "Couldn't create the TLS key!"); - tls_initialized = true; -} - -void -rust_sched_loop::place_task_in_tls(rust_task *task) { - int result = pthread_setspecific(task_key, task); - assert(!result && "Couldn't place the task in TLS!"); - task->record_stack_limit(); -} -#else -void -rust_sched_loop::init_tls() { - task_key = TlsAlloc(); - assert(task_key != TLS_OUT_OF_INDEXES && "Couldn't create the TLS key!"); - tls_initialized = true; -} - -void -rust_sched_loop::place_task_in_tls(rust_task *task) { - BOOL result = TlsSetValue(task_key, task); - assert(result && "Couldn't place the task in TLS!"); - task->record_stack_limit(); -} -#endif - -void -rust_sched_loop::exit() { - scoped_lock with(lock); - DLOG(this, dom, "Requesting exit for thread %d", id); - should_exit = true; - pump_loop(); -} - -// Before activating each task, make sure we have a C stack available. -// It needs to be allocated ahead of time (while we're on our own -// stack), because once we're on the Rust stack we won't have enough -// room to do the allocation -void -rust_sched_loop::prepare_c_stack(rust_task *task) { - assert(!extra_c_stack); - if (!cached_c_stack && !task->have_c_stack()) { - cached_c_stack = create_exchange_stack(kernel->region(), - C_STACK_SIZE); - } - assert(!extra_big_stack); - if (!cached_big_stack) { - cached_big_stack = create_exchange_stack(kernel->region(), - C_STACK_SIZE + - (C_STACK_SIZE * 2)); - cached_big_stack->is_big = 1; - } -} - -void -rust_sched_loop::unprepare_c_stack() { - if (extra_c_stack) { - destroy_exchange_stack(kernel->region(), extra_c_stack); - extra_c_stack = NULL; - } - if (extra_big_stack) { - destroy_exchange_stack(kernel->region(), extra_big_stack); - extra_big_stack = NULL; - } -} - -// -// Local Variables: -// mode: C++ -// fill-column: 70; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/rt/rust_sched_loop.h b/src/rt/rust_sched_loop.h deleted file mode 100644 index e0101c46fb9..00000000000 --- a/src/rt/rust_sched_loop.h +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#ifndef RUST_SCHED_LOOP_H -#define RUST_SCHED_LOOP_H - -#include "rust_globals.h" -#include "rust_log.h" -#include "rust_rng.h" -#include "rust_stack.h" -#include "rust_signal.h" -#include "context.h" -#include "util/indexed_list.h" - -enum rust_task_state { - task_state_newborn, - task_state_running, - task_state_blocked, - task_state_dead -}; - -/* -The result of every turn of the scheduler loop. Instructs the loop -driver how to proceed. - */ -enum rust_sched_loop_state { - sched_loop_state_keep_going, - sched_loop_state_block, - sched_loop_state_exit -}; - -class rust_kernel; -class rust_scheduler; -struct rust_task; - -typedef indexed_list<rust_task> rust_task_list; - -struct rust_sched_loop -{ -private: - - lock_and_signal lock; - - // Fields known only by the runtime: - rust_log _log; - - const int id; - - static bool tls_initialized; - -#ifndef __WIN32__ - static pthread_key_t task_key; -#else - static DWORD task_key; -#endif - - context c_context; - rust_rng rng; - bool should_exit; - - stk_seg *cached_c_stack; - stk_seg *extra_c_stack; - stk_seg *cached_big_stack; - stk_seg *extra_big_stack; - - rust_task_list running_tasks; - rust_task_list blocked_tasks; - rust_task *dead_task; - bool killed; - - rust_signal *pump_signal; - - void prepare_c_stack(rust_task *task); - void unprepare_c_stack(); - - rust_task_list *state_list(rust_task_state state); - const char *state_name(rust_task_state state); - - void pump_loop(); - -private: - // private and undefined to disable copying - rust_sched_loop(const rust_sched_loop& rhs); - rust_sched_loop& operator=(const rust_sched_loop& rhs); - -public: - rust_kernel *kernel; - rust_scheduler *sched; - - // NB: this is used to filter *runtime-originating* debug - // logging, on a per-scheduler basis. It's not likely what - // you want to expose to the user in terms of per-task - // or per-module logging control. By default all schedulers - // are set to debug-level logging here, and filtered by - // runtime category using the pseudo-modules ::rt::foo. - uint32_t log_lvl; - - size_t min_stack_size; - memory_region local_region; - - const char *const name; // Used for debugging - - // Only a pointer to 'name' is kept, so it must live as long as this - // domain. - rust_sched_loop(rust_scheduler *sched, int id, bool killed); - void activate(rust_task *task); - rust_log & get_log(); - void fail(); - - size_t number_of_live_tasks(); - - void reap_dead_tasks(); - rust_task *schedule_task(); - - void on_pump_loop(rust_signal *signal); - rust_sched_loop_state run_single_turn(); - - void log_state(); - - void kill_all_tasks(); - bool doomed(); - - rust_task *create_task(rust_task *spawner, const char *name); - - void transition(rust_task *task, - rust_task_state src, rust_task_state dst, - rust_cond *cond, const char* cond_name); - - void init_tls(); - void place_task_in_tls(rust_task *task); - - static rust_task *get_task_tls(); - static rust_task *try_get_task_tls(); - - // Called by each task when they are ready to be destroyed - void release_task(rust_task *task); - - // Tells the scheduler to exit it's scheduling loop and thread - void exit(); - - // Called by tasks when they need a stack on which to run C code - stk_seg *borrow_c_stack(); - void return_c_stack(stk_seg *stack); - - // Called by tasks when they need a big stack - stk_seg *borrow_big_stack(); - void return_big_stack(stk_seg *stack); - - int get_id() { return this->id; } -}; - -inline rust_log & -rust_sched_loop::get_log() { - return _log; -} - -inline rust_task* rust_sched_loop::try_get_task_tls() -{ - if (!tls_initialized) - return NULL; -#ifdef __WIN32__ - rust_task *task = reinterpret_cast<rust_task *> - (TlsGetValue(task_key)); -#else - rust_task *task = reinterpret_cast<rust_task *> - (pthread_getspecific(task_key)); -#endif - return task; -} - -inline rust_task* rust_sched_loop::get_task_tls() -{ - rust_task *task = try_get_task_tls(); - assert(task && "Couldn't get the task from TLS!"); - return task; -} - -// NB: Runs on the Rust stack -inline stk_seg * -rust_sched_loop::borrow_c_stack() { - assert(cached_c_stack); - stk_seg *your_stack; - if (extra_c_stack) { - your_stack = extra_c_stack; - extra_c_stack = NULL; - } else { - your_stack = cached_c_stack; - cached_c_stack = NULL; - } - return your_stack; -} - -// NB: Runs on the Rust stack -inline void -rust_sched_loop::return_c_stack(stk_seg *stack) { - assert(!extra_c_stack); - if (!cached_c_stack) { - cached_c_stack = stack; - } else { - extra_c_stack = stack; - } -} - -// NB: Runs on the Rust stack. Might return NULL! -inline stk_seg * -rust_sched_loop::borrow_big_stack() { - stk_seg *your_stack; - if (extra_big_stack) { - your_stack = extra_big_stack; - extra_big_stack = NULL; - } else { - // NB: This may be null if we're asking for a *second* - // big stack, in which case the caller will fall back to a slow path - your_stack = cached_big_stack; - cached_big_stack = NULL; - } - return your_stack; -} - -// NB: Runs on the Rust stack -inline void -rust_sched_loop::return_big_stack(stk_seg *stack) { - assert(!extra_big_stack); - assert(stack); - if (!cached_big_stack) - cached_big_stack = stack; - else - extra_big_stack = stack; -} - -// this is needed to appease the circular dependency gods -#include "rust_task.h" - -// -// Local Variables: -// mode: C++ -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; -// End: -// - -#endif /* RUST_SCHED_LOOP_H */ diff --git a/src/rt/rust_scheduler.cpp b/src/rt/rust_scheduler.cpp deleted file mode 100644 index e3a5d9db91f..00000000000 --- a/src/rt/rust_scheduler.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -#include "rust_globals.h" -#include "rust_scheduler.h" -#include "rust_task.h" -#include "rust_util.h" -#include "rust_sched_launcher.h" - -rust_scheduler::rust_scheduler(rust_kernel *kernel, - size_t max_num_threads, - rust_sched_id id, - bool allow_exit, - bool killed, - rust_sched_launcher_factory *launchfac) : - ref_count(1), - kernel(kernel), - live_threads(0), - live_tasks(0), - cur_thread(0), - may_exit(allow_exit), - killed(killed), - launchfac(launchfac), - max_num_threads(max_num_threads), - id(id) -{ - // Create the first thread - scoped_lock with(lock); - threads.push(create_task_thread(0)); -} - -void rust_scheduler::delete_this() { - destroy_task_threads(); - delete launchfac; - delete this; -} - -rust_sched_launcher * -rust_scheduler::create_task_thread(int id) { - lock.must_have_lock(); - live_threads++; - rust_sched_launcher *thread = launchfac->create(this, id, killed); - KLOG(kernel, kern, "created task thread: " PTR - ", id: %d, live_threads: %d", - thread, id, live_threads); - return thread; -} - -void -rust_scheduler::destroy_task_thread(rust_sched_launcher *thread) { - KLOG(kernel, kern, "deleting task thread: " PTR, thread); - delete thread; -} - -void -rust_scheduler::destroy_task_threads() { - scoped_lock with(lock); - for(size_t i = 0; i < threads.size(); ++i) { - destroy_task_thread(threads[i]); - } -} - -void -rust_scheduler::start_task_threads() -{ - scoped_lock with(lock); - for(size_t i = 0; i < threads.size(); ++i) { - rust_sched_launcher *thread = threads[i]; - thread->start(); - } -} - -void -rust_scheduler::join_task_threads() -{ - scoped_lock with(lock); - for(size_t i = 0; i < threads.size(); ++i) { - rust_sched_launcher *thread = threads[i]; - thread->join(); - } -} - -void -rust_scheduler::kill_all_tasks() { - array_list<rust_sched_launcher *> copied_threads; - { - scoped_lock with(lock); - killed = true; - for (size_t i = 0; i < threads.size(); ++i) { - copied_threads.push(threads[i]); - } - } - for(size_t i = 0; i < copied_threads.size(); ++i) { - rust_sched_launcher *thread = copied_threads[i]; - thread->get_loop()->kill_all_tasks(); - } -} - -rust_task * -rust_scheduler::create_task(rust_task *spawner, const char *name) { - size_t thread_no; - { - scoped_lock with(lock); - live_tasks++; - - if (cur_thread < threads.size()) { - thread_no = cur_thread; - } else { - assert(threads.size() < max_num_threads); - thread_no = threads.size(); - rust_sched_launcher *thread = create_task_thread(thread_no); - thread->start(); - threads.push(thread); - } - cur_thread = (thread_no + 1) % max_num_threads; - } - KLOG(kernel, kern, "Creating task %s, on thread %d.", name, thread_no); - kernel->inc_live_count(); - rust_sched_launcher *thread = threads[thread_no]; - return thread->get_loop()->create_task(spawner, name); -} - -void -rust_scheduler::release_task() { - bool need_exit = false; - { - scoped_lock with(lock); - live_tasks--; - if (live_tasks == 0 && may_exit) { - need_exit = true; - } - } - kernel->dec_live_count(); - if (need_exit) { - exit(); - } -} - -void -rust_scheduler::exit() { - // Take a copy of the number of threads. After the last thread exits this - // scheduler will get destroyed, and our fields will cease to exist. - // - // This is also the reason we can't use the lock here (as in the other - // cases when accessing `threads`), after the loop the lock won't exist - // anymore. This is safe because this method is only called when all the - // task are dead, so there is no chance of a task trying to create new - // threads. - size_t current_num_threads = threads.size(); - for(size_t i = 0; i < current_num_threads; ++i) { - threads[i]->get_loop()->exit(); - } -} - -size_t -rust_scheduler::max_number_of_threads() { - return max_num_threads; -} - -size_t -rust_scheduler::number_of_threads() { - scoped_lock with(lock); - return threads.size(); -} - -void -rust_scheduler::release_task_thread() { - uintptr_t new_live_threads; - { - scoped_lock with(lock); - new_live_threads = --live_threads; - } - if (new_live_threads == 0) { - kernel->release_scheduler_id(id); - } -} - -void -rust_scheduler::allow_exit() { - bool need_exit = false; - { - scoped_lock with(lock); - may_exit = true; - need_exit = live_tasks == 0; - } - if (need_exit) { - exit(); - } -} - -void -rust_scheduler::disallow_exit() { - scoped_lock with(lock); - may_exit = false; -} diff --git a/src/rt/rust_scheduler.h b/src/rt/rust_scheduler.h deleted file mode 100644 index 30e0626ddd3..00000000000 --- a/src/rt/rust_scheduler.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/** - The rust scheduler. Schedulers may be added to the kernel - dynamically and they run until there are no more tasks to - schedule. Most of the scheduler work is carried out in worker - threads by rust_sched_loop. - */ - -#ifndef RUST_SCHEDULER_H -#define RUST_SCHEDULER_H - -#include "rust_globals.h" -#include "util/array_list.h" -#include "rust_kernel.h" -#include "rust_refcount.h" - -class rust_sched_launcher; -class rust_sched_launcher_factory; - -class rust_scheduler : public kernel_owned<rust_scheduler> { - RUST_ATOMIC_REFCOUNT(); - // FIXME (#2693): Make these private -public: - rust_kernel *kernel; -private: - // Protects live_threads, live_tasks, cur_thread, may_exit - lock_and_signal lock; - // When this hits zero we'll tell the kernel to release us - uintptr_t live_threads; - // When this hits zero we'll tell the threads to exit - uintptr_t live_tasks; - size_t cur_thread; - bool may_exit; - bool killed; - - rust_sched_launcher_factory *launchfac; - array_list<rust_sched_launcher *> threads; - const size_t max_num_threads; - - rust_sched_id id; - - void destroy_task_threads(); - - rust_sched_launcher *create_task_thread(int id); - void destroy_task_thread(rust_sched_launcher *thread); - - void exit(); - - // Called when refcount reaches zero - void delete_this(); - -private: - // private and undefined to disable copying - rust_scheduler(const rust_scheduler& rhs); - rust_scheduler& operator=(const rust_scheduler& rhs); - -public: - rust_scheduler(rust_kernel *kernel, size_t max_num_threads, - rust_sched_id id, bool allow_exit, bool killed, - rust_sched_launcher_factory *launchfac); - - void start_task_threads(); - void join_task_threads(); - void kill_all_tasks(); - rust_task* create_task(rust_task *spawner, const char *name); - - void release_task(); - - size_t max_number_of_threads(); - size_t number_of_threads(); - // Called by each thread when it terminates. When all threads - // terminate the scheduler does as well. - void release_task_thread(); - - rust_sched_id get_id() { return id; } - // Tells the scheduler that as soon as it runs out of tasks - // to run it should exit - void allow_exit(); - void disallow_exit(); -}; - -#endif /* RUST_SCHEDULER_H */ diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp deleted file mode 100644 index 2f6b8acb072..00000000000 --- a/src/rt/rust_task.cpp +++ /dev/null @@ -1,742 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -#ifndef __WIN32__ -#ifdef __ANDROID__ -#include "rust_android_dummy.h" -#else -#include <execinfo.h> -#endif -#endif -#include <iostream> -#include <algorithm> - -#include "rust_task.h" -#include "rust_env.h" -#include "rust_globals.h" -#include "rust_crate_map.h" - -// Tasks -rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state, - const char *name, size_t init_stack_sz) : - ref_count(1), - id(0), - stk(NULL), - runtime_sp(0), - sched(sched_loop->sched), - sched_loop(sched_loop), - kernel(sched_loop->kernel), - name(name), - list_index(-1), - boxed(&local_region, sched_loop->kernel->env->poison_on_free), - local_region(&sched_loop->local_region), - unwinding(false), - total_stack_sz(0), - task_local_data(NULL), - task_local_data_cleanup(NULL), - borrow_list(NULL), - state(state), - cond(NULL), - cond_name("none"), - event_reject(false), - event(NULL), - killed(false), - reentered_rust_stack(false), - disallow_kill(0), - disallow_yield(0), - c_stack(NULL), - next_c_sp(0), - next_rust_sp(0) -{ - LOGPTR(sched_loop, "new task", (uintptr_t)this); - DLOG(sched_loop, task, "sizeof(task) = %d (0x%x)", - sizeof *this, sizeof *this); - - new_stack(init_stack_sz); -} - -// NB: This does not always run on the task's scheduler thread -void -rust_task::delete_this() -{ - DLOG(sched_loop, task, "~rust_task %s @0x%" PRIxPTR ", refcnt=%d", - name, (uintptr_t)this, ref_count); - - /* FIXME (#2677): tighten this up, there are some more - assertions that hold at task-lifecycle events. */ - assert(ref_count == 0); // || - // (ref_count == 1 && this == sched->root_task)); - - // The borrow list should be freed in the task annihilator - assert(!borrow_list); - - sched_loop->release_task(this); -} - -// All failure goes through me. Put your breakpoints here! -extern "C" void -rust_task_fail(rust_task *task, - char const *expr, - char const *file, - size_t line) { - assert(task != NULL); - task->begin_failure(expr, file, line); -} - -struct spawn_args { - rust_task *task; - spawn_fn f; - rust_opaque_box *envptr; - void *argptr; -}; - -struct cleanup_args { - spawn_args *spargs; - bool threw_exception; -}; - -void -annihilate_boxes(rust_task *task); - -void -cleanup_task(cleanup_args *args) { - spawn_args *a = args->spargs; - bool threw_exception = args->threw_exception; - rust_task *task = a->task; - - { - scoped_lock with(task->lifecycle_lock); - if (task->killed && !threw_exception) { - LOG(task, task, "Task killed during termination"); - threw_exception = true; - } - } - - // Clean up TLS. This will only be set if TLS was used to begin with. - // Because this is a crust function, it must be called from the C stack. - if (task->task_local_data_cleanup != NULL) { - // This assert should hold but it's not our job to ensure it (and - // the condition might change). Handled in libcore/task.rs. - // assert(task->task_local_data != NULL); - task->task_local_data_cleanup(task->task_local_data); - task->task_local_data = NULL; - } else if (threw_exception && task->id == INIT_TASK_ID) { - // Edge case: If main never spawns any tasks, but fails anyway, TLS - // won't be around to take down the kernel (task.rs:kill_taskgroup, - // rust_task_kill_all). Do it here instead. - // (Note that children tasks can not init their TLS if they were - // killed too early, so we need to check main's task id too.) - task->fail_sched_loop(); - // This must not happen twice. - static bool main_task_failed_without_spawning = false; - assert(!main_task_failed_without_spawning); - main_task_failed_without_spawning = true; - } - - // Call the box annihilator. - cratemap* map = reinterpret_cast<cratemap*>(global_crate_map); - task->call_on_rust_stack(NULL, const_cast<void*>(map->annihilate_fn())); - - task->die(); - -#ifdef __WIN32__ - assert(!threw_exception && "No exception-handling yet on windows builds"); -#endif -} - -// This runs on the Rust stack -void task_start_wrapper(spawn_args *a) -{ - rust_task *task = a->task; - - bool threw_exception = false; - try { - a->f(a->envptr, a->argptr); - } catch (rust_task *ex) { - assert(ex == task && "Expected this task to be thrown for unwinding"); - threw_exception = true; - - if (task->c_stack) { - task->return_c_stack(); - } - - // Since we call glue code below we need to make sure we - // have the stack limit set up correctly - task->reset_stack_limit(); - } - - // We should have returned any C stack by now - assert(task->c_stack == NULL); - - rust_opaque_box* env = a->envptr; - if(env) { - // free the environment (which should be a unique closure). - const type_desc *td = env->td; - td->drop_glue(NULL, - box_body(env)); - task->kernel->region()->free(env); - } - - // The cleanup work needs lots of stack - cleanup_args ca = {a, threw_exception}; - task->call_on_c_stack(&ca, (void*)cleanup_task); - - task->ctx.next->swap(task->ctx); -} - -void -rust_task::start(spawn_fn spawnee_fn, - rust_opaque_box *envptr, - void *argptr) -{ - LOG(this, task, "starting task from fn 0x%" PRIxPTR - " with env 0x%" PRIxPTR " and arg 0x%" PRIxPTR, - spawnee_fn, envptr, argptr); - - assert(stk->data != NULL); - - char *sp = (char *)stk->end; - - sp -= sizeof(spawn_args); - - spawn_args *a = (spawn_args *)sp; - - a->task = this; - a->envptr = envptr; - a->argptr = argptr; - a->f = spawnee_fn; - - ctx.call((void *)task_start_wrapper, a, sp); - - this->start(); -} - -void rust_task::start() -{ - transition(task_state_newborn, task_state_running, NULL, "none"); -} - -bool -rust_task::must_fail_from_being_killed() { - scoped_lock with(lifecycle_lock); - return must_fail_from_being_killed_inner(); -} - -bool -rust_task::must_fail_from_being_killed_inner() { - lifecycle_lock.must_have_lock(); - return killed && !reentered_rust_stack && disallow_kill == 0; -} - -void rust_task_yield_fail(rust_task *task) { - LOG_ERR(task, task, "task %" PRIxPTR " yielded in an atomic section", - task); - task->fail(); -} - -// Only run this on the rust stack -MUST_CHECK bool rust_task::yield() { - bool killed = false; - - if (disallow_yield > 0) { - call_on_c_stack(this, (void *)rust_task_yield_fail); - } - - // This check is largely superfluous; it's the one after the context swap - // that really matters. This one allows us to assert a useful invariant. - - // NB: This takes lifecycle_lock three times, and I believe that none of - // them are actually necessary, as per #3213. Removing the locks here may - // cause *harmless* races with a killer... but I didn't observe any - // substantial performance improvement from removing them, even with - // msgsend-ring-pipes, and also it's my last day, so I'm not about to - // remove them. -- bblum - if (must_fail_from_being_killed()) { - { - scoped_lock with(lifecycle_lock); - assert(!(state == task_state_blocked)); - } - killed = true; - } - - // Return to the scheduler. - ctx.next->swap(ctx); - - if (must_fail_from_being_killed()) { - killed = true; - } - return killed; -} - -void -rust_task::kill() { - scoped_lock with(lifecycle_lock); - kill_inner(); -} - -void rust_task::kill_inner() { - lifecycle_lock.must_have_lock(); - - // Multiple kills should be able to safely race, but check anyway. - if (killed) { - LOG(this, task, "task %s @0x%" PRIxPTR " already killed", name, this); - return; - } - - // Note the distinction here: kill() is when you're in an upcall - // from task A and want to force-fail task B, you do B->kill(). - // If you want to fail yourself you do self->fail(). - LOG(this, task, "killing task %s @0x%" PRIxPTR, name, this); - // When the task next goes to yield or resume it will fail - killed = true; - // Unblock the task so it can unwind. - - if (state == task_state_blocked && - must_fail_from_being_killed_inner()) { - wakeup_inner(cond); - } - - LOG(this, task, "preparing to unwind task: 0x%" PRIxPTR, this); -} - -void -rust_task::fail() { - // See note in ::kill() regarding who should call this. - fail(NULL, NULL, 0); -} - -void -rust_task::fail(char const *expr, char const *file, size_t line) { - rust_task_fail(this, expr, file, line); -} - -// Called only by rust_task_fail -void -rust_task::begin_failure(char const *expr, char const *file, size_t line) { - - if (expr) { - LOG_ERR(this, task, "task failed at '%s', %s:%" PRIdPTR, - expr, file, line); - } - - DLOG(sched_loop, task, "task %s @0x%" PRIxPTR " failing", name, this); - backtrace(); - unwinding = true; -#ifndef __WIN32__ - throw this; -#else - die(); - // FIXME (#908): Need unwinding on windows. This will end up aborting - fail_sched_loop(); -#endif -} - -void rust_task::fail_sched_loop() { - sched_loop->fail(); -} - -void rust_task::assert_is_running() -{ - scoped_lock with(lifecycle_lock); - assert(state == task_state_running); -} - -// FIXME (#2851) Remove this code when rust_port goes away? -bool -rust_task::blocked_on(rust_cond *on) -{ - lifecycle_lock.must_have_lock(); - return cond == on; -} - -void * -rust_task::malloc(size_t sz, const char *tag, type_desc *td) -{ - return local_region.malloc(sz, tag); -} - -void * -rust_task::realloc(void *data, size_t sz) -{ - return local_region.realloc(data, sz); -} - -void -rust_task::free(void *p) -{ - local_region.free(p); -} - -void -rust_task::transition(rust_task_state src, rust_task_state dst, - rust_cond *cond, const char* cond_name) { - scoped_lock with(lifecycle_lock); - transition_inner(src, dst, cond, cond_name); -} - -void rust_task::transition_inner(rust_task_state src, rust_task_state dst, - rust_cond *cond, const char* cond_name) { - lifecycle_lock.must_have_lock(); - sched_loop->transition(this, src, dst, cond, cond_name); -} - -void -rust_task::set_state(rust_task_state state, - rust_cond *cond, const char* cond_name) { - lifecycle_lock.must_have_lock(); - this->state = state; - this->cond = cond; - this->cond_name = cond_name; -} - -bool -rust_task::block(rust_cond *on, const char* name) { - scoped_lock with(lifecycle_lock); - return block_inner(on, name); -} - -bool -rust_task::block_inner(rust_cond *on, const char* name) { - if (must_fail_from_being_killed_inner()) { - // We're already going to die. Don't block. Tell the task to fail - return false; - } - - LOG(this, task, "Blocking on 0x%" PRIxPTR ", cond: 0x%" PRIxPTR, - (uintptr_t) on, (uintptr_t) cond); - assert(cond == NULL && "Cannot block an already blocked task."); - assert(on != NULL && "Cannot block on a NULL object."); - - transition_inner(task_state_running, task_state_blocked, on, name); - - return true; -} - -void -rust_task::wakeup(rust_cond *from) { - scoped_lock with(lifecycle_lock); - wakeup_inner(from); -} - -void -rust_task::wakeup_inner(rust_cond *from) { - assert(cond != NULL && "Cannot wake up unblocked task."); - LOG(this, task, "Blocked on 0x%" PRIxPTR " woken up on 0x%" PRIxPTR, - (uintptr_t) cond, (uintptr_t) from); - assert(cond == from && "Cannot wake up blocked task on wrong condition."); - - transition_inner(task_state_blocked, task_state_running, NULL, "none"); -} - -void -rust_task::die() { - transition(task_state_running, task_state_dead, NULL, "none"); -} - -void -rust_task::backtrace() { - if (log_rt_backtrace <= log_err) return; -#ifndef __WIN32__ - void *call_stack[256]; - int nframes = ::backtrace(call_stack, 256); - backtrace_symbols_fd(call_stack + 1, nframes - 1, 2); -#endif -} - -size_t -rust_task::get_next_stack_size(size_t min, size_t current, size_t requested) { - LOG(this, mem, "calculating new stack size for 0x%" PRIxPTR, this); - LOG(this, mem, - "min: %" PRIdPTR " current: %" PRIdPTR " requested: %" PRIdPTR, - min, current, requested); - - // Allocate at least enough to accomodate the next frame, plus a little - // slack to avoid thrashing - size_t sz = std::max(min, requested + (requested / 2)); - - // And double the stack size each allocation - const size_t max = 1024 * 1024; - size_t next = std::min(max, current * 2); - - sz = std::max(sz, next); - - LOG(this, mem, "next stack size: %" PRIdPTR, sz); - assert(requested <= sz); - return sz; -} - -void -rust_task::free_stack(stk_seg *stk) { - LOGPTR(sched_loop, "freeing stk segment", (uintptr_t)stk); - total_stack_sz -= user_stack_size(stk); - destroy_stack(&local_region, stk); -} - -void -new_stack_slow(new_stack_args *args) { - args->task->new_stack(args->requested_sz); -} - -void -rust_task::new_stack(size_t requested_sz) { - LOG(this, mem, "creating new stack for task %" PRIxPTR, this); - if (stk) { - ::check_stack_canary(stk); - } - - // The minimum stack size, in bytes, of a Rust stack, excluding red zone - size_t min_sz = sched_loop->min_stack_size; - - // Try to reuse an existing stack segment - while (stk != NULL && stk->next != NULL) { - size_t next_sz = user_stack_size(stk->next); - if (min_sz <= next_sz && requested_sz <= next_sz) { - LOG(this, mem, "reusing existing stack"); - stk = stk->next; - return; - } else { - LOG(this, mem, "existing stack is not big enough"); - stk_seg *new_next = stk->next->next; - free_stack(stk->next); - stk->next = new_next; - if (new_next) { - new_next->prev = stk; - } - } - } - - // The size of the current stack segment, excluding red zone - size_t current_sz = 0; - if (stk != NULL) { - current_sz = user_stack_size(stk); - } - // The calculated size of the new stack, excluding red zone - size_t rust_stk_sz = get_next_stack_size(min_sz, - current_sz, requested_sz); - - size_t max_stack = kernel->env->max_stack_size; - size_t used_stack = total_stack_sz + rust_stk_sz; - - // Don't allow stacks to grow forever. During unwinding we have to allow - // for more stack than normal in order to allow destructors room to run, - // arbitrarily selected as 2x the maximum stack size. - if (!unwinding && used_stack > max_stack) { - LOG_ERR(this, task, "task %" PRIxPTR " ran out of stack", this); - abort(); - } else if (unwinding && used_stack > max_stack * 2) { - LOG_ERR(this, task, - "task %" PRIxPTR " ran out of stack during unwinding", this); - abort(); - } - - size_t sz = rust_stk_sz + RED_ZONE_SIZE; - stk_seg *new_stk = create_stack(&local_region, sz); - LOGPTR(sched_loop, "new stk", (uintptr_t)new_stk); - new_stk->task = this; - new_stk->next = NULL; - new_stk->prev = stk; - if (stk) { - stk->next = new_stk; - } - LOGPTR(sched_loop, "stk end", new_stk->end); - - stk = new_stk; - total_stack_sz += user_stack_size(new_stk); -} - -void -rust_task::cleanup_after_turn() { - // Delete any spare stack segments that were left - // behind by calls to prev_stack - assert(stk); - - while (stk->next) { - stk_seg *new_next = stk->next->next; - assert (!stk->next->is_big); - free_stack(stk->next); - - stk->next = new_next; - } -} - -// NB: Runs on the Rust stack. Returns true if we successfully allocated the big -// stack and false otherwise. -bool -rust_task::new_big_stack() { - assert(stk); - - stk_seg *borrowed_big_stack = sched_loop->borrow_big_stack(); - if (!borrowed_big_stack) { - return false; - } - - borrowed_big_stack->task = this; - borrowed_big_stack->next = stk->next; - if (borrowed_big_stack->next) - borrowed_big_stack->next->prev = borrowed_big_stack; - borrowed_big_stack->prev = stk; - stk->next = borrowed_big_stack; - - stk = borrowed_big_stack; - - return true; -} - -static bool -sp_in_stk_seg(uintptr_t sp, stk_seg *stk) { - // Not positive these bounds for sp are correct. I think that the first - // possible value for esp on a new stack is stk->end, which points to the - // address before the first value to be pushed onto a new stack. The last - // possible address we can push data to is stk->data. Regardless, there's - // so much slop at either end that we should never hit one of these - // boundaries. - return (uintptr_t)stk->data <= sp && sp <= stk->end; -} - -/* -Called by landing pads during unwinding to figure out which stack segment we -are currently running on and record the stack limit (which was not restored -when unwinding through __morestack). - */ -void -rust_task::reset_stack_limit() { - uintptr_t sp = get_sp(); - bool reseted = false; - while (!sp_in_stk_seg(sp, stk)) { - reseted = true; - prev_stack(); - assert(stk != NULL && "Failed to find the current stack"); - } - - // Each call to prev_stack will record the stack limit. If we *didn't* - // call prev_stack then we still need to record it now to catch a corner case: - // the throw to initiate unwinding starts on the C stack while sp limit is 0. - // If we don't set the limit here then the rust code run subsequently will - // will veer into the red zone. Lame! - if (!reseted) { - record_stack_limit(); - } -} - -void -rust_task::check_stack_canary() { - ::check_stack_canary(stk); -} - -void -rust_task::delete_all_stacks() { - assert(!on_rust_stack()); - // Delete all the stacks. There may be more than one if the task failed - // and no landing pads stopped to clean up. - assert(stk->next == NULL); - while (stk != NULL) { - stk_seg *prev = stk->prev; - - if (stk->is_big) - sched_loop->return_big_stack(stk); - else - free_stack(stk); - - stk = prev; - } -} - -/* -Returns true if we're currently running on the Rust stack - */ -bool -rust_task::on_rust_stack() { - if (stk == NULL) { - // This only happens during construction - return false; - } - - uintptr_t sp = get_sp(); - bool in_first_segment = sp_in_stk_seg(sp, stk); - if (in_first_segment) { - return true; - } else if (stk->prev != NULL) { - // This happens only when calling the upcall to delete - // a stack segment - bool in_second_segment = sp_in_stk_seg(sp, stk->prev); - return in_second_segment; - } else { - return false; - } -} - -// NB: In inhibit_kill and allow_kill, helgrind would complain that we need to -// hold lifecycle_lock while accessing disallow_kill. Even though another -// killing task may access disallow_kill concurrently, this is not racy -// because the killer only cares if this task is blocking, and block() already -// uses proper locking. See https://github.com/mozilla/rust/issues/3213 . - -void -rust_task::inhibit_kill() { - // Here might be good, though not mandatory, to check if we have to die. - disallow_kill++; -} - -void -rust_task::allow_kill() { - assert(disallow_kill > 0 && "Illegal allow_kill(): already killable!"); - disallow_kill--; -} - -void rust_task::inhibit_yield() { - disallow_yield++; -} - -void rust_task::allow_yield() { - assert(disallow_yield > 0 && "Illegal allow_yield(): already yieldable!"); - disallow_yield--; -} - -MUST_CHECK bool rust_task::wait_event(void **result) { - bool killed = false; - scoped_lock with(lifecycle_lock); - - if(!event_reject) { - block_inner(&event_cond, "waiting on event"); - lifecycle_lock.unlock(); - killed = yield(); - lifecycle_lock.lock(); - } else if (must_fail_from_being_killed_inner()) { - // If the deschedule was rejected, yield won't do our killed check for - // us. For thoroughness, do it here. FIXME (#524) - killed = true; - } - - event_reject = false; - *result = event; - return killed; -} - -void -rust_task::signal_event(void *event) { - scoped_lock with(lifecycle_lock); - - this->event = event; - event_reject = true; - if(task_state_blocked == state) { - wakeup_inner(&event_cond); - } -} - -// -// Local Variables: -// mode: C++ -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h deleted file mode 100644 index 1735d35b065..00000000000 --- a/src/rt/rust_task.h +++ /dev/null @@ -1,681 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/** - The rust task is a cooperatively-scheduled green thread that executes - Rust code on a segmented stack. - - This class has too many responsibilities: - - * Working with the scheduler loop to signal and respond to state changes, - and dealing with all the thread synchronization issues involved - - * Managing the dynamically resizing list of Rust stack segments - - * Switching between running Rust code on the Rust segmented stack and - foreign C code on large stacks owned by the scheduler - - # Lifetime - - The lifetime of a rust_task object closely mirrors that of a running Rust - task object, but they are not identical. In particular, the rust_task is an - atomically reference counted object that might be accessed from arbitrary - threads at any time. This may keep the task from being destroyed even after - the task is dead from a Rust task lifecycle perspective. The rust_tasks are - reference counted in the following places: - - * By the task's lifetime (i.e., running tasks hold a reference to themself) - - * In the rust_task_kill_all -> rust_kernel::fail -> - rust_sched_loop::kill_all_tasks path. When a task brings down the whole - runtime, each sched_loop must use refcounts to take a 'snapshot' of all - existing tasks so it can be sure to kill all of them. - - * In core::pipes, tasks that use select() use reference counts to avoid - use-after-free races with multiple different signallers. - - # Death - - All task death goes through a single central path: The task invokes - rust_task::die(), which invokes transition(task_state_dead), which pumps - the scheduler loop, which switches to rust_sched_loop::run_single_turn(), - which calls reap_dead_tasks(), which cleans up the task's stack segments - and drops the reference count. - - When a task's reference count hits zero, rust_sched_loop::release_task() - is called. This frees the memory and deregisters the task from the kernel, - which may trigger the sched_loop, the scheduler, and/or the kernel to exit - completely in the case it was the last task alive. - - die() is called from two places: the successful exit path, in cleanup_task, - and on failure (on linux, this is also in cleanup_task, after unwinding - completes; on windows, it is in begin_failure). - - Tasks do not force-quit other tasks; a task die()s only itself. However... - - # Killing - - Tasks may kill each other. This happens when propagating failure between - tasks (see the task::spawn options interface). The code path for this is - rust_task_kill_other() -> rust_task::kill(). - - It also happens when the main ("root") task (or any task in that task's - linked-failure-group) fails: this brings down the whole runtime, and kills - all tasks in all groups. The code path for this is rust_task_kill_all() -> - rust_kernel::fail() -> rust_scheduler::kill_all_tasks() -> - rust_sched_loop::kill_all_tasks() -> rust_task::kill(). - - In either case, killing a task involves, under the protection of its - lifecycle_lock, (a) setting the 'killed' flag, and (b) checking if it is - 'blocked'* and if so punting it awake. - (* and also isn't unkillable, which may happen via task::unkillable() - or via calling an extern rust function from C.) - - The killed task will then (wake up if it was asleep, and) eventually call - yield() (or wait_event()), which will check the killed flag, see that it is - true, and then invoke 'fail', which begins the death process described - above. - - Three things guarantee concurrency safety in this whole affair: - - * The lifecycle_lock protects tasks accessing each other's state: it makes - killing-and-waking up atomic with respect to a task in block() deciding - whether it's allowed to go to sleep, so tasks can't 'escape' being woken. - - * In the case of linked failure propagation, we ensure (in task.rs) that - tasks can only see another task's rust_task pointer if that task is - already alive. Even before entering the runtime failure path, a task will - access (locked) the linked-failure data structures to remove its task - pointer so that no subsequently-failing tasks will do a use-after-free. - - * In the case of bringing down the whole runtime, each sched_loop takes an - "atomic snapshot" of all its tasks, protected by the sched_loop's lock, - and also sets a 'failing' flag so that any subsequently-failing task will - know that it must fail immediately upon creation (which is also checked - under the same lock). A similar process exists at the one-step-higher - level of the kernel killing all the schedulers (the kernel snapshots all - the schedulers and sets a 'failing' flag in the scheduler table). - */ - -#ifndef RUST_TASK_H -#define RUST_TASK_H - -#include <map> - -#include "rust_globals.h" -#include "util/array_list.h" -#include "context.h" -#include "rust_debug.h" -#include "rust_kernel.h" -#include "boxed_region.h" -#include "rust_stack.h" -#include "rust_type.h" -#include "rust_sched_loop.h" -#include "sp.h" - -// The amount of extra space at the end of each stack segment, available -// to the rt, compiler and dynamic linker for running small functions -// FIXME (#1509): We want this to be 128 but need to slim the red zone calls -// down, disable lazy symbol relocation, and other things we haven't -// discovered yet -#define RZ_LINUX_32 (1024*2) -#define RZ_LINUX_64 (1024*2) -#define RZ_MAC_32 (1024*20) -#define RZ_MAC_64 (1024*20) -#define RZ_WIN_32 (1024*20) -#define RZ_BSD_32 (1024*20) -#define RZ_BSD_64 (1024*20) - -// The threshold beyond which we switch to the C stack. -#define STACK_THRESHOLD (1024 * 1024) - -#ifdef __linux__ -#ifdef __i386__ -#define RED_ZONE_SIZE RZ_LINUX_32 -#endif -#ifdef __x86_64__ -#define RED_ZONE_SIZE RZ_LINUX_64 -#endif -#ifdef __mips__ -#define RED_ZONE_SIZE RZ_MAC_32 -#endif -#ifdef __arm__ -#define RED_ZONE_SIZE RZ_LINUX_32 -#endif -#endif -#ifdef __APPLE__ -#ifdef __i386__ -#define RED_ZONE_SIZE RZ_MAC_32 -#endif -#ifdef __x86_64__ -#define RED_ZONE_SIZE RZ_MAC_64 -#endif -#endif -#ifdef __WIN32__ -#ifdef __i386__ -#define RED_ZONE_SIZE RZ_WIN_32 -#endif -#ifdef __x86_64__ -#define RED_ZONE_SIZE RZ_WIN_64 -#endif -#endif -#ifdef __FreeBSD__ -#ifdef __i386__ -#define RED_ZONE_SIZE RZ_BSD_32 -#endif -#ifdef __x86_64__ -#define RED_ZONE_SIZE RZ_BSD_64 -#endif -#endif -#ifdef __ANDROID__ -#define RED_ZONE_SIZE RZ_MAC_32 -#endif - -#ifndef RED_ZONE_SIZE -# error "Red zone not defined for this platform" -#endif - -struct frame_glue_fns { - uintptr_t mark_glue_off; - uintptr_t drop_glue_off; - uintptr_t reloc_glue_off; -}; - -// std::lib::task::task_result -typedef unsigned long task_result; -#define tr_success 0 -#define tr_failure 1 - -struct spawn_args; -struct cleanup_args; -struct reset_args; -struct new_stack_args; - -// std::lib::task::task_notification -// -// since it's currently a unary tag, we only add the fields. -struct task_notification { - rust_task_id id; - task_result result; // task_result -}; - -extern "C" void -rust_task_fail(rust_task *task, - char const *expr, - char const *file, - size_t line); - -struct -rust_task : public kernel_owned<rust_task> -{ - RUST_ATOMIC_REFCOUNT(); - - rust_task_id id; - - context ctx; - stk_seg *stk; - uintptr_t runtime_sp; // Runtime sp while task running. - rust_scheduler *sched; - rust_sched_loop *sched_loop; - - // Fields known only to the runtime. - rust_kernel *kernel; - const char *const name; - int32_t list_index; - - boxed_region boxed; - memory_region local_region; - - // Indicates that fail() has been called and we are cleaning up. - // We use this to suppress the "killed" flag during calls to yield. - bool unwinding; - - bool propagate_failure; - - debug::task_debug_info debug; - - // The amount of stack we're using, excluding red zones - size_t total_stack_sz; - - // Used by rust task management routines in libcore/task.rs. - void *task_local_data; - void (*task_local_data_cleanup)(void *data); - - // Contains a ~[BorrowRecord] pointer, or NULL. - // - // Used by borrow management code in libcore/unstable/lang.rs. - void *borrow_list; - -private: - - // Protects state, cond, cond_name - // Protects the killed flag, disallow_kill flag, reentered_rust_stack - lock_and_signal lifecycle_lock; - rust_task_state state; - rust_cond *cond; - const char *cond_name; - - bool event_reject; - rust_cond event_cond; - void *event; - - // Indicates that the task was killed and needs to unwind - bool killed; - // Indicates that we've called back into Rust from C - bool reentered_rust_stack; - unsigned long disallow_kill; - unsigned long disallow_yield; - - // The stack used for running C code, borrowed from the scheduler thread - stk_seg *c_stack; - uintptr_t next_c_sp; - uintptr_t next_rust_sp; - - // Called when the atomic refcount reaches zero - void delete_this(); - - bool new_big_stack(); - void new_stack_fast(size_t requested_sz); - void new_stack(size_t requested_sz); - void free_stack(stk_seg *stk); - size_t get_next_stack_size(size_t min, size_t current, size_t requested); - - void return_c_stack(); - - void transition(rust_task_state src, rust_task_state dst, - rust_cond *cond, const char* cond_name); - void transition_inner(rust_task_state src, rust_task_state dst, - rust_cond *cond, const char* cond_name); - - bool must_fail_from_being_killed_inner(); - // Called by rust_task_fail to unwind on failure - void begin_failure(char const *expr, - char const *file, - size_t line); - - friend void task_start_wrapper(spawn_args *a); - friend void cleanup_task(cleanup_args *a); - friend void reset_stack_limit_on_c_stack(reset_args *a); - friend void new_stack_slow(new_stack_args *a); - friend void rust_task_fail(rust_task *task, - char const *expr, - char const *file, - size_t line); - - bool block_inner(rust_cond *on, const char* name); - void wakeup_inner(rust_cond *from); - bool blocked_on(rust_cond *cond); - -private: - // private and undefined to disable copying - rust_task(const rust_task& rhs); - rust_task& operator=(const rust_task& rhs); - -public: - - // Only a pointer to 'name' is kept, so it must live as long as this task. - rust_task(rust_sched_loop *sched_loop, - rust_task_state state, - const char *name, - size_t init_stack_sz); - - void start(spawn_fn spawnee_fn, - rust_opaque_box *env, - void *args); - void start(); - void assert_is_running(); - - void *malloc(size_t sz, const char *tag, type_desc *td=0); - void *realloc(void *data, size_t sz); - void free(void *p); - - void set_state(rust_task_state state, - rust_cond *cond, const char* cond_name); - - bool block(rust_cond *on, const char* name); - void wakeup(rust_cond *from); - void die(); - - // Print a backtrace, if the "bt" logging option is on. - void backtrace(); - - // Yields control to the scheduler. Called from the Rust stack - // Returns TRUE if the task was killed and needs to fail. - MUST_CHECK bool yield(); - - // Fail this task (assuming caller-on-stack is different task). - void kill(); - void kill_inner(); - - // Indicates that we've been killed and now is an apropriate - // time to fail as a result - bool must_fail_from_being_killed(); - - // Fail self, assuming caller-on-stack is this task. - void fail(); - void fail(char const *expr, char const *file, size_t line); - - // Propagate failure to the entire rust runtime. - void fail_sched_loop(); - - void *calloc(size_t size, const char *tag); - - // Use this function sparingly. Depending on the ref count is generally - // not at all safe. - intptr_t get_ref_count() const { return ref_count; } - - void *next_stack(size_t stk_sz, void *args_addr, size_t args_sz); - void prev_stack(); - void record_stack_limit(); - void reset_stack_limit(); - - bool on_rust_stack(); - void check_stack_canary(); - void delete_all_stacks(); - - void call_on_c_stack(void *args, void *fn_ptr); - void call_on_rust_stack(void *args, void *fn_ptr); - bool have_c_stack() { return c_stack != NULL; } - stk_seg *get_c_stack() { return c_stack; } - - rust_task_state get_state() { return state; } - rust_cond *get_cond() { return cond; } - const char *get_cond_name() { return cond_name; } - - void clear_event_reject() { - this->event_reject = false; - } - - // Returns TRUE if the task was killed and needs to fail. - MUST_CHECK bool wait_event(void **result); - void signal_event(void *event); - - void cleanup_after_turn(); - - void inhibit_kill(); - void allow_kill(); - void inhibit_yield(); - void allow_yield(); -}; - -template <typename T> struct task_owned { - inline void *operator new(size_t size, rust_task *task, - const char *tag) { - return task->malloc(size, tag); - } - - inline void *operator new[](size_t size, rust_task *task, - const char *tag) { - return task->malloc(size, tag); - } - - inline void *operator new(size_t size, rust_task &task, - const char *tag) { - return task.malloc(size, tag); - } - - inline void *operator new[](size_t size, rust_task &task, - const char *tag) { - return task.malloc(size, tag); - } - - void operator delete(void *ptr) { - ((T *)ptr)->task->free(ptr); - } -}; - -// This is the function that switches between the C and the Rust stack by -// calling another function with a single void* argument while changing the -// stack pointer. It has a funny name because gdb doesn't normally like to -// backtrace through split stacks (thinks it indicates a bug), but has a -// special case to allow functions named __morestack to move the stack pointer -// around. -extern "C" void __morestack(void *args, void *fn_ptr, uintptr_t stack_ptr); - -inline static uintptr_t -sanitize_next_sp(uintptr_t next_sp) { - - // Since I'm not precisely sure where the next stack pointer sits in - // relation to where the context switch actually happened, nor in relation - // to the amount of stack needed for calling __morestack I've added some - // extra bytes here. - - // FIXME (#2698): On the rust stack this potentially puts is quite far - // into the red zone. Might want to just allocate a new rust stack every - // time we switch back to rust. - const uintptr_t padding = 16; - - return align_down(next_sp - padding); -} - -inline void -rust_task::call_on_c_stack(void *args, void *fn_ptr) { - // Too expensive to check - // assert(on_rust_stack()); - - // The shim functions generated by rustc contain the morestack prologue, - // so we need to let them know they have enough stack. - record_sp_limit(0); - - uintptr_t prev_rust_sp = next_rust_sp; - next_rust_sp = get_sp(); - - bool borrowed_a_c_stack = false; - uintptr_t sp; - if (c_stack == NULL) { - c_stack = sched_loop->borrow_c_stack(); - next_c_sp = align_down(c_stack->end); - sp = next_c_sp; - borrowed_a_c_stack = true; - } else { - sp = sanitize_next_sp(next_c_sp); - } - - __morestack(args, fn_ptr, sp); - - // Note that we may not actually get here if we threw an exception, - // in which case we will return the c stack when the exception is caught. - if (borrowed_a_c_stack) { - return_c_stack(); - } - - next_rust_sp = prev_rust_sp; - - record_stack_limit(); -} - -inline void -rust_task::call_on_rust_stack(void *args, void *fn_ptr) { - // Too expensive to check - // assert(!on_rust_stack()); - - // Because of the hack in the other function that disables the stack limit - // when entering the C stack, here we restore the stack limit again. - record_stack_limit(); - - assert(get_sp_limit() != 0 && "Stack must be configured"); - assert(next_rust_sp); - - // Unlocked access. Might "race" a killer, but harmlessly. This code is - // only run by the task itself, so cannot race itself. See the comment - // above inhibit_kill (or #3213) in rust_task.cpp for justification. - bool had_reentered_rust_stack = reentered_rust_stack; - reentered_rust_stack = true; - - uintptr_t prev_c_sp = next_c_sp; - next_c_sp = get_sp(); - - uintptr_t sp = sanitize_next_sp(next_rust_sp); - - // FIXME (#2047): There are times when this is called and needs - // to be able to throw, and we don't account for that. - __morestack(args, fn_ptr, sp); - - next_c_sp = prev_c_sp; - reentered_rust_stack = had_reentered_rust_stack; - - record_sp_limit(0); -} - -inline void -rust_task::return_c_stack() { - // Too expensive to check - // assert(on_rust_stack()); - assert(c_stack != NULL); - sched_loop->return_c_stack(c_stack); - c_stack = NULL; - next_c_sp = 0; -} - -// NB: This runs on the Rust stack -inline void * -rust_task::next_stack(size_t stk_sz, void *args_addr, size_t args_sz) { - new_stack_fast(stk_sz + args_sz); - assert(stk->end - (uintptr_t)stk->data >= stk_sz + args_sz - && "Did not receive enough stack"); - uint8_t *new_sp = (uint8_t*)stk->end; - // Push the function arguments to the new stack - new_sp = align_down(new_sp - args_sz); - - // I don't know exactly where the region ends that valgrind needs us - // to mark accessible. On x86_64 these extra bytes aren't needed, but - // on i386 we get errors without. - const int fudge_bytes = 16; - reuse_valgrind_stack(stk, new_sp - fudge_bytes); - - memcpy(new_sp, args_addr, args_sz); - record_stack_limit(); - return new_sp; -} - -// The amount of stack in a segment available to Rust code -inline size_t -user_stack_size(stk_seg *stk) { - return (size_t)(stk->end - - (uintptr_t)&stk->data[0] - - RED_ZONE_SIZE); -} - -struct new_stack_args { - rust_task *task; - size_t requested_sz; -}; - -void -new_stack_slow(new_stack_args *args); - -// NB: This runs on the Rust stack -// This is the new stack fast path, in which we -// reuse the next cached stack segment -inline void -rust_task::new_stack_fast(size_t requested_sz) { - // The minimum stack size, in bytes, of a Rust stack, excluding red zone - size_t min_sz = sched_loop->min_stack_size; - - if (requested_sz > STACK_THRESHOLD) { - if (new_big_stack()) - return; - } - - // Try to reuse an existing stack segment - if (stk != NULL && stk->next != NULL) { - size_t next_sz = user_stack_size(stk->next); - if (min_sz <= next_sz && requested_sz <= next_sz) { - stk = stk->next; - return; - } - } - - new_stack_args args = {this, requested_sz}; - call_on_c_stack(&args, (void*)new_stack_slow); -} - -// NB: This runs on the Rust stack -inline void -rust_task::prev_stack() { - // We're not going to actually delete anything now because that would - // require switching to the C stack and be costly. Instead we'll just move - // up the link list and clean up later, either in new_stack or after our - // turn ends on the scheduler. - if (stk->is_big) { - stk_seg *ss = stk; - stk = stk->prev; - - // Unlink the big stack. - if (ss->next) - ss->next->prev = ss->prev; - if (ss->prev) - ss->prev->next = ss->next; - - sched_loop->return_big_stack(ss); - } else { - stk = stk->prev; - } - - record_stack_limit(); -} - -// The LLVM-generated segmented-stack function prolog compares the amount of -// stack needed for each frame to the end-of-stack pointer stored in the -// TCB. As an optimization, when the frame size is less than 256 bytes, it -// will simply compare %esp to the stack limit instead of subtracting the -// frame size. As a result we need our stack limit to account for those 256 -// bytes. -const unsigned LIMIT_OFFSET = 256; - -inline void -rust_task::record_stack_limit() { - assert(stk); - assert((uintptr_t)stk->end - RED_ZONE_SIZE - - (uintptr_t)stk->data >= LIMIT_OFFSET - && "Stack size must be greater than LIMIT_OFFSET"); - record_sp_limit(stk->data + LIMIT_OFFSET + RED_ZONE_SIZE); -} - -inline rust_task* rust_try_get_current_task() { - uintptr_t sp_limit = get_sp_limit(); - - // FIXME (#1226) - Because of a hack in upcall_call_shim_on_c_stack this - // value is sometimes inconveniently set to 0, so we can't use this - // method of retreiving the task pointer and need to fall back to TLS. - if (sp_limit == 0) - return rust_sched_loop::try_get_task_tls(); - - // The stack pointer boundary is stored in a quickly-accessible location - // in the TCB. From that we can calculate the address of the stack segment - // structure it belongs to, and in that structure is a pointer to the task - // that owns it. - uintptr_t seg_addr = - sp_limit - RED_ZONE_SIZE - LIMIT_OFFSET - sizeof(stk_seg); - stk_seg *stk = (stk_seg*) seg_addr; - - // Make sure we've calculated the right address - ::check_stack_canary(stk); - assert(stk->task != NULL && "task pointer not in stack structure"); - return stk->task; -} - -inline rust_task* rust_get_current_task() { - rust_task* task = rust_try_get_current_task(); - assert(task != NULL && "no current task"); - return task; -} - -// -// Local Variables: -// mode: C++ -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// - -#endif /* RUST_TASK_H */ diff --git a/src/rt/rust_test_helpers.cpp b/src/rt/rust_test_helpers.cpp index 492874a0c26..b0aab9672ea 100644 --- a/src/rt/rust_test_helpers.cpp +++ b/src/rt/rust_test_helpers.cpp @@ -10,12 +10,10 @@ // Helper functions used only in tests -#include "rust_sched_loop.h" -#include "rust_task.h" #include "rust_util.h" -#include "rust_scheduler.h" #include "sync/timer.h" #include "sync/rust_thread.h" +#include "sync/lock_and_signal.h" #include "rust_abi.h" // These functions are used in the unit tests for C ABI calls. diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index c011219ade8..f1b31e89df8 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -17,8 +17,6 @@ */ #include "rust_globals.h" -#include "rust_task.h" -#include "rust_sched_loop.h" #include "rust_upcall.h" #include "rust_util.h" @@ -29,28 +27,6 @@ typedef int _Unwind_Action; struct _Unwind_Context; struct _Unwind_Exception; -#ifdef __GNUC__ -#define LOG_UPCALL_ENTRY(task) \ - LOG(task, upcall, \ - "> UPCALL %s - task: %s 0x%" PRIxPTR \ - " retpc: x%" PRIxPTR, \ - __FUNCTION__, \ - (task)->name, (task), \ - __builtin_return_address(0)); -#else -#define LOG_UPCALL_ENTRY(task) \ - LOG(task, upcall, "> UPCALL task: %s @x%" PRIxPTR, \ - (task)->name, (task)); -#endif - -#define UPCALL_SWITCH_STACK(T, A, F) \ - call_upcall_on_c_stack(T, (void*)A, (void*)F) - -inline void -call_upcall_on_c_stack(rust_task *task, void *args, void *fn_ptr) { - task->call_on_c_stack(args, fn_ptr); -} - typedef void (*CDECL stack_switch_shim)(void*); /********************************************************************** @@ -62,21 +38,8 @@ typedef void (*CDECL stack_switch_shim)(void*); */ extern "C" CDECL void upcall_call_shim_on_c_stack(void *args, void *fn_ptr) { - rust_task *task = rust_try_get_current_task(); - - if (task) { - // We're running in task context, do a stack switch - try { - task->call_on_c_stack(args, fn_ptr); - } catch (...) { - // Logging here is not reliable - assert(false && "Foreign code threw an exception"); - } - } else { - // There's no task. Call the function and hope for the best - stack_switch_shim f = (stack_switch_shim)fn_ptr; - f(args); - } + stack_switch_shim f = (stack_switch_shim)fn_ptr; + f(args); } /* @@ -85,171 +48,9 @@ upcall_call_shim_on_c_stack(void *args, void *fn_ptr) { */ extern "C" CDECL void upcall_call_shim_on_rust_stack(void *args, void *fn_ptr) { - rust_task *task = rust_try_get_current_task(); - - if (task) { - try { - task->call_on_rust_stack(args, fn_ptr); - } catch (...) { - // We can't count on being able to unwind through arbitrary - // code. Our best option is to just fail hard. - // Logging here is not reliable - assert(false - && "Rust task failed after reentering the Rust stack"); - } - } else { - // There's no task. Call the function and hope for the best - stack_switch_shim f = (stack_switch_shim)fn_ptr; - f(args); - } -} - -/**********************************************************************/ - -struct s_fail_args { - rust_task *task; - char const *expr; - char const *file; - size_t line; -}; - -extern "C" CDECL void -upcall_s_fail(s_fail_args *args) { - rust_task *task = args->task; - LOG_UPCALL_ENTRY(task); - task->fail(args->expr, args->file, args->line); -} - -extern "C" CDECL void -upcall_fail(char const *expr, - char const *file, - size_t line) { - rust_task *task = rust_try_get_current_task(); - if (task == NULL) { - // FIXME #5161: Need to think about what to do here - printf("failure outside of a task"); - abort(); - } - s_fail_args args = {task,expr,file,line}; - UPCALL_SWITCH_STACK(task, &args, upcall_s_fail); -} - -// FIXME (#2861): Alias used by libcore/rt.rs to avoid naming conflicts with -// autogenerated wrappers for upcall_fail. Remove this when we fully move away -// away from the C upcall path. -extern "C" CDECL void -rust_upcall_fail(char const *expr, - char const *file, - size_t line) { - upcall_fail(expr, file, line); -} - -struct s_trace_args { - rust_task *task; - char const *msg; - char const *file; - size_t line; -}; - -/********************************************************************** - * Allocate an object in the task-local heap. - */ - -struct s_malloc_args { - rust_task *task; - uintptr_t retval; - type_desc *td; - uintptr_t size; -}; - -extern "C" CDECL void -upcall_s_malloc(s_malloc_args *args) { - rust_task *task = args->task; - LOG_UPCALL_ENTRY(task); - LOG(task, mem, "upcall malloc(0x%" PRIxPTR ")", args->td); - - rust_opaque_box *box = task->boxed.malloc(args->td, args->size); - void *body = box_body(box); - - debug::maybe_track_origin(task, box); - - LOG(task, mem, - "upcall malloc(0x%" PRIxPTR ") = box 0x%" PRIxPTR - " with body 0x%" PRIxPTR, - args->td, (uintptr_t)box, (uintptr_t)body); - - args->retval = (uintptr_t)box; -} - -extern "C" CDECL uintptr_t -upcall_malloc(type_desc *td, uintptr_t size) { - rust_task *task = rust_get_current_task(); - s_malloc_args args = {task, 0, td, size}; - UPCALL_SWITCH_STACK(task, &args, upcall_s_malloc); - return args.retval; -} - -// FIXME (#2861): Alias used by libcore/rt.rs to avoid naming conflicts with -// autogenerated wrappers for upcall_malloc. Remove this when we fully move -// away from the C upcall path. -extern "C" CDECL uintptr_t -rust_upcall_malloc(type_desc *td, uintptr_t size) { - return upcall_malloc(td, size); -} - -extern "C" CDECL uintptr_t -rust_upcall_malloc_noswitch(type_desc *td, uintptr_t size) { - rust_task *task = rust_get_current_task(); - s_malloc_args args = {task, 0, td, size}; - upcall_s_malloc(&args); - return args.retval; -} - -/********************************************************************** - * Called whenever an object in the task-local heap is freed. - */ - -struct s_free_args { - rust_task *task; - void *ptr; -}; - -extern "C" CDECL void -upcall_s_free(s_free_args *args) { - rust_task *task = args->task; - LOG_UPCALL_ENTRY(task); - - rust_sched_loop *sched_loop = task->sched_loop; - DLOG(sched_loop, mem, - "upcall free(0x%" PRIxPTR ", is_gc=%" PRIdPTR ")", - (uintptr_t)args->ptr); - - debug::maybe_untrack_origin(task, args->ptr); - - rust_opaque_box *box = (rust_opaque_box*) args->ptr; - task->boxed.free(box); -} - -extern "C" CDECL void -upcall_free(void* ptr) { - rust_task *task = rust_get_current_task(); - s_free_args args = {task,ptr}; - UPCALL_SWITCH_STACK(task, &args, upcall_s_free); -} - -// FIXME (#2861): Alias used by libcore/rt.rs to avoid naming conflicts with -// autogenerated wrappers for upcall_free. Remove this when we fully move away -// away from the C upcall path. -extern "C" CDECL void -rust_upcall_free(void* ptr) { - upcall_free(ptr); -} - -extern "C" CDECL void -rust_upcall_free_noswitch(void* ptr) { - rust_task *task = rust_get_current_task(); - s_free_args args = {task,ptr}; - upcall_s_free(&args); + // There's no task. Call the function and hope for the best + stack_switch_shim f = (stack_switch_shim)fn_ptr; + f(args); } /**********************************************************************/ @@ -293,41 +94,21 @@ upcall_rust_personality(int version, s_rust_personality_args args = {(_Unwind_Reason_Code)0, version, actions, exception_class, ue_header, context}; - rust_task *task = rust_try_get_current_task(); - - if (task == NULL) { - // Assuming we're running with the new scheduler - upcall_s_rust_personality(&args); - return args.retval; - } - - // The personality function is run on the stack of the - // last function that threw or landed, which is going - // to sometimes be the C stack. If we're on the Rust stack - // then switch to the C stack. - - if (task->on_rust_stack()) { - UPCALL_SWITCH_STACK(task, &args, upcall_s_rust_personality); - } else { - upcall_s_rust_personality(&args); - } + upcall_s_rust_personality(&args); return args.retval; } // NB: This needs to be blazing fast. Don't switch stacks extern "C" CDECL void * upcall_new_stack(size_t stk_sz, void *args_addr, size_t args_sz) { - rust_task *task = rust_get_current_task(); - return task->next_stack(stk_sz, - args_addr, - args_sz); + assert(false && "newsched shouldn't be growing the stack"); + return NULL; } // NB: This needs to be blazing fast. Don't switch stacks extern "C" CDECL void upcall_del_stack() { - rust_task *task = rust_get_current_task(); - task->prev_stack(); + assert(false && "newsched shouldn't be growing the stack"); } // Landing pads need to call this to insert the @@ -336,12 +117,6 @@ upcall_del_stack() { // needs to acquire the value of the stack pointer extern "C" CDECL void upcall_reset_stack_limit() { - rust_task *task = rust_try_get_current_task(); - if (task != NULL) { - task->reset_stack_limit(); - } else { - // We must be in a newsched task - } } // diff --git a/src/rt/rust_util.h b/src/rt/rust_util.h index 95651c68602..30d4fcbdc49 100644 --- a/src/rt/rust_util.h +++ b/src/rt/rust_util.h @@ -12,7 +12,8 @@ #define RUST_UTIL_H #include <limits.h> -#include "rust_task.h" +#include "rust_exchange_alloc.h" +#include "rust_type.h" #include "rust_env.h" extern struct type_desc str_body_tydesc; diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 19162b8df6b..f537e866dfc 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -16,8 +16,6 @@ #include "uv.h" #include "rust_globals.h" -#include "rust_task.h" -#include "rust_log.h" // extern fn pointers typedef void (*extern_async_op_cb)(uv_loop_t* loop, void* data, @@ -35,43 +33,6 @@ struct handle_data { extern_close_cb close_cb; }; -// helpers -static void* -current_kernel_malloc(size_t size, const char* tag) { - void* ptr = rust_get_current_task()->kernel->malloc(size, tag); - return ptr; -} - -static void -current_kernel_free(void* ptr) { - rust_get_current_task()->kernel->free(ptr); -} - -static handle_data* -new_handle_data_from(uint8_t* buf, extern_simple_cb cb) { - handle_data* data = (handle_data*)current_kernel_malloc( - sizeof(handle_data), - "handle_data"); - memcpy(data->id_buf, buf, RUST_UV_HANDLE_LEN); - data->cb = cb; - return data; -} - -// libuv callback impls -static void -foreign_extern_async_op_cb(uv_async_t* handle, int status) { - extern_async_op_cb cb = (extern_async_op_cb)handle->data; - void* loop_data = handle->loop->data; - cb(handle->loop, loop_data, handle); -} - -static void -foreign_async_cb(uv_async_t* handle, int status) { - handle_data* handle_d = (handle_data*)handle->data; - void* loop_data = handle->loop->data; - handle_d->cb(handle_d->id_buf, loop_data); -} - static void foreign_timer_cb(uv_timer_t* handle, int status) { handle_data* handle_d = (handle_data*)handle->data; @@ -84,18 +45,6 @@ foreign_close_cb(uv_handle_t* handle) { handle_data* data = (handle_data*)handle->data; data->close_cb(data->id_buf, handle, handle->loop->data); } - -static void -foreign_close_op_cb(uv_handle_t* op_handle) { - current_kernel_free(op_handle); - // uv_run() should return after this.. -} - -// foreign fns bound in rust -extern "C" void -rust_uv_free(void* ptr) { - current_kernel_free(ptr); -} extern "C" void* rust_uv_loop_new() { return (void*)uv_loop_new(); @@ -127,24 +76,6 @@ rust_uv_loop_set_data(uv_loop_t* loop, void* data) { loop->data = data; } -extern "C" void* -rust_uv_bind_op_cb(uv_loop_t* loop, extern_async_op_cb cb) { - uv_async_t* async = (uv_async_t*)current_kernel_malloc( - sizeof(uv_async_t), - "uv_async_t"); - uv_async_init(loop, async, foreign_extern_async_op_cb); - async->data = (void*)cb; - // decrement the ref count, so that our async bind - // doesn't count towards keeping the loop alive - //uv_unref(loop); - return async; -} - -extern "C" void -rust_uv_stop_op_cb(uv_handle_t* op_handle) { - uv_close(op_handle, foreign_close_op_cb); -} - extern "C" void rust_uv_run(uv_loop_t* loop) { uv_run(loop, UV_RUN_DEFAULT); @@ -168,18 +99,6 @@ rust_uv_hilvl_close(uv_handle_t* handle, extern_close_cb cb) { } extern "C" void -rust_uv_hilvl_close_async(uv_async_t* handle) { - current_kernel_free(handle->data); - current_kernel_free(handle); -} - -extern "C" void -rust_uv_hilvl_close_timer(uv_async_t* handle) { - current_kernel_free(handle->data); - current_kernel_free(handle); -} - -extern "C" void rust_uv_async_send(uv_async_t* handle) { uv_async_send(handle); } @@ -191,32 +110,6 @@ rust_uv_async_init(uv_loop_t* loop_handle, return uv_async_init(loop_handle, async_handle, cb); } -extern "C" void* -rust_uv_hilvl_async_init(uv_loop_t* loop, extern_simple_cb cb, - uint8_t* buf) { - uv_async_t* async = (uv_async_t*)current_kernel_malloc( - sizeof(uv_async_t), - "uv_async_t"); - uv_async_init(loop, async, foreign_async_cb); - handle_data* data = new_handle_data_from(buf, cb); - async->data = data; - - return async; -} - -extern "C" void* -rust_uv_hilvl_timer_init(uv_loop_t* loop, extern_simple_cb cb, - uint8_t* buf) { - uv_timer_t* new_timer = (uv_timer_t*)current_kernel_malloc( - sizeof(uv_timer_t), - "uv_timer_t"); - uv_timer_init(loop, new_timer); - handle_data* data = new_handle_data_from(buf, cb); - new_timer->data = data; - - return new_timer; -} - extern "C" void rust_uv_hilvl_timer_start(uv_timer_t* the_timer, uint32_t timeout, uint32_t repeat) { @@ -469,15 +362,6 @@ rust_uv_get_stream_handle_from_write_req(uv_write_t* write_req) { return write_req->handle; } -extern "C" uv_buf_t -current_kernel_malloc_alloc_cb(uv_handle_t* handle, - size_t suggested_size) { - char* base_ptr = (char*)current_kernel_malloc(sizeof(char) - * suggested_size, - "uv_buf_t_base_val"); - return uv_buf_init(base_ptr, suggested_size); -} - extern "C" void rust_uv_buf_init(uv_buf_t* out_buf, char* base, size_t len) { *out_buf = uv_buf_init(base, len); @@ -563,16 +447,6 @@ rust_uv_read_stop(uv_stream_t* stream) { return uv_read_stop(stream); } -extern "C" char* -rust_uv_malloc_buf_base_of(size_t suggested_size) { - return (char*) current_kernel_malloc(sizeof(char)*suggested_size, - "uv_buf_t base"); -} -extern "C" void -rust_uv_free_base_of_buf(uv_buf_t buf) { - current_kernel_free(buf.base); -} - extern "C" struct sockaddr_in rust_uv_ip4_addr(const char* ip, int port) { struct sockaddr_in addr = uv_ip4_addr(ip, port); @@ -639,16 +513,6 @@ rust_uv_ip6_port(struct sockaddr_in6* src) { return ntohs(src->sin6_port); } -extern "C" void* -rust_uv_current_kernel_malloc(size_t size) { - return current_kernel_malloc(size, "rust_uv_current_kernel_malloc"); -} - -extern "C" void -rust_uv_current_kernel_free(void* mem) { - current_kernel_free(mem); -} - extern "C" int rust_uv_getaddrinfo(uv_loop_t* loop, uv_getaddrinfo_t* handle, uv_getaddrinfo_cb cb, diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 75e02d0a103..b5ce0400c1e 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -1,27 +1,19 @@ -debug_get_stk_seg debug_abi_1 debug_abi_2 debug_static_mut debug_static_mut_check_four -get_task_id get_time rust_tzset rust_gmtime rust_localtime rust_timegm rust_mktime -new_task precise_time_ns rand_free rand_new_seeded rand_seed_size rand_gen_seed rand_next -rust_get_sched_id -rust_get_argc -rust_get_argv -rust_new_sched -rust_new_task_in_sched rust_path_is_dir rust_path_exists rust_get_stdin @@ -35,55 +27,26 @@ rust_log_console_off rust_should_log_console rust_set_environ rust_unset_sigprocmask -rust_set_exit_status -rust_start rust_env_pairs -rust_task_yield -rust_task_is_unwinding -rust_get_task -rust_try_get_task -rust_get_stack_segment -rust_get_c_stack -rust_log_str -start_task -rust_local_realloc -task_clear_event_reject -task_wait_event -task_signal_event -upcall_fail -upcall_free -upcall_malloc upcall_rust_personality upcall_call_shim_on_c_stack upcall_call_shim_on_rust_stack upcall_new_stack upcall_del_stack upcall_reset_stack_limit -rust_upcall_fail -rust_upcall_free -rust_upcall_free_noswitch -rust_upcall_malloc -rust_upcall_malloc_noswitch rust_uv_loop_new rust_uv_loop_delete rust_uv_walk rust_uv_loop_set_data -rust_uv_bind_op_cb -rust_uv_stop_op_cb rust_uv_run rust_uv_close rust_uv_hilvl_close -rust_uv_hilvl_close_async -rust_uv_hilvl_close_timer rust_uv_async_send rust_uv_async_init -rust_uv_hilvl_async_init -rust_uv_hilvl_timer_init rust_uv_hilvl_timer_start rust_uv_timer_init rust_uv_timer_start rust_uv_timer_stop -rust_uv_free rust_uv_tcp_init rust_uv_buf_init rust_uv_last_error @@ -124,8 +87,6 @@ rust_uv_accept rust_uv_write rust_uv_read_start rust_uv_read_stop -rust_uv_malloc_buf_base_of -rust_uv_free_base_of_buf rust_uv_is_ipv4_addrinfo rust_uv_is_ipv6_addrinfo rust_uv_get_next_addrinfo @@ -155,8 +116,6 @@ rust_uv_get_data_for_req rust_uv_set_data_for_req rust_uv_get_base_from_buf rust_uv_get_len_from_buf -rust_uv_current_kernel_malloc -rust_uv_current_kernel_free rust_uv_getaddrinfo rust_uv_freeaddrinfo rust_uv_idle_new @@ -172,21 +131,10 @@ rust_dbg_lock_wait rust_dbg_lock_signal rust_dbg_call rust_dbg_do_nothing -rust_osmain_sched_id -rust_task_inhibit_kill -rust_task_allow_kill -rust_task_inhibit_yield -rust_task_allow_yield -rust_task_kill_other -rust_task_kill_all rust_create_little_lock rust_destroy_little_lock rust_lock_little_lock rust_unlock_little_lock -rust_get_task_local_data -rust_task_local_data_atexit -rust_task_ref -rust_task_deref tdefl_compress_mem_to_heap tinfl_decompress_mem_to_heap rust_gc_metadata @@ -221,7 +169,6 @@ rust_dbg_extern_return_TwoU32s rust_dbg_extern_return_TwoU64s rust_dbg_extern_identity_double rust_dbg_extern_identity_u8 -rust_get_rt_env rust_uv_handle_size rust_uv_req_size rust_uv_handle_type_max @@ -241,8 +188,6 @@ rust_boxed_region_realloc rust_boxed_region_free rust_try rust_begin_unwind -rust_take_task_borrow_list -rust_set_task_borrow_list rust_valgrind_stack_register rust_valgrind_stack_deregister rust_take_env_lock @@ -251,7 +196,6 @@ rust_update_log_settings rust_running_on_valgrind rust_get_num_cpus rust_get_global_args_ptr -rust_current_boxed_region rust_take_global_args_lock rust_drop_global_args_lock rust_set_exit_status_newrt @@ -259,3 +203,4 @@ rust_get_exit_status_newrt rust_take_change_dir_lock rust_drop_change_dir_lock rust_get_test_int +rust_get_task \ No newline at end of file diff --git a/src/test/auxiliary/cci_class_5.rs b/src/test/auxiliary/cci_class_5.rs index 7cdfcf64bb9..5b8bebda924 100644 --- a/src/test/auxiliary/cci_class_5.rs +++ b/src/test/auxiliary/cci_class_5.rs @@ -17,7 +17,7 @@ pub mod kitties { } impl cat { - priv fn nap(&self) {} + fn nap(&self) {} } pub fn cat(in_x : uint, in_y : int) -> cat { diff --git a/src/test/auxiliary/xc_private_method_lib.rs b/src/test/auxiliary/xc_private_method_lib.rs index 05325c3b935..8290f62bada 100644 --- a/src/test/auxiliary/xc_private_method_lib.rs +++ b/src/test/auxiliary/xc_private_method_lib.rs @@ -1,9 +1,33 @@ #[crate_type="lib"]; -pub struct Foo { +pub struct Struct { x: int } -impl Foo { - fn new() -> Foo { Foo { x: 1 } } +impl Struct { + fn static_meth_struct() -> Struct { + Struct { x: 1 } + } + + fn meth_struct(&self) -> int { + self.x + } +} + +pub enum Enum { + Variant1(int), + Variant2(int) +} + +impl Enum { + fn static_meth_enum() -> Enum { + Variant2(10) + } + + fn meth_enum(&self) -> int { + match *self { + Variant1(x) | + Variant2(x) => x + } + } } diff --git a/src/test/auxiliary/xcrate_unit_struct.rs b/src/test/auxiliary/xcrate_unit_struct.rs new file mode 100644 index 00000000000..a72bf307e5d --- /dev/null +++ b/src/test/auxiliary/xcrate_unit_struct.rs @@ -0,0 +1,31 @@ +// 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. + +#[crate_type = "lib"]; + +// used by the rpass test + +pub struct Struct; + +pub enum Unit { + Unit, + Argument(Struct) +} + +// used by the cfail test + +pub struct StructWithFields { + foo: int, +} + +pub enum EnumWithVariants { + EnumVariant, + EnumVariantArg(int) +} diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index cf160ca31c6..6475012e009 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -53,24 +53,21 @@ fn descending<M: MutableMap<uint, uint>>(map: &mut M, n_keys: uint) { io::println(" Descending integers:"); do timed("insert") { - do uint::range_rev(n_keys, 0) |i| { + for i in range(0, n_keys).invert() { map.insert(i, i + 1); - true - }; + } } do timed("search") { - do uint::range_rev(n_keys, 0) |i| { + for i in range(0, n_keys).invert() { assert_eq!(map.find(&i).unwrap(), &(i + 1)); - true - }; + } } do timed("remove") { - do uint::range_rev(n_keys, 0) |i| { + for i in range(0, n_keys) { assert!(map.remove(&i)); - true - }; + } } } diff --git a/src/test/bench/graph500-bfs.rs b/src/test/bench/graph500-bfs.rs index 2f4d763b84d..9725297bace 100644 --- a/src/test/bench/graph500-bfs.rs +++ b/src/test/bench/graph500-bfs.rs @@ -96,9 +96,9 @@ fn make_graph(N: uint, edges: ~[(node_id, node_id)]) -> graph { } } - do graph.consume_iter().transform |v| { + do graph.move_iter().map |v| { let mut vec = ~[]; - for i in v.consume() { + for i in v.move_iter() { vec.push(i); } vec @@ -119,7 +119,7 @@ fn gen_search_keys(graph: &[~[node_id]], n: uint) -> ~[node_id] { } } let mut vec = ~[]; - for i in keys.consume() { + for i in keys.move_iter() { vec.push(i); } return vec; @@ -193,7 +193,7 @@ fn bfs2(graph: graph, key: node_id) -> bfs_result { // Do the BFS. info!("PBFS iteration %?", i); i += 1; - colors = do colors.iter().enumerate().transform |(i, c)| { + colors = do colors.iter().enumerate().map |(i, c)| { let c : color = *c; match c { white => { @@ -220,7 +220,7 @@ fn bfs2(graph: graph, key: node_id) -> bfs_result { } // Convert the results. - do colors.iter().transform |c| { + do colors.iter().map |c| { match *c { white => { -1i64 } black(parent) => { parent } diff --git a/src/test/bench/rt-messaging-ping-pong.rs b/src/test/bench/rt-messaging-ping-pong.rs new file mode 100644 index 00000000000..3d38d61bc2e --- /dev/null +++ b/src/test/bench/rt-messaging-ping-pong.rs @@ -0,0 +1,82 @@ +// 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. + +extern mod extra; + +use std::task::spawn; +use std::os; +use std::uint; +use std::rt::test::spawntask_later; +use std::cell::Cell; + +// This is a simple bench that creates M pairs of of tasks. These +// tasks ping-pong back and forth over a pair of streams. This is a +// cannonical message-passing benchmark as it heavily strains message +// passing and almost nothing else. + +fn ping_pong_bench(n: uint, m: uint) { + + // Create pairs of tasks that pingpong back and forth. + fn run_pair(n: uint) { + // Create a stream A->B + let (pa,ca) = stream::<()>(); + // Create a stream B->A + let (pb,cb) = stream::<()>(); + + let pa = Cell::new(pa); + let ca = Cell::new(ca); + let pb = Cell::new(pb); + let cb = Cell::new(cb); + + do spawntask_later() || { + let chan = ca.take(); + let port = pb.take(); + do n.times { + chan.send(()); + port.recv(); + } + } + + do spawntask_later() || { + let chan = cb.take(); + let port = pa.take(); + do n.times { + port.recv(); + chan.send(()); + } + } + } + + do m.times { + run_pair(n) + } + +} + + + +fn main() { + + let args = os::args(); + let n = if args.len() == 3 { + uint::from_str(args[1]).unwrap() + } else { + 10000 + }; + + let m = if args.len() == 3 { + uint::from_str(args[2]).unwrap() + } else { + 4 + }; + + ping_pong_bench(n, m); + +} diff --git a/src/test/bench/rt-parfib.rs b/src/test/bench/rt-parfib.rs new file mode 100644 index 00000000000..6669342f511 --- /dev/null +++ b/src/test/bench/rt-parfib.rs @@ -0,0 +1,49 @@ +// 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. + +extern mod extra; + +use std::task::spawn; +use std::os; +use std::uint; +use std::rt::test::spawntask_later; +use std::cell::Cell; +use std::comm::*; + +// A simple implementation of parfib. One subtree is found in a new +// task and communicated over a oneshot pipe, the other is found +// locally. There is no sequential-mode threshold. + +fn parfib(n: uint) -> uint { + if(n == 0 || n == 1) { + return 1; + } + + let (port,chan) = oneshot::<uint>(); + let chan = Cell::new(chan); + do spawntask_later { + chan.take().send(parfib(n-1)); + }; + let m2 = parfib(n-2); + return (port.recv() + m2); +} + +fn main() { + + let args = os::args(); + let n = if args.len() == 2 { + uint::from_str(args[1]).unwrap() + } else { + 10 + }; + + parfib(n); + +} diff --git a/src/test/compile-fail/static-slice-not-null-terminated.rs b/src/test/bench/rt-spawn-rate.rs index 3cfaa57d540..ff578ed70b9 100644 --- a/src/test/compile-fail/static-slice-not-null-terminated.rs +++ b/src/test/bench/rt-spawn-rate.rs @@ -8,14 +8,26 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +extern mod extra; + +use std::task::spawn; +use std::os; +use std::uint; + +// Very simple spawn rate test. Spawn N tasks that do nothing and +// return. + fn main() { - let _ = (~"foo").as_bytes_with_null(); - let _ = (@"foo").as_bytes_with_null(); - // a plain static slice is null terminated, but such a slice can - // be sliced shorter (i.e. become non-null terminated) and still - // have the static lifetime - let foo: &'static str = "foo"; - let _ = foo.as_bytes_with_null(); - //~^ ERROR does not implement any method in scope named `as_bytes_with_null` + let args = os::args(); + let n = if args.len() == 2 { + uint::from_str(args[1]).unwrap() + } else { + 100000 + }; + + do n.times { + do spawn || {}; + } + } diff --git a/src/test/bench/shootout-chameneos-redux.rs b/src/test/bench/shootout-chameneos-redux.rs index 2b177ccb98f..f82c5e692e4 100644 --- a/src/test/bench/shootout-chameneos-redux.rs +++ b/src/test/bench/shootout-chameneos-redux.rs @@ -150,7 +150,7 @@ fn rendezvous(nn: uint, set: ~[color]) { // these channels will allow us to talk to each creature by 'name'/index let to_creature: ~[Chan<Option<CreatureInfo>>] = - set.iter().enumerate().transform(|(ii, col)| { + set.iter().enumerate().map(|(ii, col)| { // create each creature as a listener with a port, and // give us a channel to talk to each let ii = ii; diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 8c4e9092ce0..66b9bdc0a42 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -75,7 +75,7 @@ fn sort_and_fmt(mm: &HashMap<~[u8], uint>, total: uint) -> ~str { unsafe { let b = str::raw::from_bytes(k); // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use - // to_ascii_consume and to_str_consume to not do a unnecessary copy. + // to_ascii_move and to_str_move to not do a unnecessary copy. buffer.push_str(fmt!("%s %0.3f\n", b.to_ascii().to_upper().to_str_ascii(), v)); } } @@ -86,7 +86,7 @@ fn sort_and_fmt(mm: &HashMap<~[u8], uint>, total: uint) -> ~str { // given a map, search for the frequency of a pattern fn find(mm: &HashMap<~[u8], uint>, key: ~str) -> uint { // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use - // to_ascii_consume and to_str_consume to not do a unnecessary copy. + // to_ascii_move and to_str_move to not do a unnecessary copy. let key = key.to_ascii().to_lower().to_str_ascii(); match mm.find_equiv(&key.as_bytes()) { option::None => { return 0u; } @@ -172,7 +172,7 @@ fn main() { let sizes = ~[1u,2,3,4,6,12,18]; let mut streams = vec::from_fn(sizes.len(), |_| Some(stream::<~str>())); let mut from_child = ~[]; - let to_child = do sizes.iter().zip(streams.mut_iter()).transform |(sz, stream_ref)| { + let to_child = do sizes.iter().zip(streams.mut_iter()).map |(sz, stream_ref)| { let sz = *sz; let stream = util::replace(stream_ref, None); let (from_child_, to_parent_) = stream.unwrap(); diff --git a/src/test/bench/task-perf-one-million.rs b/src/test/bench/task-perf-one-million.rs index 7f986eab789..5efe13f8bca 100644 --- a/src/test/bench/task-perf-one-million.rs +++ b/src/test/bench/task-perf-one-million.rs @@ -28,20 +28,20 @@ fn calc(children: uint, parent_wait_chan: &Chan<Chan<Chan<int>>>) { }; let child_start_chans: ~[Chan<Chan<int>>] = - wait_ports.consume_iter().transform(|port| port.recv()).collect(); + wait_ports.move_iter().map(|port| port.recv()).collect(); let (start_port, start_chan) = stream::<Chan<int>>(); parent_wait_chan.send(start_chan); let parent_result_chan: Chan<int> = start_port.recv(); let child_sum_ports: ~[Port<int>] = - do child_start_chans.consume_iter().transform |child_start_chan| { + do child_start_chans.move_iter().map |child_start_chan| { let (child_sum_port, child_sum_chan) = stream::<int>(); child_start_chan.send(child_sum_chan); child_sum_port }.collect(); - let sum = child_sum_ports.consume_iter().fold(0, |sum, sum_port| sum + sum_port.recv() ); + let sum = child_sum_ports.move_iter().fold(0, |sum, sum_port| sum + sum_port.recv() ); parent_result_chan.send(sum + 1); } diff --git a/src/test/run-pass/extern-mod-url.rs b/src/test/codegen/single-return-value.cc index 363c54f6812..97d80d3950f 100644 --- a/src/test/run-pass/extern-mod-url.rs +++ b/src/test/codegen/single-return-value.cc @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Just a test that new-style extern mods parse - -// xfail-test FIXME #6407 -extern mod test = "github.com/catamorphism/test-pkg"; - -fn main() {} +extern "C" +int test() { + return 5; +} diff --git a/src/test/codegen/single-return-value.rs b/src/test/codegen/single-return-value.rs new file mode 100644 index 00000000000..e6eb9a2be72 --- /dev/null +++ b/src/test/codegen/single-return-value.rs @@ -0,0 +1,14 @@ +// 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. + +#[no_mangle] +fn test() -> int { + 5 +} diff --git a/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs b/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs index 39a0e585ad2..0f67d8a6d0c 100644 --- a/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs +++ b/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs @@ -6,7 +6,7 @@ struct Foo { } pub fn main() { - let x = [ + let x = ~[ Foo { string: ~"foo" }, Foo { string: ~"bar" }, Foo { string: ~"baz" } diff --git a/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs b/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs index 7f98eba5996..ca20d68e4cd 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs @@ -1,5 +1,5 @@ fn a() -> &[int] { - let vec = [1, 2, 3, 4]; + let vec = ~[1, 2, 3, 4]; let tail = match vec { [_, ..tail] => tail, //~ ERROR does not live long enough _ => fail!("a") @@ -8,7 +8,7 @@ fn a() -> &[int] { } fn b() -> &[int] { - let vec = [1, 2, 3, 4]; + let vec = ~[1, 2, 3, 4]; let init = match vec { [..init, _] => init, //~ ERROR does not live long enough _ => fail!("b") @@ -17,7 +17,7 @@ fn b() -> &[int] { } fn c() -> &[int] { - let vec = [1, 2, 3, 4]; + let vec = ~[1, 2, 3, 4]; let slice = match vec { [_, ..slice, _] => slice, //~ ERROR does not live long enough _ => fail!("c") diff --git a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs index 36ae5f88208..02ba1b9d2ff 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs @@ -1,24 +1,24 @@ fn a() { - let mut vec = [~1, ~2, ~3]; + let mut vec = ~[~1, ~2, ~3]; match vec { [~ref _a] => { - vec[0] = ~4; //~ ERROR cannot assign to `vec[]` because it is borrowed + vec[0] = ~4; //~ ERROR cannot assign to `(*vec)[]` because it is borrowed } _ => fail!("foo") } } fn b() { - let mut vec = [~1, ~2, ~3]; + let mut vec = ~[~1, ~2, ~3]; match vec { [.._b] => { - vec[0] = ~4; //~ ERROR cannot assign to `vec[]` because it is borrowed + vec[0] = ~4; //~ ERROR cannot assign to `(*vec)[]` because it is borrowed } } } fn c() { - let mut vec = [~1, ~2, ~3]; + let mut vec = ~[~1, ~2, ~3]; match vec { [_a, .._b] => { //~^ ERROR cannot move out @@ -35,7 +35,7 @@ fn c() { } fn d() { - let mut vec = [~1, ~2, ~3]; + let mut vec = ~[~1, ~2, ~3]; match vec { [.._a, _b] => { //~^ ERROR cannot move out @@ -46,7 +46,7 @@ fn d() { } fn e() { - let mut vec = [~1, ~2, ~3]; + let mut vec = ~[~1, ~2, ~3]; match vec { [_a, _b, _c] => {} _ => {} diff --git a/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs b/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs index e3e12a4a416..87511c34172 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs @@ -1,5 +1,5 @@ fn a() -> &int { - let vec = [1, 2, 3, 4]; + let vec = ~[1, 2, 3, 4]; let tail = match vec { [_a, ..tail] => &tail[0], //~ ERROR borrowed value does not live long enough _ => fail!("foo") diff --git a/src/test/compile-fail/extenv-arg-2-not-string-literal.rs b/src/test/compile-fail/extenv-arg-2-not-string-literal.rs new file mode 100644 index 00000000000..c2362689721 --- /dev/null +++ b/src/test/compile-fail/extenv-arg-2-not-string-literal.rs @@ -0,0 +1,11 @@ +// 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. + +fn main() { env!("one", 10); } //~ ERROR: expected string literal diff --git a/src/test/compile-fail/extenv-no-args.rs b/src/test/compile-fail/extenv-no-args.rs index 7ff1357dcf3..afa47dbe744 100644 --- a/src/test/compile-fail/extenv-no-args.rs +++ b/src/test/compile-fail/extenv-no-args.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. // @@ -8,6 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: env! takes 1 argument - -fn main() { env!(); } +fn main() { env!(); } //~ ERROR: env! takes 1 or 2 arguments diff --git a/src/test/compile-fail/extenv-not-defined-custom.rs b/src/test/compile-fail/extenv-not-defined-custom.rs new file mode 100644 index 00000000000..485b6c09f0a --- /dev/null +++ b/src/test/compile-fail/extenv-not-defined-custom.rs @@ -0,0 +1,11 @@ +// 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. + +fn main() { env!("__HOPEFULLY_NOT_DEFINED__", "my error message"); } //~ ERROR: my error message diff --git a/src/rt/rust_sched_reaper.cpp b/src/test/compile-fail/extenv-not-defined-default.rs index 1aef9cd5588..d7a543c045a 100644 --- a/src/rt/rust_sched_reaper.cpp +++ b/src/test/compile-fail/extenv-not-defined-default.rs @@ -8,18 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#include "rust_kernel.h" -#include "rust_sched_reaper.h" - -// NB: We're using a very small stack here -const size_t STACK_SIZE = 1024*20; - -rust_sched_reaper::rust_sched_reaper(rust_kernel *kernel) - : rust_thread(STACK_SIZE), kernel(kernel) { -} - -void -rust_sched_reaper::run() { - kernel->wait_for_schedulers(); -} +fn main() { env!("__HOPEFULLY_NOT_DEFINED__"); } //~ ERROR: Environment variable __HOPEFULLY_NOT_DEFINED__ not defined diff --git a/src/test/compile-fail/extenv-not-string-literal.rs b/src/test/compile-fail/extenv-not-string-literal.rs index 3f09f81b85b..07ce47a14d8 100644 --- a/src/test/compile-fail/extenv-not-string-literal.rs +++ b/src/test/compile-fail/extenv-not-string-literal.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. // @@ -8,6 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:requires a string - -fn main() { env!(10); } +fn main() { env!(10, "two"); } //~ ERROR: expected string literal diff --git a/src/test/compile-fail/extenv-too-many-args.rs b/src/test/compile-fail/extenv-too-many-args.rs index b1b2001abc3..c6c4f0ec6b8 100644 --- a/src/test/compile-fail/extenv-too-many-args.rs +++ b/src/test/compile-fail/extenv-too-many-args.rs @@ -8,6 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: env! takes 1 argument - -fn main() { env!("one", "two"); } +fn main() { env!("one", "two", "three"); } //~ ERROR: env! takes 1 or 2 arguments diff --git a/src/rt/rust_sched_reaper.h b/src/test/compile-fail/extoption_env-no-args.rs index 75a8d18c0ab..fd56756584a 100644 --- a/src/rt/rust_sched_reaper.h +++ b/src/test/compile-fail/extoption_env-no-args.rs @@ -8,20 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#ifndef RUST_SCHED_REAPER_H -#define RUST_SCHED_REAPER_H - -#include "sync/rust_thread.h" - -class rust_kernel; - -/* Responsible for joining with rust_schedulers */ -class rust_sched_reaper : public rust_thread { -private: - rust_kernel *kernel; -public: - rust_sched_reaper(rust_kernel *kernel); - virtual void run(); -}; - -#endif /* RUST_SCHED_REAPER_H */ +fn main() { option_env!(); } //~ ERROR: option_env! takes 1 argument diff --git a/src/test/compile-fail/extoption_env-not-string-literal.rs b/src/test/compile-fail/extoption_env-not-string-literal.rs new file mode 100644 index 00000000000..10f6c34980e --- /dev/null +++ b/src/test/compile-fail/extoption_env-not-string-literal.rs @@ -0,0 +1,11 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <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 main() { option_env!(10); } //~ ERROR: requires a string diff --git a/src/test/compile-fail/extoption_env-too-many-args.rs b/src/test/compile-fail/extoption_env-too-many-args.rs new file mode 100644 index 00000000000..b31e857c14e --- /dev/null +++ b/src/test/compile-fail/extoption_env-too-many-args.rs @@ -0,0 +1,11 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <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 main() { option_env!("one", "two"); } //~ ERROR: option_env! takes 1 argument diff --git a/src/test/compile-fail/issue-2766-a.rs b/src/test/compile-fail/issue-2766-a.rs deleted file mode 100644 index c5d13c81b7c..00000000000 --- a/src/test/compile-fail/issue-2766-a.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub mod stream { - pub enum Stream<T:Send> { send(T, ::stream::server::Stream<T>), } - pub mod server { - use std::option; - use std::pipes; - - impl<T:Send> Stream<T> { - pub fn recv() -> extern fn(v: Stream<T>) -> ::stream::Stream<T> { - // resolve really should report just one error here. - // Change the test case when it changes. - pub fn recv(pipe: Stream<T>) -> ::stream::Stream<T> { //~ ERROR attempt to use a type argument out of scope - //~^ ERROR use of undeclared type name - //~^^ ERROR attempt to use a type argument out of scope - //~^^^ ERROR use of undeclared type name - pipes::recv(pipe).unwrap() - } - recv - } - } - - pub type Stream<T:Send> = pipes::RecvPacket<::stream::Stream<T>>; - } -} - -fn main() {} diff --git a/src/test/compile-fail/issue-3763.rs b/src/test/compile-fail/issue-3763.rs index 9647d412d2c..7097615b87e 100644 --- a/src/test/compile-fail/issue-3763.rs +++ b/src/test/compile-fail/issue-3763.rs @@ -16,7 +16,7 @@ mod my_mod { MyStruct {priv_field: 4} } impl MyStruct { - priv fn happyfun(&self) {} + fn happyfun(&self) {} } } diff --git a/src/test/compile-fail/issue-3993-3.rs b/src/test/compile-fail/issue-3993-3.rs index ccda6f158ed..cab999f621d 100644 --- a/src/test/compile-fail/issue-3993-3.rs +++ b/src/test/compile-fail/issue-3993-3.rs @@ -12,8 +12,8 @@ use zoo::fly; //~ ERROR failed to resolve import //~^ ERROR unresolved import: found `fly` in `zoo` but it is private mod zoo { - priv type fly = (); - priv fn fly() {} + type fly = (); + fn fly() {} } diff --git a/src/test/compile-fail/issue-3993.rs b/src/test/compile-fail/issue-3993.rs index 450ea023bcb..53a56ad2774 100644 --- a/src/test/compile-fail/issue-3993.rs +++ b/src/test/compile-fail/issue-3993.rs @@ -12,7 +12,7 @@ use zoo::fly; //~ ERROR failed to resolve import //~^ ERROR unresolved import: found `fly` in `zoo` but it is private mod zoo { - priv fn fly() {} + fn fly() {} } diff --git a/src/test/compile-fail/macro-inner-attributes.rs b/src/test/compile-fail/macro-inner-attributes.rs new file mode 100644 index 00000000000..95000f4aa22 --- /dev/null +++ b/src/test/compile-fail/macro-inner-attributes.rs @@ -0,0 +1,21 @@ +macro_rules! test ( ($nm:ident, + $a:attr, + $i:item) => (mod $nm { $a; $i }); ) + +test!(a, + #[cfg(qux)], + pub fn bar() { }) + +test!(b, + #[cfg(not(qux))], + pub fn bar() { }) + +#[qux] +fn main() { + a::bar(); + //~^ ERROR use of undeclared module `a` + //~^^ ERROR unresolved name + //~^^^ ERROR unresolved name `a::bar` + b::bar(); +} + diff --git a/src/test/compile-fail/macro-outer-attributes.rs b/src/test/compile-fail/macro-outer-attributes.rs new file mode 100644 index 00000000000..23c3e80cd3b --- /dev/null +++ b/src/test/compile-fail/macro-outer-attributes.rs @@ -0,0 +1,19 @@ +macro_rules! test ( ($nm:ident, + $a:attr, + $i:item) => (mod $nm { $a $i }); ) + +test!(a, + #[cfg(qux)], + pub fn bar() { }) + +test!(b, + #[cfg(not(qux))], + pub fn bar() { }) + +// test1!(#[bar]) +#[qux] +fn main() { + a::bar(); //~ ERROR unresolved name `a::bar` + b::bar(); +} + diff --git a/src/test/compile-fail/match-vec-fixed.rs b/src/test/compile-fail/match-vec-fixed.rs new file mode 100644 index 00000000000..b3e139805a0 --- /dev/null +++ b/src/test/compile-fail/match-vec-fixed.rs @@ -0,0 +1,16 @@ +fn a() { + let v = [1, 2, 3]; + match v { + [_, _, _] => {} + [_, _, _] => {} //~ ERROR unreachable pattern + } + match v { + [_, 1, _] => {} + [_, 1, _] => {} //~ ERROR unreachable pattern + _ => {} + } +} + +fn main() { + a(); +} diff --git a/src/test/compile-fail/match-vec-unreachable.rs b/src/test/compile-fail/match-vec-unreachable.rs index 3930e7d2192..b557242af44 100644 --- a/src/test/compile-fail/match-vec-unreachable.rs +++ b/src/test/compile-fail/match-vec-unreachable.rs @@ -6,13 +6,13 @@ fn main() { _ => () } - match [~"foo", ~"bar", ~"baz"] { + match ~[~"foo", ~"bar", ~"baz"] { [a, _, _, .._] => { println(a); } [~"foo", ~"bar", ~"baz", ~"foo", ~"bar"] => { } //~ ERROR unreachable pattern _ => { } } - match ['a', 'b', 'c'] { + match ~['a', 'b', 'c'] { ['a', 'b', 'c', .._tail] => {} ['a', 'b', 'c'] => {} //~ ERROR unreachable pattern _ => {} diff --git a/src/test/compile-fail/private-impl-method.rs b/src/test/compile-fail/private-impl-method.rs index 26b7d73ab2a..42da53e9890 100644 --- a/src/test/compile-fail/private-impl-method.rs +++ b/src/test/compile-fail/private-impl-method.rs @@ -14,7 +14,7 @@ mod a { } impl Foo { - priv fn foo(&self) {} + fn foo(&self) {} } } diff --git a/src/test/compile-fail/private-item-simple.rs b/src/test/compile-fail/private-item-simple.rs index 8776739db2d..a31d0030f67 100644 --- a/src/test/compile-fail/private-item-simple.rs +++ b/src/test/compile-fail/private-item-simple.rs @@ -9,7 +9,7 @@ // except according to those terms. mod a { - priv fn f() {} + fn f() {} } fn main() { diff --git a/src/test/compile-fail/private-method.rs b/src/test/compile-fail/private-method.rs index 1cde50cc15e..85822765595 100644 --- a/src/test/compile-fail/private-method.rs +++ b/src/test/compile-fail/private-method.rs @@ -18,7 +18,7 @@ mod kitties { } impl cat { - priv fn nap(&self) {} + fn nap(&self) {} } pub fn cat(in_x : uint, in_y : int) -> cat { diff --git a/src/test/compile-fail/xc-private-method.rs b/src/test/compile-fail/xc-private-method.rs index e8777a0a9f2..8314755af3b 100644 --- a/src/test/compile-fail/xc-private-method.rs +++ b/src/test/compile-fail/xc-private-method.rs @@ -4,5 +4,13 @@ extern mod xc_private_method_lib; fn main() { - let _ = xc_private_method_lib::Foo::new(); //~ ERROR function `new` is private + // normal method on struct + let _ = xc_private_method_lib::Struct{ x: 10 }.meth_struct(); //~ ERROR method `meth_struct` is private + // static method on struct + let _ = xc_private_method_lib::Struct::static_meth_struct(); //~ ERROR function `static_meth_struct` is private + + // normal method on enum + let _ = xc_private_method_lib::Variant1(20).meth_enum(); //~ ERROR method `meth_enum` is private + // static method on enum + let _ = xc_private_method_lib::Enum::static_meth_enum(); //~ ERROR function `static_meth_enum` is private } diff --git a/src/test/compile-fail/xcrate-unit-struct.rs b/src/test/compile-fail/xcrate-unit-struct.rs new file mode 100644 index 00000000000..e71a0f05dff --- /dev/null +++ b/src/test/compile-fail/xcrate-unit-struct.rs @@ -0,0 +1,21 @@ +// 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. + +// aux-build:xcrate_unit_struct.rs + +// Make sure that when we have cross-crate unit structs we don't accidentally +// make values out of cross-crate structs that aren't unit. + +extern mod xcrate_unit_struct; + +fn main() { + let _ = xcrate_unit_struct::StructWithFields; //~ ERROR: unresolved name + let _ = xcrate_unit_struct::Struct; +} diff --git a/src/test/run-fail/assert-eq-macro-fail b/src/test/run-fail/assert-eq-macro-fail new file mode 100755 index 00000000000..2841756d4a0 --- /dev/null +++ b/src/test/run-fail/assert-eq-macro-fail Binary files differdiff --git a/src/test/run-pass/binops.rs b/src/test/run-pass/binops.rs index b360cc7528f..4bfdb20d9f2 100644 --- a/src/test/run-pass/binops.rs +++ b/src/test/run-pass/binops.rs @@ -81,17 +81,6 @@ fn test_ptr() { } } -mod test { - use std::libc; - - #[abi = "cdecl"] - #[nolink] - extern { - pub fn rust_get_sched_id() -> libc::intptr_t; - pub fn get_task_id() -> libc::intptr_t; - } -} - #[deriving(Eq)] struct p { x: int, diff --git a/src/test/run-pass/block-arg.rs b/src/test/run-pass/block-arg.rs index 7b74d1d314b..aabc005c57f 100644 --- a/src/test/run-pass/block-arg.rs +++ b/src/test/run-pass/block-arg.rs @@ -28,7 +28,7 @@ pub fn main() { assert!(any_negative); // Higher precedence than unary operations: - let abs_v = do v.iter().transform |e| { e.abs() }.collect::<~[float]>(); + let abs_v = do v.iter().map |e| { e.abs() }.collect::<~[float]>(); assert!(do abs_v.iter().all |e| { e.is_positive() }); assert!(!do abs_v.iter().any |e| { e.is_negative() }); diff --git a/src/test/run-pass/c-stack-as-value.rs b/src/test/run-pass/c-stack-as-value.rs index 747066cb4e8..85e22cfecb4 100644 --- a/src/test/run-pass/c-stack-as-value.rs +++ b/src/test/run-pass/c-stack-as-value.rs @@ -15,12 +15,12 @@ mod rustrt { #[abi = "cdecl"] extern { - pub fn get_task_id() -> libc::intptr_t; + pub fn rust_get_test_int() -> libc::intptr_t; } } pub fn main() { unsafe { - let _foo = rustrt::get_task_id; + let _foo = rustrt::rust_get_test_int; } } diff --git a/src/test/run-pass/c-stack-returning-int64.rs b/src/test/run-pass/c-stack-returning-int64.rs index 9775f1ef45a..e91c11f5cd0 100644 --- a/src/test/run-pass/c-stack-returning-int64.rs +++ b/src/test/run-pass/c-stack-returning-int64.rs @@ -20,11 +20,11 @@ mod libc { } fn atol(s: ~str) -> int { - s.as_imm_buf(|x, _len| unsafe { libc::atol(x) }) + s.to_c_str().with_ref(|x| unsafe { libc::atol(x as *u8) }) } fn atoll(s: ~str) -> i64 { - s.as_imm_buf(|x, _len| unsafe { libc::atoll(x) }) + s.to_c_str().with_ref(|x| unsafe { libc::atoll(x as *u8) }) } pub fn main() { diff --git a/src/test/run-pass/class-cast-to-trait-multiple-types.rs b/src/test/run-pass/class-cast-to-trait-multiple-types.rs index a5d7ba2c1aa..a134ffe49fd 100644 --- a/src/test/run-pass/class-cast-to-trait-multiple-types.rs +++ b/src/test/run-pass/class-cast-to-trait-multiple-types.rs @@ -21,7 +21,7 @@ struct dog { } impl dog { - priv fn bark(&self) -> int { + fn bark(&self) -> int { info!("Woof %u %d", *self.barks, *self.volume); *self.barks += 1u; if *self.barks % 3u == 0u { diff --git a/src/test/run-pass/const-str-ptr.rs b/src/test/run-pass/const-str-ptr.rs index 2f0cd3c611f..0e7d6d9f16a 100644 --- a/src/test/run-pass/const-str-ptr.rs +++ b/src/test/run-pass/const-str-ptr.rs @@ -10,15 +10,20 @@ use std::str; -static a: [u8, ..3] = ['h' as u8, 'i' as u8, 0 as u8]; -static c: &'static [u8, ..3] = &a; -static b: *u8 = c as *u8; +static A: [u8, ..2] = ['h' as u8, 'i' as u8]; +static B: &'static [u8, ..2] = &A; +static C: *u8 = B as *u8; pub fn main() { - let foo = &a as *u8; - assert_eq!(unsafe { str::raw::from_bytes(a) }, ~"hi\x00"); - assert_eq!(unsafe { str::raw::from_buf(foo) }, ~"hi"); - assert_eq!(unsafe { str::raw::from_buf(b) }, ~"hi"); - assert!(unsafe { *b == a[0] }); - assert!(unsafe { *(&c[0] as *u8) == a[0] }); + unsafe { + let foo = &A as *u8; + assert_eq!(str::raw::from_bytes(A), ~"hi"); + assert_eq!(str::raw::from_buf_len(foo, A.len()), ~"hi"); + assert_eq!(str::raw::from_buf_len(C, B.len()), ~"hi"); + assert!(*C == A[0]); + assert!(*(&B[0] as *u8) == A[0]); + + let bar = str::raw::from_bytes(A).to_c_str(); + assert_eq!(bar.with_ref(|buf| str::raw::from_c_str(buf)), ~"hi"); + } } diff --git a/src/test/run-pass/extoption_env-not-defined.rs b/src/test/run-pass/extoption_env-not-defined.rs new file mode 100644 index 00000000000..412efcc25a8 --- /dev/null +++ b/src/test/run-pass/extoption_env-not-defined.rs @@ -0,0 +1,14 @@ +// 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. + +fn main() { + let opt: Option<&'static str> = option_env!("__HOPEFULLY_DOESNT_EXIST__"); + assert!(opt.is_none()); +} diff --git a/src/test/run-pass/foreign-fn-linkname.rs b/src/test/run-pass/foreign-fn-linkname.rs index 38f36dd258b..b5a114ef223 100644 --- a/src/test/run-pass/foreign-fn-linkname.rs +++ b/src/test/run-pass/foreign-fn-linkname.rs @@ -26,8 +26,9 @@ mod libc { fn strlen(str: ~str) -> uint { unsafe { // C string is terminated with a zero - let bytes = str.to_bytes_with_null(); - return libc::my_strlen(vec::raw::to_ptr(bytes)); + do str.to_c_str().with_ref |buf| { + libc::my_strlen(buf as *u8) + } } } diff --git a/src/test/run-pass/issue-1251.rs b/src/test/run-pass/issue-1251.rs index 546368c8f9a..a78a10e20e8 100644 --- a/src/test/run-pass/issue-1251.rs +++ b/src/test/run-pass/issue-1251.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[link(name = "get_task_id")]; +#[link(name = "rust_get_test_int")]; mod rustrt { use std::libc; extern { - pub fn get_task_id() -> libc::intptr_t; + pub fn rust_get_test_int() -> libc::intptr_t; } } diff --git a/src/test/run-pass/issue-3121.rs b/src/test/run-pass/issue-3121.rs index 522a68856b6..206dc383cb3 100644 --- a/src/test/run-pass/issue-3121.rs +++ b/src/test/run-pass/issue-3121.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test enum side { mayo, catsup, vinegar } enum order { hamburger, fries(side), shake } enum meal { to_go(order), for_here(order) } diff --git a/src/test/run-pass/issue-4446.rs b/src/test/run-pass/issue-4446.rs index 2f44f9783e1..accf7c4e6cd 100644 --- a/src/test/run-pass/issue-4446.rs +++ b/src/test/run-pass/issue-4446.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{pipes, io, task, comm}; - fn main() { - let (port, chan) = comm::stream(); + let (port, chan) = stream(); - do task::spawn { - io::println(port.recv()); + do spawn { + println(port.recv()); } chan.send("hello, world"); diff --git a/src/test/run-pass/issue-5530.rs b/src/test/run-pass/issue-5530.rs index 002435fcb36..8e55ad90c70 100644 --- a/src/test/run-pass/issue-5530.rs +++ b/src/test/run-pass/issue-5530.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - enum Enum { Foo { foo: uint }, Bar { bar: uint } diff --git a/src/test/run-pass/item-attributes.rs b/src/test/run-pass/item-attributes.rs index 77affb5ecf3..2d2a82ddb1b 100644 --- a/src/test/run-pass/item-attributes.rs +++ b/src/test/run-pass/item-attributes.rs @@ -174,7 +174,7 @@ mod test_foreign_items { #[attr]; #[attr] - fn get_task_id() -> libc::intptr_t; + fn rust_get_test_int() -> libc::intptr_t; } } } diff --git a/src/test/run-pass/match-enum-struct-0.rs b/src/test/run-pass/match-enum-struct-0.rs new file mode 100644 index 00000000000..365729ec860 --- /dev/null +++ b/src/test/run-pass/match-enum-struct-0.rs @@ -0,0 +1,24 @@ +// 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. + +// regression test for issue #5625 + +enum E { + Foo{f : int}, + Bar +} + +pub fn main() { + let e = Bar; + match e { + Foo{f: _f} => fail!(), + _ => (), + } +} diff --git a/src/test/run-pass/match-enum-struct-1.rs b/src/test/run-pass/match-enum-struct-1.rs new file mode 100644 index 00000000000..15d24c41a3d --- /dev/null +++ b/src/test/run-pass/match-enum-struct-1.rs @@ -0,0 +1,26 @@ +// 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. + +enum E { + Foo{f : int}, + Bar +} + +pub fn main() { + let e = Foo{f: 1}; + match e { + Foo{_} => (), + _ => fail!(), + } + match e { + Foo{f: _f} => (), + _ => fail!(), + } +} diff --git a/src/test/run-pass/match-struct-0.rs b/src/test/run-pass/match-struct-0.rs new file mode 100644 index 00000000000..67e844c519e --- /dev/null +++ b/src/test/run-pass/match-struct-0.rs @@ -0,0 +1,29 @@ +// 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. + +struct Foo{ + f : int, +} + +pub fn main() { + let f = Foo{f: 1}; + match f { + Foo{f: 0} => fail!(), + Foo{_} => (), + } + match f { + Foo{f: 0} => fail!(), + Foo{f: _f} => (), + } + match f { + Foo{f: 0} => fail!(), + _ => (), + } +} diff --git a/src/test/run-pass/num-range-rev.rs b/src/test/run-pass/num-range-rev.rs index 5eecbe7e03a..ea7d4a651f7 100644 --- a/src/test/run-pass/num-range-rev.rs +++ b/src/test/run-pass/num-range-rev.rs @@ -20,11 +20,11 @@ fn int_range(lo: int, hi: int, it: &fn(int) -> bool) -> bool { } fn uint_range_rev(hi: uint, lo: uint, it: &fn(uint) -> bool) -> bool { - uint::range_rev(hi, lo, it) + range(lo, hi).invert().advance(it) } fn int_range_rev(hi: int, lo: int, it: &fn(int) -> bool) -> bool { - int::range_rev(hi, lo, it) + range(lo, hi).invert().advance(it) } fn int_range_step(a: int, b: int, step: int, it: &fn(int) -> bool) -> bool { diff --git a/src/test/run-pass/trait-to-str.rs b/src/test/run-pass/trait-to-str.rs index 3e4cfdc105c..493b810c104 100644 --- a/src/test/run-pass/trait-to-str.rs +++ b/src/test/run-pass/trait-to-str.rs @@ -16,7 +16,7 @@ extern mod std; use std::str::StrVector; use std::vec::ImmutableVector; -use std::iterator::IteratorUtil; +use std::iterator::Iterator; use std::int; trait to_str { @@ -29,7 +29,7 @@ impl to_str for int { impl<T:to_str> to_str for ~[T] { fn to_str(&self) -> ~str { - fmt!("[%s]", self.iter().transform(|e| e.to_str()).collect::<~[~str]>().connect(", ")) + fmt!("[%s]", self.iter().map(|e| e.to_str()).collect::<~[~str]>().connect(", ")) } } diff --git a/src/test/run-pass/vec-matching-autoslice.rs b/src/test/run-pass/vec-matching-autoslice.rs index d04deeac52e..13a8e324d43 100644 --- a/src/test/run-pass/vec-matching-autoslice.rs +++ b/src/test/run-pass/vec-matching-autoslice.rs @@ -1,22 +1,22 @@ pub fn main() { let x = @[1, 2, 3]; match x { - [2, .._] => ::std::util::unreachable(), + [2, .._] => fail!(), [1, ..tail] => { assert_eq!(tail, [2, 3]); } - [_] => ::std::util::unreachable(), - [] => ::std::util::unreachable() + [_] => fail!(), + [] => fail!() } let y = (~[(1, true), (2, false)], 0.5); match y { - ([_, _, _], 0.5) => ::std::util::unreachable(), + ([_, _, _], 0.5) => fail!(), ([(1, a), (b, false), ..tail], _) => { assert_eq!(a, true); assert_eq!(b, 2); assert!(tail.is_empty()); } - ([..tail], _) => ::std::util::unreachable() + ([..tail], _) => fail!() } } diff --git a/src/test/run-pass/vec-matching-fixed.rs b/src/test/run-pass/vec-matching-fixed.rs new file mode 100644 index 00000000000..234311dec33 --- /dev/null +++ b/src/test/run-pass/vec-matching-fixed.rs @@ -0,0 +1,28 @@ +fn a() { + let x = [1, 2, 3]; + match x { + [1, 2, 4] => ::std::util::unreachable(), + [0, 2, 3, .._] => ::std::util::unreachable(), + [0, .._, 3] => ::std::util::unreachable(), + [0, .._] => ::std::util::unreachable(), + [1, 2, 3] => (), + [_, _, _] => ::std::util::unreachable(), + } + match x { + [.._] => (), + } + match x { + [_, _, _, .._] => (), + } + match x { + [a, b, c] => { + assert_eq!(1, a); + assert_eq!(2, b); + assert_eq!(3, c); + } + } +} + +pub fn main() { + a(); +} diff --git a/src/test/run-pass/vec-matching.rs b/src/test/run-pass/vec-matching.rs index 5e906fa2659..c09fb8d6bc7 100644 --- a/src/test/run-pass/vec-matching.rs +++ b/src/test/run-pass/vec-matching.rs @@ -1,19 +1,19 @@ fn a() { - let x = [1]; + let x = ~[1]; match x { - [_, _, _, _, _, .._] => ::std::util::unreachable(), - [.._, _, _, _, _] => ::std::util::unreachable(), - [_, .._, _, _] => ::std::util::unreachable(), - [_, _] => ::std::util::unreachable(), + [_, _, _, _, _, .._] => fail!(), + [.._, _, _, _, _] => fail!(), + [_, .._, _, _] => fail!(), + [_, _] => fail!(), [a] => { assert_eq!(a, 1); } - [] => ::std::util::unreachable() + [] => fail!() } } fn b() { - let x = [1, 2, 3]; + let x = ~[1, 2, 3]; match x { [a, b, ..c] => { assert_eq!(a, 1); @@ -48,7 +48,28 @@ fn b() { } } +fn c() { + let x = [1]; + match x { + [2, .. _] => fail!(), + [.. _] => () + } +} + +fn d() { + let x = [1, 2, 3]; + let branch = match x { + [1, 1, .. _] => 0, + [1, 2, 3, .. _] => 1, + [1, 2, .. _] => 2, + _ => 3 + }; + assert_eq!(branch, 1); +} + pub fn main() { a(); b(); + c(); + d(); } diff --git a/src/test/run-pass/vec-tail-matching.rs b/src/test/run-pass/vec-tail-matching.rs index 27f4fc83351..6a60308f2e7 100644 --- a/src/test/run-pass/vec-tail-matching.rs +++ b/src/test/run-pass/vec-tail-matching.rs @@ -3,7 +3,7 @@ struct Foo { } pub fn main() { - let x = [ + let x = ~[ Foo { string: ~"foo" }, Foo { string: ~"bar" }, Foo { string: ~"baz" } diff --git a/src/test/run-pass/xcrate-unit-struct.rs b/src/test/run-pass/xcrate-unit-struct.rs new file mode 100644 index 00000000000..d6522231f65 --- /dev/null +++ b/src/test/run-pass/xcrate-unit-struct.rs @@ -0,0 +1,35 @@ +// 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. + +// aux-build:xcrate_unit_struct.rs +// xfail-fast +extern mod xcrate_unit_struct; + +use std::util; + +static s1: xcrate_unit_struct::Struct = xcrate_unit_struct::Struct; +static s2: xcrate_unit_struct::Unit = xcrate_unit_struct::Unit; +static s3: xcrate_unit_struct::Unit = + xcrate_unit_struct::Argument(xcrate_unit_struct::Struct); +static s4: xcrate_unit_struct::Unit = xcrate_unit_struct::Argument(s1); + +fn f1(_: xcrate_unit_struct::Struct) {} +fn f2(_: xcrate_unit_struct::Unit) {} + +fn main() { + f1(xcrate_unit_struct::Struct); + f2(xcrate_unit_struct::Unit); + f2(xcrate_unit_struct::Argument(xcrate_unit_struct::Struct)); + + f1(s1); + f2(s2); + f2(s3); + f2(s4); +} |
