##### 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 ;
~~~~~~~~
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");
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
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,
$(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))), \
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 \
$(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))), \
$$(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
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(), ~""),
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 {
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
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()
}
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))))
(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
(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))))))
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();
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
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))
}
}
}
/// DList consuming iterator
#[deriving(Clone)]
-pub struct ConsumeIterator<T> {
+pub struct MoveIterator<T> {
priv list: 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()
}
}
}
}
-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() }
}
}
-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() }
}
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()
}
}
#[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]
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))
}
}
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))
}
}
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]
}
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]
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]);
}
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]
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);
}
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();
}
}
#[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);
}
}
}
*/
// 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 {
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;
let port = Cell::new(port);
do from_fn {
- recv_one(port.take())
+ port.take().recv()
}
}
let chan = Cell::new(chan);
do task::spawn {
let chan = chan.take();
- send_one(chan, blk());
+ chan.send(blk());
}
return from_port(port);
use future::*;
use std::cell::Cell;
- use std::comm::{oneshot, send_one};
+ use std::comm::oneshot;
use std::task;
#[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");
}
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,
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() {
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
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));
}
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)
);
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)
);
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()
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
}))
}
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()
};
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);
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);
// 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;
/// 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
}
}
/// 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 }
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);
}
}
#[allow(missing_doc)];
-use std::iterator::{Iterator, IteratorUtil, Enumerate, FilterMap, Invert};
+use std::iterator::{Iterator, Enumerate, FilterMap, Invert};
use std::util::replace;
use std::vec::{VecIterator, VecMutIterator};
use std::vec;
}
/// 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))
})
}
}
#[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);
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();
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;
}
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.
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();
}
}
}
* 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.
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());
}
do (|| {
unsafe {
do task::rekillable {
- let _ = comm::recv_one(WaitEnd.take_unwrap());
+ let _ = WaitEnd.take_unwrap().recv();
}
}
}).finally {
/// parallelism.
-use std::comm::Chan;
+use std::comm::{Chan, GenericChan, GenericPort};
use std::comm;
use std::task::SchedMode;
use std::task;
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 {
*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 {
}
}
+#[cfg(stage0)]
fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> {
let mut s = match val {
Number(d) => {
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);
}
}
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
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;
}
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(", ")
}
// 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();
}
}
- 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
None
}
};
- filtered.consume_iter().filter_map(|x| filter(x)).collect()
+ filtered.move_iter().filter_map(|x| filter(x)).collect()
};
// Sort the tests alphabetically
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) }
}
/**
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;
#[cfg(test)]
mod tests {
- use time::*;
+ use super::*;
use std::float;
use std::os;
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);
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);
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);
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);
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);
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);
}
/// 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
}
}
/// 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() {
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));
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));
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;
};
let chan = chan.take();
let v = blk(&exe);
- send_one(chan, (exe, v));
+ chan.send((exe, v));
}
Right(port)
}
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,
}
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)
}
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;
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,
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;
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");
}
// 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() {
use back::passes;
+ use std::c_str::ToCStr;
use std::libc::{c_int, c_uint};
use std::path::Path;
use std::run;
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);
}
}
// 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
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);
}
}
struct ProvidedMetas {
name: Option<@str>,
vers: Option<@str>,
+ pkg_id: Option<@str>,
cmh_items: ~[@ast::MetaItem]
}
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);
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)
}
}
ProvidedMetas {
name: name,
vers: vers,
+ pkg_id: pkg_id,
cmh_items: cmh_items
}
}
// 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)
}
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();
}
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);
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
}
}
// 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);
}
}
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); }
// 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};
}
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() {
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
}
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,
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,
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");
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 = ~[];
#[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]
assert_eq!(res, ~[Path("1a"), Path("2"), Path("4a"), Path("3")]);
}
- #[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,
#[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"),
-// 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.
//
// 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>()
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
};
}
+#[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)
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),
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);
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()
}
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"),
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,
_ => ()
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(),
// 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))
}
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()))
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)
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
}
}
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,
// 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;
/* 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]
}
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) }
};
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
}
use std::hashmap::HashMap;
use syntax::ast;
+use std::vec;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::{span, dummy_sp};
*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)
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) {
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 {
}
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 => {
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,
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",
// 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);
}
// 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 {
}
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 {
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);
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');
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 = ~[];
};
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);
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));
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);
/* 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
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,
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);
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 {
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,
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);
}
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();
-// 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.
//
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> {
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)
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()
}
}
-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() {
}
libdir.to_owned()
}
+
+#[cfg(not(stage0))]
+pub fn libdir() -> ~str {
+ (env!("CFG_LIBDIR")).to_owned()
+}
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;
diag: @span_handler,
filesearch: @FileSearch,
span: span,
- ident: ast::ident,
+ ident: @str,
metas: ~[@ast::MetaItem],
hash: @str,
os: os,
None => {
cx.diag.span_fatal(cx.span,
fmt!("can't find crate for `%s`",
- token::ident_to_str(&cx.ident)));
+ cx.ident));
}
}
}
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,
}
cx.diag.handler().abort_if_errors();
None
- }
}
+ }
}
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]) {
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());
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]>; }
}
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);
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])
}
}
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)
}
};
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")
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() }
}
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 {
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.
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")
}
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()
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()
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) => {
}
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)
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)
}
}
// 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)) => {
-// 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.
//
}
}
- 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
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",
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) {
// 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
// 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_ge(uint, /* slice */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) {
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;
}
}
-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) {
}
#[deriving(Clone)]
-pub enum TransBindingMode {
+enum TransBindingMode {
TrByValue(/*llbinding:*/ ValueRef),
TrByRef,
}
* - `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>
}
}
}
-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,
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)
}
}
-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,
}
}
-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,
return result;
}
-pub fn enter_default<'r>(bcx: @mut Block,
+fn enter_default<'r>(bcx: @mut Block,
dm: DefMap,
m: &[Match<'r>],
col: uint,
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
}
// <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,
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)
}
}
}
-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,
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)
}
}
}
-pub fn enter_tup<'r>(bcx: @mut Block,
+fn enter_tup<'r>(bcx: @mut Block,
dm: DefMap,
m: &[Match<'r>],
col: uint,
}
}
-pub fn enter_tuple_struct<'r>(bcx: @mut Block,
+fn enter_tuple_struct<'r>(bcx: @mut Block,
dm: DefMap,
m: &[Match<'r>],
col: uint,
}
}
-pub fn enter_box<'r>(bcx: @mut Block,
+fn enter_box<'r>(bcx: @mut Block,
dm: DefMap,
m: &[Match<'r>],
col: uint,
}
}
-pub fn enter_uniq<'r>(bcx: @mut Block,
+fn enter_uniq<'r>(bcx: @mut Block,
dm: DefMap,
m: &[Match<'r>],
col: uint,
}
}
-pub fn enter_region<'r>(bcx: @mut Block,
+fn enter_region<'r>(bcx: @mut Block,
dm: DefMap,
m: &[Match<'r>],
col: uint,
// 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;}
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)
}
-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,
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() {
}
}
-pub fn pats_require_rooting(bcx: @mut Block,
+fn pats_require_rooting(bcx: @mut Block,
m: &[Match],
col: uint)
-> bool {
}
}
-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)
)
)
-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 {
}
}
-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,
// 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)
return bcx;
}
-pub fn compile_guard(bcx: @mut Block,
+fn compile_guard(bcx: @mut Block,
guard_expr: @ast::expr,
data: &ArmData,
m: &[Match],
}
}
-pub fn compile_submatch(bcx: @mut Block,
+fn compile_submatch(bcx: @mut Block,
m: &[Match],
vals: &[ValueRef],
chk: Option<mk_fail>) {
// 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) {
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 {
}
}
-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`.
}
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);
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]>();
# Translation of inline assembly.
*/
+use std::c_str::ToCStr;
use lib;
use middle::trans::build::*;
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)
}
};
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;
}
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())
}
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);
// 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)
}
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,
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);
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)
}
}
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)
}
}
// 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, }
};
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)
}
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)
};
};
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)
};
(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);
}
}
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)
};
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);
}
},
}
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)
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)
}
}
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)
}
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)
}
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)
}
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)
}
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);
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);
--- /dev/null
+// 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
+ }
+ }
+}
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)
}
}
}
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)
}
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)
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));
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);
use middle::trans::type_::Type;
+use std::c_str::ToCStr;
use std::cast::transmute;
use std::cast;
use std::hashmap::{HashMap};
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) {
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)
}
}
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);
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)])
}
}
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()
}
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))
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))
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()
}
use middle::trans::type_::Type;
+use std::c_str::ToCStr;
use std::libc::c_uint;
use syntax::{ast, ast_util, ast_map};
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);
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 {
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);
use middle::trans::type_::Type;
+use std::c_str::ToCStr;
use std::hash;
use std::hashmap::{HashMap, HashSet};
use std::local_data;
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);
// 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;
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);
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;
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),
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),
};
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),
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,
};
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)
}
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),
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),
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),
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),
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,
Some(discriminant_type_metadata),
span);
- do "".as_c_str |name| {
+ do "".to_c_str().with_ref |name| {
unsafe {
llvm::LLVMDIBuilderCreateMemberType(
DIB(cx),
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),
{
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)
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),
})
.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),
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),
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), _}) => {
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));
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));
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)
use middle::trans::type_::Type;
+use std::c_str::ToCStr;
use std::libc::c_uint;
use syntax::ast;
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)
}
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;
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);
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);
pub mod adt;
pub mod asm;
pub mod type_;
+pub mod value;
+pub mod basic_block;
}
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 {
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()
};
// 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)
}).collect()
}
None => {
- precise_param_ids.iter().transform(|x| {
+ precise_param_ids.iter().map(|x| {
let (a, b) = *x;
mono_precise(a, b)
}).collect()
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 ]));
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());
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);
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, _) => {
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)
}
use syntax::ast;
use syntax::abi::{Architecture, X86, X86_64, Arm, Mips};
+use std::c_str::ToCStr;
use std::vec;
use std::cast;
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 {
--- /dev/null
+// 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() }
+ }
+}
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);
_
}, _) => {
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,
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")
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
-> 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);
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)
}
_ => ()
}
- 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,
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
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();
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);
}
// 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(
-> ~[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,
}
*/
+#[cfg(stage0)]
pub fn version(argv0: &str) {
let mut vers = ~"unknown version";
let env_vers = env!("CFG_VERSION");
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\
");
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();
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),
// 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);
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()
}
}
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() {
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();
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();
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),
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()
}
};
- 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();
}
};
- 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
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 {
) -> 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 {
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,
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))
) -> 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
) -> 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
) -> 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
) -> 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
) -> 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
) -> 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
doc::ModTag(_) | doc::NmodTag(_) => false,
_ => true
}
- }.transform(|x| (*x).clone()).collect::<~[doc::ItemTag]>(),
+ }.map(|x| (*x).clone()).collect::<~[doc::ItemTag]>(),
.. doc.clone()
}
}
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
}
}
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());
ast::private => false,
ast::inherited => item_vis == ast::public
}
- }.transform(|x| (*x).clone()).collect();
+ }.map(|x| (*x).clone()).collect();
doc::ImplDoc {
methods: methods,
is_visible(fold.ctxt.clone(), item_tag.item())
}
}
- }).transform(|x| (*x).clone()).collect(),
+ }).map(|x| (*x).clone()).collect(),
.. doc
}
}
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| {
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();
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()
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,
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) => {
}
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);
}
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) }
// 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);
}
// 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,
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 {
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), ~[]);
}
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: ~[],
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)});
}
use std::hashmap::HashMap;
+use std::os;
pub struct Ctx {
// Sysroot -- if this is None, uses rustc filesearch's
// 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"))
+ }
+ }
+}
// Listing installed packages
+use rustc::metadata::filesearch::rust_path;
use path_util::*;
use std::os;
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| {
false
};
is_installed
-}
\ No newline at end of file
+}
// 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))
}
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;
}
};
- 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()
+}
+++ /dev/null
-// 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()
-}
use target::*;
use package_id::PkgId;
use std::path::Path;
-use std::{os, str};
+use std::os;
use context::*;
use crate::Crate;
use messages::*;
// 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],
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: ~[],
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() {
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) {
}
/// 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) {
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,
fn build_crates(&self,
ctx: &Ctx,
- dst_dir: &Path,
src_dir: &Path,
crates: &[Crate],
cfgs: &[~str],
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,
}
}
- 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);
}
}
// 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() {
/// 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
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
}
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) {
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) {
/// 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")
}
/// 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);
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());
// 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) {
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>.
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
}
/// 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() },
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;
mod installed_packages;
mod messages;
mod package_id;
-mod package_path;
mod package_source;
mod path_util;
mod search;
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)
}
}
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());
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
}
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);
}
"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
};
}
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;
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(),
}
// 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
// Find crates inside the workspace
src.find_crates();
// Build it!
- src.build(self, build_dir, cfgs);
+ src.build(self, cfgs);
}
}
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)) {
};
}
- 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
// 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::*;
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()),
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,
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
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)
}
}
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()));
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(),
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 {
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) {
}
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 {
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)
}
/// 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 {
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()
}
}
-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));
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,
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);
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 = (); }");
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);
*/
- 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());
}
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());
}
"#[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)",
}
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"));
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");
}
#[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");
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) }));
}
#[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",
#[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);
// ("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);
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());
#[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,
#[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,
#[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"));
#[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"));
#[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
#[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);
}
#[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);
}
#[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);
}
#[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);
#[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 = (); }");
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
+ }
+}
// 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};
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,
}
}
-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)
}
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,
+ 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()
// 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);
// 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
}
// 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());
// 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)
}
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...")
#[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
}
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 {
}
}
-/// 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);
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..");
}
/// 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
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) {
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
// 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() {
}
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()
}
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))
}
* 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
}
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 *()
}
}
}
}
#[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]
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))]
--- /dev/null
+// 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);
+ }
+}
}
}
+ #[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"));
+ }
+ }
+
}
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))]
#[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)]
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;
- }
-}
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(
#[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) }
}
#[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> {
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 {
- 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 {
-
- 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 {
- 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 {
- 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() }
}
}
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)
use clone::Clone;
use cmp::{Eq, Equiv};
use hash::Hash;
-use iterator::{Iterator, IteratorUtil, FromIterator, Extendable};
+use iterator::{Iterator, FromIterator, Extendable};
use iterator::{FilterMap, Chain, Repeat, Zip};
use num;
use option::{None, Option, Some};
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);
}
}
/// 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()}
}
}
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
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> {
}
}
-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 {
}
}
-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 {
/// 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
/// 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
/// 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))
}
}
}
#[test]
- fn test_consume() {
+ fn test_move_iter() {
let hm = {
let mut hm = HashMap::new();
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);
}
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));
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));
}
#[test]
- fn test_consume() {
+ fn test_move_iter() {
let hs = {
let mut hs = HashSet::new();
hs
};
- let v = hs.consume().collect::<~[char]>();
+ let v = hs.move_iter().collect::<~[char]>();
assert!(['a', 'b'] == v || ['b', 'a'] == v);
}
}
use cast;
use clone::Clone;
+use c_str::ToCStr;
use container::Container;
use int;
use iterator::Iterator;
}
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) }
}
};
}
}
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) {
// 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)
}
};
(*bytes).clone()
}
+#[cfg(stage0)]
pub fn with_str_writer(f: &fn(@Writer)) -> ~str {
let mut v = with_bytes_writer(f);
}
}
+#[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 {
/// 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.
/// ~~~ {.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
/// 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.
///
///
/// ~~~ {.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
/// 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.
/// 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.
/// 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
/// 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
/// 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.
/// 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.
///
///
/// ~~~ {.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
/// 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
/// ~~~ {.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 {
/// 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
/// ~~~ {.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.
///
/// 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`.
///
/// ~~~ {.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.
///
/// ~~~ {.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.
/// 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.
/// 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.
/// 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
/// ~~~ {.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.
///
/// 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.
/// 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; } }
/// 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) }
}
None
}
+ /// Count the number of elements satisfying the specified predicate
#[inline]
fn count(&mut self, predicate: &fn(A) -> bool) -> uint {
let mut i = 0;
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| {
}).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| {
}
}
+/// 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
///
/// ~~~ {.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;
/// # 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));
#[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]);
}
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]);
}
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]);
#[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]);
}
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]);
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]);
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());
#[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);
}
#[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]
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));
#[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));
#[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]
#[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);
}
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));
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)
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);
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);
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]
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));
}
#[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));
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);
}
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"]
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 ;
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();
}
/**
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) {
}
}
}
-
-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);
- }
-}
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))]
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))]
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))]
/// 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}
}
#[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;
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);
}
}
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]))
}
}
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
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))
}
}
}
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);
}
}
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);
}
}
}
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)
}
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)
}
}
}
/// 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
}
}
/// 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
}
}
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)
}
}
#[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)
}
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(
closedir(dir_ptr);
}
else {
- debug!("os::list_dir -- opendir() FAILURE");
+ debug!("os::list_dir -- opendir() FAILURE");
}
debug!(
"os::list_dir -- AFTER -- #: %?",
FindNextFileW,
FindClose,
};
+ use libc::types::os::arch::extra::HANDLE;
use os::win32::{
as_utf16_p
};
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 {
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)
strings
}
}
- do get_list(p).consume_iter().filter |filename| {
+ do get_list(p).move_iter().filter |filename| {
"." != *filename && ".." != *filename
}.collect()
}
#[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)
}
#[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)
}
#[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)
}
};
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)
}
};
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...
#[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)
}
}
}
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)
+ }
}
}
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)
+ }
}
}
*/
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] {
#[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")
}
}
}
unsafe {
- LocalFree(cast::transmute(szArgList));
+ LocalFree(szArgList as *c_void);
}
return args;
}
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(|| {
#[cfg(test)]
mod tests {
+ use c_str::ToCStr;
use libc::{c_int, c_void, size_t};
use libc;
use option::Some;
use rand;
use run;
use str::StrSlice;
- use vec::CopyableVector;
use libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
#[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)));
}
}
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
#[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;
/// 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")]
#[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),
#[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),
#[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),
}
}
+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 {
self.is_ancestor_of(&other.pop()))
}
+ fn components(self) -> ~[~str] { self.components }
}
}
}
+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 {
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,
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,
(!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] {
}
+ #[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("."));
+
+ }
+
}
+++ /dev/null
-// 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 }
-}
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;
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};
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};
use super::*;
use prelude::*;
+ use c_str::ToCStr;
use cast;
use libc;
use str;
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);
#[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))]
match *self {
Ok(ref t) => Some(t),
Err(*) => None,
- }.consume()
+ }.move_iter()
}
/// Call a method based on a previous result
match *self {
Ok(*) => None,
Err(ref t) => Some(t),
- }.consume()
+ }.move_iter()
}
/// Unwraps a result, yielding the content of an `Ok`.
// 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};
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;
}
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() {
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
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)
}
}
}
//! 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);
}
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
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;
-}
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};
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.
// '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;
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 {
//! 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.
// 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>;
// 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;
}
// 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();
}
}
}
+
+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");
+ }
+
+}
};
// 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.
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;
// 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)]
/// 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) }
}
}
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;
/// 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
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 = ~[];
// 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);
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));
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);
}
rtdebug!("waiting for threads");
// Wait for schedulers
- for thread in threads.consume_iter() {
+ for thread in threads.move_iter() {
thread.join();
}
}
}
-/// 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
+ }
}
}
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};
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
/// 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.
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 {
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)
}
// 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>)
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()
}
}
// 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.
}
}
- // 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);
}
}
GiveTask(task, f) => f.to_fn()(self, task)
}
}
-
}
// The cases for the below function.
#[cfg(test)]
mod test {
+ extern mod extra;
+
use prelude::*;
use rt::test::*;
use unstable::run_in_bare_thread;
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());
// 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));
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;
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 {
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 {
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.
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.
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);
}
}
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;
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
};
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();
}
// Wait for schedulers
- for thread in threads.consume_iter() {
+ for thread in threads.move_iter() {
thread.join();
}
}
use container::Container;
use from_str::FromStr;
-use iterator::IteratorUtil;
use libc;
use option::{Some, None};
use os;
use vec;
use str;
use from_str::{FromStr};
-use num;
pub enum UvSocketAddr {
UvIpv4SocketAddr(*sockaddr_in),
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 {
// 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;
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)
}
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)
}
#[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;
}
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)
}
}
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);
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;
#[allow(missing_doc)];
+use c_str::ToCStr;
use cast;
use clone::Clone;
use comm::{stream, SharedChan, GenericChan, GenericPort};
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);
}
#[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())
}
}
// 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())
}
}
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)));
}
}
}
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;
pub use kinds;
pub use local_data;
pub use sys;
- pub use pipes;
pub use unstable;
pub use str;
pub use os;
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};
use ptr::RawPtr;
use to_str::ToStr;
use uint;
+#[cfg(stage0)]
use unstable::raw::Repr;
use vec;
use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector, MutableVector};
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 {
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 {
}
}
-/// 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
/// # Failure
///
/// Fails if invalid UTF-8
+#[cfg(stage0)]
pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str {
unsafe {
assert!(is_utf8(vector));
}
}
+/// 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() }
/// # 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 = ~"";
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);
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 ~""; }
// 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;
}
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
*/
/// Bytewise slice equality
-#[cfg(not(test))]
+#[cfg(not(test), stage0)]
#[lang="str_eq"]
#[inline]
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| {
}
}
+/// 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"]
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| {
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.
/// 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)
}
/// 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;
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`).
///
/// 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| {
}
}
+ /// 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();
}
/// 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);
*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 {
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 {
}
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 {
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
/// ~~~
#[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.
/// 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
/// 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 }
/// 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`)
}
/// Copy a slice into a new unique str
+ #[cfg(stage0)]
#[inline]
fn to_owned(&self) -> ~str {
do self.as_imm_buf |src, len| {
}
}
+ /// 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| {
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 = ~[];
/// 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();
}
}
+ /// 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
}
/// 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
}
}
+ /// 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
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)]
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.
///
/// * s - A string
/// * n - The number of bytes to reserve space for
+ #[cfg(stage0)]
#[inline]
pub fn reserve(&mut self, n: uint) {
unsafe {
}
}
+ /// 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.
///
///
/// * 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();
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) }
#[cfg(test)]
mod tests {
- use iterator::IteratorUtil;
use container::Container;
use option::Some;
use libc::c_char;
}
#[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");
}
}
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";
// 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);
}
}
}
#[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";
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};
}
}
-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())
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`
}
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]
}
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) }
}
}
impl ToBytesConsume for ~[Ascii] {
fn into_bytes(self) -> ~[u8] {
- unsafe {cast::transmute(self)}
+ unsafe { cast::transmute(self) }
}
}
#[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 {
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)
}
}
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)
}
}
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();
}
}
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)
}
}
}
// 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 {
}
match handle {
- OldHandle(task) => oldsched_map(task),
NewHandle(local_storage) => newsched_map(local_storage)
}
}
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;
#[cfg(test)] use task;
mod local_data_priv;
-pub mod rt;
pub mod spawn;
/**
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);
}
}
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
}
}
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()
}
}
}
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()
}
}
#[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
}
}
+++ /dev/null
-// 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);
-}
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;
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;
// 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()),
}
}
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),
}
}
assert!(was_present);
}
#[inline]
- fn consume(self) -> HashSetConsumeIterator<TaskHandle> {
- (*self).consume()
+ fn move_iter(self) -> HashSetMoveIterator<TaskHandle> {
+ (*self).move_iter()
}
}
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);
}
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| {
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"),
}
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>();
// 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>();
}
Some(ref group) => group,
})
- },
- SchedulerContext | GlobalContext => rtabort!("spawning in bad context"),
+ }
+ } else {
+ rtabort!("spawning in bad context")
}
}
}
-> 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| {
}
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")
}
}
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));
}
-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();
use cast;
use io;
use io::Writer;
-use iterator::IteratorUtil;
+use iterator::Iterator;
use option::{None, Option, Some};
use str::StrSlice;
use vec::ImmutableVector;
//! 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;
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> {
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 {
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));
}
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)]
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));
use clone::Clone;
use vec;
use vec::ImmutableVector;
-use iterator::IteratorUtil;
+use iterator::Iterator;
pub use self::inner::*;
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()
}
}
}
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()
}
}
}
A simple wrapper over the platforms dynamic library facilities
*/
+use c_str::ToCStr;
use cast;
use path;
use libc;
// 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)
}
};
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
mod dl {
+ use c_str::ToCStr;
use libc;
use path;
use ptr;
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)
}
}
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()
// 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);
}
//! 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);
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
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();
+ };
}
}
// 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()
}
}
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);
}
/// 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()
}
/**
#[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);
/// 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 }
}
/**
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 {
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()
}
}
/// 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
/// 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()
}
}
#[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]
}
assert_eq!(cnt, 8);
- for f in v.consume_iter() {
+ for f in v.move_iter() {
assert!(f == Foo);
cnt += 1;
}
#[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]),
}
}
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
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) => {
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 */
// 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, _)| {
}
// 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 {
-// 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.
//
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 &&
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"),
}
}
-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,
// 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)
}
// 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
// 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) =>
// 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 {
}
}
- 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
}
// 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),
// ... 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) {
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();
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);
}
}
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();
// 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)
}
}
}
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)
}
}
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)
// 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
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);
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);
-// 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.
//
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)
}
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 () {
-// 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.
//
}
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) -> ! {
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) => {
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();
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"), ~[
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 {
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"), ~[
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, ~[
};
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| {
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) => {
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,
// ...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(),
}
}
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(),
}
}
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))
})
}
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),
}
}
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);
*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()
}
#[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())}
}
#[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;
}
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 => {}
}
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) {
}
}
- fn ne(&self, other: &OptVec<A>) -> bool {
+ pub fn ne(&self, other: &OptVec<A>) -> bool {
!self.eq(other)
}
}
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);
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,
self.this_token_to_str()));
}
- (ast::anonymous,
+ (ast::anonymous, None,
special_idents::clownshoes_foreign_mod)
}
};
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)
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(),
} 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");
};
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));
// 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"
+++ /dev/null
-// 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:
-//
/* 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>
}
#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();
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) {
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;
}
}
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*
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;
#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
delete 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) {
change_dir_lock.unlock();
}
+// Used by i386 __morestack
+extern "C" CDECL uintptr_t
+rust_get_task() {
+ return 0;
+}
+
//
// Local Variables:
// mode: C++
#ifndef RUST_CRATE_MAP_H
#define RUST_CRATE_MAP_H
-#include "rust_log.h"
+#include "rust_globals.h"
#include <stdint.h>
struct mod_entry {
+++ /dev/null
-// 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
+++ /dev/null
-// 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
+++ /dev/null
-// 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:
-//
+++ /dev/null
-// 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:
-//
#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
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;
// except according to those terms.
-#include "rust_kernel.h"
+#include "rust_globals.h"
#ifdef __APPLE__
#include <crt_externs.h>
+++ /dev/null
-// 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();
-}
+++ /dev/null
-// 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 */
+++ /dev/null
-// 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;
-}
+++ /dev/null
-// 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
+++ /dev/null
-// 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:
-//
+++ /dev/null
-// 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 */
+++ /dev/null
-// 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_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();
-}
+++ /dev/null
-// 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_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 */
+++ /dev/null
-// 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;
-}
+++ /dev/null
-// 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 */
+++ /dev/null
-// 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:
-//
+++ /dev/null
-// 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 */
// 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.
*/
#include "rust_globals.h"
-#include "rust_task.h"
-#include "rust_sched_loop.h"
#include "rust_upcall.h"
#include "rust_util.h"
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*);
/**********************************************************************
*/
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);
}
/*
*/
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);
}
/**********************************************************************/
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
// 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
- }
}
//
#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;
#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,
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;
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();
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);
uv_close(handle, foreign_close_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);
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) {
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);
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);
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,
-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
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
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
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
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
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
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
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
rust_take_change_dir_lock
rust_drop_change_dir_lock
rust_get_test_int
+rust_get_task
\ No newline at end of file
#[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
+ }
+ }
}
}
}
- 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
}
}
let mut vec = ~[];
- for i in keys.consume() {
+ for i in keys.move_iter() {
vec.push(i);
}
return vec;
// 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 => {
}
// Convert the results.
- do colors.iter().transform |c| {
+ do colors.iter().map |c| {
match *c {
white => { -1i64 }
black(parent) => { parent }
--- /dev/null
+// 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);
+
+}
--- /dev/null
+// 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);
+
+}
--- /dev/null
+// 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;
+
+// Very simple spawn rate test. Spawn N tasks that do nothing and
+// return.
+
+fn main() {
+
+ let args = os::args();
+ let n = if args.len() == 2 {
+ uint::from_str(args[1]).unwrap()
+ } else {
+ 100000
+ };
+
+ do n.times {
+ do spawn || {};
+ }
+
+}
// 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;
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));
}
}
// 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; }
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();
};
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);
}
--- /dev/null
+// 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 "C"
+int test() {
+ return 5;
+}
--- /dev/null
+// 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
+}
}
pub fn main() {
- let x = [
+ let x = ~[
Foo { string: ~"foo" },
Foo { string: ~"bar" },
Foo { string: ~"baz" }
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")
}
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")
}
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")
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
}
fn d() {
- let mut vec = [~1, ~2, ~3];
+ let mut vec = ~[~1, ~2, ~3];
match vec {
[.._a, _b] => {
//~^ ERROR cannot move out
}
fn e() {
- let mut vec = [~1, ~2, ~3];
+ let mut vec = ~[~1, ~2, ~3];
match vec {
[_a, _b, _c] => {}
_ => {}
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")
--- /dev/null
+// 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
-// 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.
//
// 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
--- /dev/null
+// 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
--- /dev/null
+// 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.
+
+fn main() { env!("__HOPEFULLY_NOT_DEFINED__"); } //~ ERROR: Environment variable __HOPEFULLY_NOT_DEFINED__ not defined
-// 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.
//
// 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
// 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
--- /dev/null
+// 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.
+
+fn main() { option_env!(); } //~ ERROR: option_env! takes 1 argument
--- /dev/null
+// 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
--- /dev/null
+// 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
+++ /dev/null
-// 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() {}
--- /dev/null
+fn a() {
+ let v = [1, 2, 3];
+ match v {
+ [_, _, _] => {}
+ [_, _, _] => {} //~ ERROR unreachable pattern
+ }
+ match v {
+ [_, 1, _] => {}
+ [_, 1, _] => {} //~ ERROR unreachable pattern
+ _ => {}
+ }
+}
+
+fn main() {
+ a();
+}
_ => ()
}
- 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
_ => {}
+++ /dev/null
-// 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 _ = (~"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`
-}
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
}
}
}
-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,
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() });
#[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;
}
}
}
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() {
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");
+ }
}
+++ /dev/null
-// 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.
-
-// Just a test that new-style extern mods parse
-
-// xfail-test FIXME #6407
-extern mod test = "github.com/catamorphism/test-pkg";
-
-fn main() {}
--- /dev/null
+// 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());
+}
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)
+ }
}
}
// 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;
}
}
// 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");
// 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 }
#[attr];
#[attr]
- fn get_task_id() -> libc::intptr_t;
+ fn rust_get_test_int() -> libc::intptr_t;
}
}
}
--- /dev/null
+// 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!(),
+ _ => (),
+ }
+}
--- /dev/null
+// 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!(),
+ }
+}
--- /dev/null
+// 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!(),
+ _ => (),
+ }
+}
use std::str::StrVector;
use std::vec::ImmutableVector;
-use std::iterator::IteratorUtil;
+use std::iterator::Iterator;
use std::int;
trait to_str {
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(", "))
}
}
--- /dev/null
+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();
+}
fn a() {
- let x = [1];
+ let x = ~[1];
match x {
[_, _, _, _, _, .._] => ::std::util::unreachable(),
[.._, _, _, _, _] => ::std::util::unreachable(),
}
fn b() {
- let x = [1, 2, 3];
+ let x = ~[1, 2, 3];
match x {
[a, b, ..c] => {
assert_eq!(a, 1);
}
pub fn main() {
- let x = [
+ let x = ~[
Foo { string: ~"foo" },
Foo { string: ~"bar" },
Foo { string: ~"baz" }