##### 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
When building a package that is not under version control,
or that has no tags, `rustpkg` assumes the intended version is 0.1.
+> **Note:** A future version of rustpkg will support semantic versions.
+> Also, a future version will add the option to specify a version with a metadata
+> attribute like `#[link(vers = "3.1415")]` inside the crate module,
+> though this attribute will never be mandatory.
+
# Dependencies
rustpkg infers dependencies from `extern mod` directives.
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,
# impl Shape for CircleStruct { fn area(&self) -> float { pi * square(self.radius) } }
let concrete = @CircleStruct{center:Point{x:3f,y:4f},radius:5f};
-let mycircle: Circle = concrete as @Circle;
+let mycircle: @Circle = concrete as @Circle;
let nonsense = mycircle.radius() * mycircle.area();
~~~
$(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))))))
--sysroot'[Override the system root]'
--test'[Build a test harness]'
--target'[Target triple cpu-manufacturer-kernel\[-os\] to compile]'
- --target-feature'[Target specific attributes (llc -mattr=help for detail)]'
+ --target-cpu'[Select target processor (llc -mcpu=help for details)]'
+ --target-feature'[Target specific attributes (llc -mattr=help for details)]'
--android-cross-path'[The path to the Android NDK]'
{-v,--version}'[Print version info and exit]'
)
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))
}
}
}
use std::ptr;
use std::util;
use std::iterator::{FromIterator, Extendable, Invert};
+use std::iterator;
use container::Deque;
/// 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: Eq> Eq for DList<A> {
fn eq(&self, other: &DList<A>) -> bool {
self.len() == other.len() &&
- self.iter().zip(other.iter()).all(|(a, b)| a.eq(b))
+ iterator::order::eq(self.iter(), other.iter())
}
- #[inline]
fn ne(&self, other: &DList<A>) -> bool {
- !self.eq(other)
+ self.len() != other.len() &&
+ iterator::order::ne(self.iter(), other.iter())
+ }
+}
+
+impl<A: Eq + Ord> Ord for DList<A> {
+ fn lt(&self, other: &DList<A>) -> bool {
+ iterator::order::lt(self.iter(), other.iter())
+ }
+ fn le(&self, other: &DList<A>) -> bool {
+ iterator::order::le(self.iter(), other.iter())
+ }
+ fn gt(&self, other: &DList<A>) -> bool {
+ iterator::order::gt(self.iter(), other.iter())
+ }
+ fn ge(&self, other: &DList<A>) -> bool {
+ iterator::order::ge(self.iter(), other.iter())
}
}
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]
assert_eq!(&n, &m);
}
+ #[test]
+ fn test_ord() {
+ let n: DList<int> = list_from([]);
+ let m = list_from([1,2,3]);
+ assert!(n < m);
+ assert!(m > n);
+ assert!(n <= n);
+ assert!(n >= n);
+ }
+
+ #[test]
+ fn test_ord_nan() {
+ let nan = 0.0/0.0;
+ let n = list_from([nan]);
+ let m = list_from([nan]);
+ assert!(!(n < m));
+ assert!(!(n > m));
+ assert!(!(n <= m));
+ assert!(!(n >= m));
+
+ let n = list_from([nan]);
+ let one = list_from([1.0]);
+ assert!(!(n < one));
+ assert!(!(n > one));
+ assert!(!(n <= one));
+ assert!(!(n >= one));
+
+ let u = list_from([1.0,2.0,nan]);
+ let v = list_from([1.0,2.0,3.0]);
+ assert!(!(u < v));
+ assert!(!(u > v));
+ assert!(!(u <= v));
+ assert!(!(u >= v));
+
+ let s = list_from([1.0,2.0,4.0,2.0]);
+ let t = list_from([1.0,2.0,3.0,2.0]);
+ assert!(!(s < t));
+ assert!(s > one);
+ assert!(!(s <= one));
+ assert!(s >= one);
+ }
+
#[test]
fn test_fuzz() {
do 25.times {
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
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);
use std::util::{swap, replace};
-use std::iterator::{FromIterator, Extendable};
+use std::iterator::{FromIterator, Extendable, Peekable};
+use std::cmp::Ordering;
// This is implemented as an AA tree, which is a simplified variation of
// a red-black tree where red (horizontal) nodes can only be added
}
/// 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() {
/// Visit the values (in-order) representing the difference
pub fn difference<'a>(&'a self, other: &'a TreeSet<T>) -> Difference<'a, T> {
- Difference{a: Focus::new(self.iter()), b: Focus::new(other.iter())}
+ Difference{a: self.iter().peekable(), b: other.iter().peekable()}
}
/// Visit the values (in-order) representing the symmetric difference
pub fn symmetric_difference<'a>(&'a self, other: &'a TreeSet<T>)
-> SymDifference<'a, T> {
- SymDifference{a: Focus::new(self.iter()), b: Focus::new(other.iter())}
+ SymDifference{a: self.iter().peekable(), b: other.iter().peekable()}
}
/// Visit the values (in-order) representing the intersection
pub fn intersection<'a>(&'a self, other: &'a TreeSet<T>)
-> Intersection<'a, T> {
- Intersection{a: Focus::new(self.iter()), b: Focus::new(other.iter())}
+ Intersection{a: self.iter().peekable(), b: other.iter().peekable()}
}
/// Visit the values (in-order) representing the union
pub fn union<'a>(&'a self, other: &'a TreeSet<T>) -> Union<'a, T> {
- Union{a: Focus::new(self.iter()), b: Focus::new(other.iter())}
+ Union{a: self.iter().peekable(), b: other.iter().peekable()}
}
}
priv iter: TreeMapRevIterator<'self, T, ()>
}
-// Encapsulate an iterator and hold its latest value until stepped forward
-struct Focus<A, T> {
- priv iter: T,
- priv focus: Option<A>,
-}
-
-impl<A, T: Iterator<A>> Focus<A, T> {
- fn new(mut it: T) -> Focus<A, T> {
- Focus{focus: it.next(), iter: it}
- }
- fn step(&mut self) {
- self.focus = self.iter.next()
- }
-}
-
/// Lazy iterator producing elements in the set difference (in-order)
pub struct Difference<'self, T> {
- priv a: Focus<&'self T, TreeSetIterator<'self, T>>,
- priv b: Focus<&'self T, TreeSetIterator<'self, T>>,
+ priv a: Peekable<&'self T, TreeSetIterator<'self, T>>,
+ priv b: Peekable<&'self T, TreeSetIterator<'self, T>>,
}
/// Lazy iterator producing elements in the set symmetric difference (in-order)
pub struct SymDifference<'self, T> {
- priv a: Focus<&'self T, TreeSetIterator<'self, T>>,
- priv b: Focus<&'self T, TreeSetIterator<'self, T>>,
+ priv a: Peekable<&'self T, TreeSetIterator<'self, T>>,
+ priv b: Peekable<&'self T, TreeSetIterator<'self, T>>,
}
/// Lazy iterator producing elements in the set intersection (in-order)
pub struct Intersection<'self, T> {
- priv a: Focus<&'self T, TreeSetIterator<'self, T>>,
- priv b: Focus<&'self T, TreeSetIterator<'self, T>>,
+ priv a: Peekable<&'self T, TreeSetIterator<'self, T>>,
+ priv b: Peekable<&'self T, TreeSetIterator<'self, T>>,
}
/// Lazy iterator producing elements in the set intersection (in-order)
pub struct Union<'self, T> {
- priv a: Focus<&'self T, TreeSetIterator<'self, T>>,
- priv b: Focus<&'self T, TreeSetIterator<'self, T>>,
+ priv a: Peekable<&'self T, TreeSetIterator<'self, T>>,
+ priv b: Peekable<&'self T, TreeSetIterator<'self, T>>,
+}
+
+/// Compare `x` and `y`, but return `short` if x is None and `long` if y is None
+fn cmp_opt<T: TotalOrd>(x: Option<&T>, y: Option<&T>,
+ short: Ordering, long: Ordering) -> Ordering {
+ match (x, y) {
+ (None , _ ) => short,
+ (_ , None ) => long,
+ (Some(x1), Some(y1)) => x1.cmp(y1),
+ }
}
impl<'self, T: TotalOrd> Iterator<&'self T> for Difference<'self, T> {
fn next(&mut self) -> Option<&'self T> {
loop {
- match (self.a.focus, self.b.focus) {
- (None , _ ) => return None,
- (ret , None ) => { self.a.step(); return ret },
- (Some(a1), Some(b1)) => {
- let cmp = a1.cmp(b1);
- if cmp == Less {
- self.a.step();
- return Some(a1);
- } else {
- if cmp == Equal { self.a.step() }
- self.b.step();
- }
- }
+ match cmp_opt(self.a.peek(), self.b.peek(), Less, Less) {
+ Less => return self.a.next(),
+ Equal => { self.a.next(); self.b.next(); }
+ Greater => { self.b.next(); }
}
}
}
impl<'self, T: TotalOrd> Iterator<&'self T> for SymDifference<'self, T> {
fn next(&mut self) -> Option<&'self T> {
loop {
- match (self.a.focus, self.b.focus) {
- (ret , None ) => { self.a.step(); return ret },
- (None , ret ) => { self.b.step(); return ret },
- (Some(a1), Some(b1)) => {
- let cmp = a1.cmp(b1);
- if cmp == Less {
- self.a.step();
- return Some(a1);
- } else {
- self.b.step();
- if cmp == Greater {
- return Some(b1);
- } else {
- self.a.step();
- }
- }
- }
+ match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) {
+ Less => return self.a.next(),
+ Equal => { self.a.next(); self.b.next(); }
+ Greater => return self.b.next(),
}
}
}
impl<'self, T: TotalOrd> Iterator<&'self T> for Intersection<'self, T> {
fn next(&mut self) -> Option<&'self T> {
loop {
- match (self.a.focus, self.b.focus) {
- (None , _ ) => return None,
- (_ , None ) => return None,
- (Some(a1), Some(b1)) => {
- let cmp = a1.cmp(b1);
- if cmp == Less {
- self.a.step();
- } else {
- self.b.step();
- if cmp == Equal {
- return Some(a1);
- }
- }
- },
+ let o_cmp = match (self.a.peek(), self.b.peek()) {
+ (None , _ ) => None,
+ (_ , None ) => None,
+ (Some(a1), Some(b1)) => Some(a1.cmp(b1)),
+ };
+ match o_cmp {
+ None => return None,
+ Some(Less) => { self.a.next(); }
+ Some(Equal) => { self.b.next(); return self.a.next() }
+ Some(Greater) => { self.b.next(); }
}
}
}
impl<'self, T: TotalOrd> Iterator<&'self T> for Union<'self, T> {
fn next(&mut self) -> Option<&'self T> {
loop {
- match (self.a.focus, self.b.focus) {
- (ret , None) => { self.a.step(); return ret },
- (None , ret ) => { self.b.step(); return ret },
- (Some(a1), Some(b1)) => {
- let cmp = a1.cmp(b1);
- if cmp == Greater {
- self.b.step();
- return Some(b1);
- } else {
- self.a.step();
- if cmp == Equal {
- self.b.step();
- }
- return Some(a1);
- }
- }
+ match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) {
+ Less => return self.a.next(),
+ Equal => { self.b.next(); return self.a.next() }
+ Greater => return self.b.next(),
}
}
}
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)
}
pub static tydesc_field_drop_glue: uint = 3u;
pub static tydesc_field_free_glue: uint = 4u;
pub static tydesc_field_visit_glue: uint = 5u;
-pub static n_tydesc_fields: uint = 6u;
+pub static tydesc_field_borrow_offset: uint = 6u;
+pub static n_tydesc_fields: uint = 7u;
// The two halves of a closure: code and environment.
pub static fn_field_code: uint = 0u;
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;
pub fn WriteOutputFile(sess: Session,
PM: lib::llvm::PassManagerRef, M: ModuleRef,
Triple: &str,
+ Cpu: &str,
Feature: &str,
Output: &str,
// FIXME: When #2334 is fixed, change
OptLevel: c_int,
EnableSegmentedStacks: bool) {
unsafe {
- do Triple.as_c_str |Triple| {
- do Feature.as_c_str |Feature| {
- do Output.as_c_str |Output| {
- let result = llvm::LLVMRustWriteOutputFile(
- PM,
- M,
- Triple,
- Feature,
- Output,
- FileType,
- OptLevel,
- EnableSegmentedStacks);
- if (!result) {
- llvm_err(sess, ~"Could not write output");
+ do Triple.to_c_str().with_ref |Triple| {
+ do Cpu.to_c_str().with_ref |Cpu| {
+ do Feature.to_c_str().with_ref |Feature| {
+ do Output.to_c_str().with_ref |Output| {
+ let result = llvm::LLVMRustWriteOutputFile(
+ PM,
+ M,
+ Triple,
+ Cpu,
+ Feature,
+ Output,
+ FileType,
+ OptLevel,
+ EnableSegmentedStacks);
+ if (!result) {
+ llvm_err(sess, ~"Could not write output");
+ }
}
}
}
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
pm.llpm,
llmod,
sess.targ_cfg.target_strs.target_triple,
+ opts.target_cpu,
opts.target_feature,
output.to_str(),
lib::llvm::AssemblyFile as c_uint,
pm.llpm,
llmod,
sess.targ_cfg.target_strs.target_triple,
+ opts.target_cpu,
opts.target_feature,
output.to_str(),
lib::llvm::ObjectFile as c_uint,
pm.llpm,
llmod,
sess.targ_cfg.target_strs.target_triple,
+ opts.target_cpu,
opts.target_feature,
output.to_str(),
FileType as c_uint,
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 {
#[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"),
// 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>()
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),
link::output_type_bitcode
} else { link::output_type_exe };
let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot").map_move(|m| @Path(m));
- let target_opt = getopts::opt_maybe_str(matches, "target");
- let target_feature_opt = getopts::opt_maybe_str(matches, "target-feature");
+ let target = getopts::opt_maybe_str(matches, "target").unwrap_or_default(host_triple());
+ let target_cpu = getopts::opt_maybe_str(matches, "target-cpu").unwrap_or_default(~"generic");
+ let target_feature = getopts::opt_maybe_str(matches, "target-feature").unwrap_or_default(~"");
let save_temps = getopts::opt_present(matches, "save-temps");
let opt_level = {
if (debugging_opts & session::no_opt) != 0 {
let debuginfo = debugging_opts & session::debug_info != 0 ||
extra_debuginfo;
let statik = debugging_opts & session::statik != 0;
- let target =
- match target_opt {
- None => host_triple(),
- Some(s) => s
- };
- let target_feature = match target_feature_opt {
- None => ~"",
- Some(s) => s
- };
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()
}
linker_args: linker_args,
maybe_sysroot: sysroot_opt,
target_triple: target,
+ target_cpu: target_cpu,
target_feature: target_feature,
cfg: cfg,
binary: binary,
pub fn build_session_(sopts: @session::options,
cm: @codemap::CodeMap,
demitter: diagnostic::Emitter,
- span_diagnostic_handler: @diagnostic::span_handler)
+ span_diagnostic_handler: @mut diagnostic::span_handler)
-> Session {
let target_cfg = build_target_config(sopts, demitter);
let p_s = parse::new_parse_sess_special_handler(span_diagnostic_handler,
optopt("", "target",
"Target triple cpu-manufacturer-kernel[-os]
to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
- for detail)", "TRIPLE"),
+ for details)", "TRIPLE"),
+ optopt("", "target-cpu",
+ "Select target processor (llc -mcpu=help
+ for details)", "CPU"),
optopt("", "target-feature",
"Target specific attributes (llc -mattr=help
- for detail)", "FEATURE"),
+ for details)", "FEATURE"),
optopt("", "android-cross-path",
"The path to the Android NDK", "PATH"),
optflagopt("W", "warn",
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,
_ => ()
linker_args: ~[~str],
maybe_sysroot: Option<@Path>,
target_triple: ~str,
+ target_cpu: ~str,
target_feature: ~str,
// User-specified cfg meta items. The compiler itself will add additional
// items to the crate config, and during parsing the entire crate config
// For a library crate, this is always none
entry_fn: @mut Option<(NodeId, codemap::span)>,
entry_type: @mut Option<EntryFnType>,
- span_diagnostic: @diagnostic::span_handler,
+ span_diagnostic: @mut diagnostic::span_handler,
filesearch: @filesearch::FileSearch,
building_library: @mut bool,
working_dir: Path,
pub fn next_node_id(@self) -> ast::NodeId {
return syntax::parse::next_node_id(self.parse_sess);
}
- pub fn diagnostic(@self) -> @diagnostic::span_handler {
+ pub fn diagnostic(@self) -> @mut diagnostic::span_handler {
self.span_diagnostic
}
pub fn debugging_opt(@self, opt: uint) -> bool {
linker_args: ~[],
maybe_sysroot: None,
target_triple: host_triple(),
+ target_cpu: ~"generic",
target_feature: ~"",
cfg: ~[],
binary: @"rustc",
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 LLVMRustWriteOutputFile(PM: PassManagerRef,
M: ModuleRef,
Triple: *c_char,
+ Cpu: *c_char,
Feature: *c_char,
Output: *c_char,
// FIXME: When #2334 is fixed,
Elements: ValueRef,
RunTimeLang: c_uint)
-> ValueRef;
+
+ #[fast_ffi]
+ pub fn LLVMSetUnnamedAddr(GlobalVar: ValueRef, UnnamedAddr: Bool);
}
}
}
}
+pub fn SetUnnamedAddr(Global: ValueRef, Unnamed: bool) {
+ unsafe {
+ llvm::LLVMSetUnnamedAddr(Global, Unnamed as Bool);
+ }
+}
+
pub fn ConstICmp(Pred: IntPredicate, V1: ValueRef, V2: ValueRef) -> ValueRef {
unsafe {
llvm::LLVMConstICmp(Pred as c_ushort, V1, V2)
}
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};
// Traverses an AST, reading all the information about use'd crates and extern
// libraries necessary for later resolving, typechecking, linking, etc.
-pub fn read_crates(diag: @span_handler,
+pub fn read_crates(diag: @mut span_handler,
crate: &ast::Crate,
cstore: @mut cstore::CStore,
filesearch: @FileSearch,
}
fn warn_if_multiple_versions(e: @mut Env,
- diag: @span_handler,
+ diag: @mut span_handler,
crate_cache: &[cache_entry]) {
use std::either::*;
*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)
}
struct Env {
- diag: @span_handler,
+ diag: @mut span_handler,
filesearch: @FileSearch,
cstore: @mut cstore::CStore,
os: loader::os,
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);
}
ii: ast::inlined_item);
pub struct EncodeParams<'self> {
- diag: @span_handler,
+ diag: @mut span_handler,
tcx: ty::ctxt,
reexports2: middle::resolve::ExportMap2,
item_symbols: &'self HashMap<ast::NodeId, ~str>,
}
pub struct EncodeContext<'self> {
- diag: @span_handler,
+ diag: @mut span_handler,
tcx: ty::ctxt,
stats: @mut Stats,
reexports2: middle::resolve::ExportMap2,
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);
}
}
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;
}
pub struct Context {
- diag: @span_handler,
+ diag: @mut 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,
+ diag: @mut span_handler,
attrs: ~[ast::Attribute]) {
let r = attr::find_linkage_metas(attrs);
for mi in r.iter() {
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]>; }
use syntax::print::pprust::*;
pub struct ctxt {
- diag: @span_handler,
+ diag: @mut span_handler,
// Def -> str Callback:
ds: @fn(def_id) -> ~str,
// The type context.
}
)
}
- typeck::method_trait(did, m, vstore) => {
- typeck::method_trait(did.tr(xcx), m, vstore)
+ typeck::method_trait(did, m) => {
+ typeck::method_trait(did.tr(xcx), m)
}
}
}
}
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);
}
mc::cat_discr(b, _) |
- mc::cat_deref(b, _, mc::uniq_ptr(*)) => {
+ mc::cat_deref(b, _, mc::uniq_ptr) => {
assert_eq!(cmt.mutbl, mc::McInherited);
cmt = b;
}
}
}
- mc::cat_deref(b, _, mc::uniq_ptr(*)) |
+ mc::cat_deref(b, _, mc::uniq_ptr) |
mc::cat_discr(b, _) => {
check_is_legal_to_move_from(bccx, cmt0, b)
}
mc::cat_arg(*) | // L-Local
mc::cat_self(*) | // L-Local
mc::cat_deref(_, _, mc::region_ptr(*)) | // L-Deref-Borrowed
- mc::cat_deref(_, _, mc::unsafe_ptr) => {
+ mc::cat_deref(_, _, mc::unsafe_ptr(*)) => {
let scope = self.scope(cmt);
self.check_scope(scope)
}
}
mc::cat_downcast(base) |
- mc::cat_deref(base, _, mc::uniq_ptr(*)) | // L-Deref-Send
+ mc::cat_deref(base, _, mc::uniq_ptr) | // L-Deref-Send
mc::cat_interior(base, _) => { // L-Field
self.check(base, discr_scope)
}
r
}
mc::cat_downcast(cmt) |
- mc::cat_deref(cmt, _, mc::uniq_ptr(*)) |
+ mc::cat_deref(cmt, _, mc::uniq_ptr) |
mc::cat_deref(cmt, _, mc::gc_ptr(*)) |
mc::cat_interior(cmt, _) |
mc::cat_stack_upvar(cmt) |
r)
}
ty::AutoBorrowFn(r) => {
- let cmt_deref = mcx.cat_deref_fn(expr, cmt, 0);
+ let cmt_deref = mcx.cat_deref_fn_or_obj(expr, cmt, 0);
self.guarantee_valid(expr.id,
expr.span,
cmt_deref,
m_imm,
r)
}
+ ty::AutoBorrowObj(r, m) => {
+ let cmt_deref = mcx.cat_deref_fn_or_obj(expr, cmt, 0);
+ self.guarantee_valid(expr.id,
+ expr.span,
+ cmt_deref,
+ m,
+ r)
+ }
ty::AutoUnsafe(_) => {}
}
}
self.extend(result, cmt.mutbl, LpInterior(i), restrictions)
}
- mc::cat_deref(cmt_base, _, mc::uniq_ptr(*)) => {
+ mc::cat_deref(cmt_base, _, mc::uniq_ptr) => {
// R-Deref-Send-Pointer
//
// When we borrow the interior of an owned pointer, we
}
}
- mc::cat_deref(_, _, mc::unsafe_ptr) => {
+ mc::cat_deref(_, _, mc::unsafe_ptr(*)) => {
// We are very trusting when working with unsafe pointers.
Safe
}
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)
// recursive call can use the original visitor's method, although the
// recursing visitor supplied to the method is the item stopping visitor.
OldVisitor(oldvisit::vt<@mut Context>, oldvisit::vt<@mut Context>),
- NewVisitor(@visit::Visitor<()>),
+ NewVisitor(@mut visit::Visitor<()>),
}
struct Context {
self.visitors.push(OldVisitor(v, item_stopping_visitor(v)));
}
- fn add_lint(&mut self, v: @visit::Visitor<()>) {
+ fn add_lint(&mut self, v: @mut visit::Visitor<()>) {
self.visitors.push(NewVisitor(v));
}
})
}
-fn lint_session(cx: @mut Context) -> @visit::Visitor<()> {
+fn lint_session(cx: @mut Context) -> @mut visit::Visitor<()> {
ast_util::id_visitor(|id| {
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)
}
}
// different kinds of pointers:
#[deriving(Eq)]
pub enum ptr_kind {
- uniq_ptr(ast::mutability),
+ uniq_ptr,
gc_ptr(ast::mutability),
region_ptr(ast::mutability, ty::Region),
- unsafe_ptr
+ unsafe_ptr(ast::mutability)
}
// We use the term "interior" to mean "something reachable from the
// pointer adjustment).
pub fn opt_deref_kind(t: ty::t) -> Option<deref_kind> {
match ty::get(t).sty {
- ty::ty_uniq(mt) => {
- Some(deref_ptr(uniq_ptr(mt.mutbl)))
- }
-
+ ty::ty_uniq(_) |
+ ty::ty_trait(_, _, ty::UniqTraitStore, _, _) |
ty::ty_evec(_, ty::vstore_uniq) |
ty::ty_estr(ty::vstore_uniq) |
ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
- Some(deref_ptr(uniq_ptr(m_imm)))
+ Some(deref_ptr(uniq_ptr))
}
ty::ty_rptr(r, mt) |
Some(deref_ptr(region_ptr(mt.mutbl, r)))
}
+ ty::ty_trait(_, _, ty::RegionTraitStore(r), m, _) => {
+ Some(deref_ptr(region_ptr(m, r)))
+ }
+
ty::ty_estr(ty::vstore_slice(r)) |
ty::ty_closure(ty::ClosureTy {sigil: ast::BorrowedSigil,
region: r, _}) => {
Some(deref_ptr(region_ptr(ast::m_imm, r)))
}
- ty::ty_box(mt) |
- ty::ty_evec(mt, ty::vstore_box) => {
+ ty::ty_box(ref mt) |
+ ty::ty_evec(ref mt, ty::vstore_box) => {
Some(deref_ptr(gc_ptr(mt.mutbl)))
}
+ ty::ty_trait(_, _, ty::BoxTraitStore, m, _) => {
+ Some(deref_ptr(gc_ptr(m)))
+ }
+
ty::ty_estr(ty::vstore_box) |
ty::ty_closure(ty::ClosureTy {sigil: ast::ManagedSigil, _}) => {
Some(deref_ptr(gc_ptr(ast::m_imm)))
}
- ty::ty_ptr(*) => {
- Some(deref_ptr(unsafe_ptr))
+ ty::ty_ptr(ref mt) => {
+ Some(deref_ptr(unsafe_ptr(mt.mutbl)))
}
ty::ty_enum(*) |
}
}
- pub fn cat_deref_fn<N:ast_node>(&self,
- node: N,
- base_cmt: cmt,
- deref_cnt: uint)
- -> cmt {
+ pub fn cat_deref_fn_or_obj<N:ast_node>(&self,
+ node: N,
+ base_cmt: cmt,
+ deref_cnt: uint)
+ -> cmt {
// Bit of a hack: the "dereference" of a function pointer like
// `@fn()` is a mere logical concept. We interpret it as
// dereferencing the environment pointer; of course, we don't
// know what type lies at the other end, so we just call it
// `()` (the empty tuple).
- let mt = ty::mt {ty: ty::mk_tup(self.tcx, ~[]),
- mutbl: m_imm};
- return self.cat_deref_common(node, base_cmt, deref_cnt, mt);
+ let opaque_ty = ty::mk_tup(self.tcx, ~[]);
+ return self.cat_deref_common(node, base_cmt, deref_cnt, opaque_ty);
}
pub fn cat_deref<N:ast_node>(&self,
}
};
- return self.cat_deref_common(node, base_cmt, deref_cnt, mt);
+ return self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty);
}
pub fn cat_deref_common<N:ast_node>(&self,
node: N,
base_cmt: cmt,
deref_cnt: uint,
- mt: ty::mt)
+ deref_ty: ty::t)
-> cmt {
match deref_kind(self.tcx, base_cmt.ty) {
deref_ptr(ptr) => {
// for unique ptrs, we inherit mutability from the
// owning reference.
let m = match ptr {
- uniq_ptr(*) => {
- self.inherited_mutability(base_cmt.mutbl, mt.mutbl)
+ uniq_ptr => {
+ base_cmt.mutbl.inherit()
}
- gc_ptr(*) | region_ptr(_, _) | unsafe_ptr => {
- MutabilityCategory::from_mutbl(mt.mutbl)
+ gc_ptr(m) | region_ptr(m, _) | unsafe_ptr(m) => {
+ MutabilityCategory::from_mutbl(m)
}
};
span:node.span(),
cat:cat_deref(base_cmt, deref_cnt, ptr),
mutbl:m,
- ty:mt.ty
+ ty:deref_ty
}
}
deref_interior(interior) => {
- let m = self.inherited_mutability(base_cmt.mutbl, mt.mutbl);
+ let m = base_cmt.mutbl.inherit();
@cmt_ {
id:node.id(),
span:node.span(),
cat:cat_interior(base_cmt, interior),
mutbl:m,
- ty:mt.ty
+ ty:deref_ty
}
}
}
//! - `derefs`: the deref number to be used for
//! the implicit index deref, if any (see above)
- let mt = match ty::index(base_cmt.ty) {
- Some(mt) => mt,
+ let element_ty = match ty::index(base_cmt.ty) {
+ Some(ref mt) => mt.ty,
None => {
self.tcx.sess.span_bug(
elt.span(),
// for unique ptrs, we inherit mutability from the
// owning reference.
let m = match ptr {
- uniq_ptr(*) => {
- self.inherited_mutability(base_cmt.mutbl, mt.mutbl)
+ uniq_ptr => {
+ base_cmt.mutbl.inherit()
}
- gc_ptr(_) | region_ptr(_, _) | unsafe_ptr => {
- MutabilityCategory::from_mutbl(mt.mutbl)
+ gc_ptr(m) | region_ptr(m, _) | unsafe_ptr(m) => {
+ MutabilityCategory::from_mutbl(m)
}
};
span:elt.span(),
cat:cat_deref(base_cmt, derefs, ptr),
mutbl:m,
- ty:mt.ty
+ ty:element_ty
};
- interior(elt, deref_cmt, base_cmt.ty, m, mt)
+ interior(elt, deref_cmt, base_cmt.ty, m, element_ty)
}
deref_interior(_) => {
// fixed-length vectors have no deref
- let m = self.inherited_mutability(base_cmt.mutbl, mt.mutbl);
- interior(elt, base_cmt, base_cmt.ty, m, mt)
+ let m = base_cmt.mutbl.inherit();
+ interior(elt, base_cmt, base_cmt.ty, m, element_ty)
}
};
of_cmt: cmt,
vec_ty: ty::t,
mutbl: MutabilityCategory,
- mt: ty::mt) -> cmt
+ element_ty: ty::t) -> cmt
{
@cmt_ {
id:elt.id(),
span:elt.span(),
cat:cat_interior(of_cmt, InteriorElement(element_kind(vec_ty))),
mutbl:mutbl,
- ty:mt.ty
+ ty:element_ty
}
}
}
cat_stack_upvar(b) |
cat_discr(b, _) |
cat_interior(b, _) |
- cat_deref(b, _, uniq_ptr(*)) => {
+ cat_deref(b, _, uniq_ptr) => {
b.guarantor()
}
}
cat_downcast(b) |
cat_stack_upvar(b) |
- cat_deref(b, _, uniq_ptr(*)) |
+ cat_deref(b, _, uniq_ptr) |
cat_interior(b, _) |
cat_discr(b, _) => {
b.freely_aliasable()
pub fn ptr_sigil(ptr: ptr_kind) -> ~str {
match ptr {
- uniq_ptr(_) => ~"~",
+ uniq_ptr => ~"~",
gc_ptr(_) => ~"@",
region_ptr(_, _) => ~"&",
- unsafe_ptr => ~"*"
+ unsafe_ptr(_) => ~"*"
}
}
method_num: method_num,
_
}) |
- method_trait(trait_id, method_num, _) => {
+ method_trait(trait_id, method_num) => {
if trait_id.crate == LOCAL_CRATE {
match tcx.items.find(&trait_id.node) {
Some(&node_item(item, _)) => {
// 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)) => {
}
}
- 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 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) {
* - `store_non_ref_bindings()`
* - `insert_lllocals()`
*
+ *
+ * ## Notes on vector pattern matching.
+ *
+ * Vector pattern matching is surprisingly tricky. The problem is that
+ * the structure of the vector isn't fully known, and slice matches
+ * can be done on subparts of it.
+ *
+ * The way that vector pattern matches are dealt with, then, is as
+ * follows. First, we make the actual condition associated with a
+ * vector pattern simply a vector length comparison. So the pattern
+ * [1, .. x] gets the condition "vec len >= 1", and the pattern
+ * [.. x] gets the condition "vec len >= 0". The problem here is that
+ * having the condition "vec len >= 1" hold clearly does not mean that
+ * only a pattern that has exactly that condition will match. This
+ * means that it may well be the case that a condition holds, but none
+ * of the patterns matching that condition match; to deal with this,
+ * when doing vector length matches, we have match failures proceed to
+ * the next condition to check.
+ *
+ * There are a couple more subtleties to deal with. While the "actual"
+ * condition associated with vector length tests is simply a test on
+ * the vector length, the actual vec_len Opt entry contains more
+ * information used to restrict which matches are associated with it.
+ * So that all matches in a submatch are matching against the same
+ * values from inside the vector, they are split up by how many
+ * elements they match at the front and at the back of the vector. In
+ * order to make sure that arms are properly checked in order, even
+ * with the overmatching conditions, each vec_len Opt entry is
+ * associated with a range of matches.
+ * Consider the following:
+ *
+ * match &[1, 2, 3] {
+ * [1, 1, .. _] => 0,
+ * [1, 2, 2, .. _] => 1,
+ * [1, 2, 3, .. _] => 2,
+ * [1, 2, .. _] => 3,
+ * _ => 4
+ * }
+ * The proper arm to match is arm 2, but arms 0 and 3 both have the
+ * condition "len >= 2". If arm 3 was lumped in with arm 0, then the
+ * wrong branch would be taken. Instead, vec_len Opts are associated
+ * with a contiguous range of matches that have the same "shape".
+ * This is sort of ugly and requires a bunch of special handling of
+ * vec_len options.
+ *
*/
ConstLit(ast::def_id), // the def ID of the constant
}
+#[deriving(Eq)]
+pub enum VecLenOpt {
+ vec_len_eq,
+ vec_len_ge(/* length of prefix */uint)
+}
+
// An option identifying a branch (either a literal, a enum variant or a
// range)
enum Opt {
lit(Lit),
var(/* disr val */ uint, @adt::Repr),
range(@ast::expr, @ast::expr),
- vec_len_eq(uint),
- vec_len_ge(uint, /* slice */uint)
+ vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint))
}
fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool {
}
}
(&var(a, _), &var(b, _)) => a == b,
- (&vec_len_eq(a), &vec_len_eq(b)) => a == b,
- (&vec_len_ge(a, _), &vec_len_ge(b, _)) => a == b,
- _ => false
+ (&vec_len(a1, a2, _), &vec_len(b1, b2, _)) =>
+ a1 == b1 && a2 == b2,
+ _ => false
}
}
return range_result(rslt(bcx, consts::const_expr(ccx, l1)),
rslt(bcx, consts::const_expr(ccx, l2)));
}
- vec_len_eq(n) => {
+ vec_len(n, vec_len_eq, _) => {
return single_result(rslt(bcx, C_int(ccx, n as int)));
}
- vec_len_ge(n, _) => {
+ vec_len(n, vec_len_ge(_), _) => {
return lower_bound(rslt(bcx, C_int(ccx, n as int)));
}
}
}
fn enter_default<'r>(bcx: @mut Block,
- dm: DefMap,
- m: &[Match<'r>],
- col: uint,
- val: ValueRef)
+ dm: DefMap,
+ m: &[Match<'r>],
+ col: uint,
+ val: ValueRef,
+ chk: Option<mk_fail>)
-> ~[Match<'r>] {
debug!("enter_default(bcx=%s, m=%s, col=%u, val=%s)",
bcx.to_str(),
bcx.val_to_str(val));
let _indenter = indenter();
- do enter_match(bcx, dm, m, col, val) |p| {
+ // Collect all of the matches that can match against anything.
+ let matches = do enter_match(bcx, dm, m, col, val) |p| {
match p.node {
ast::pat_wild | ast::pat_tup(_) => Some(~[]),
ast::pat_ident(_, _, None) if pat_is_binding(dm, p) => Some(~[]),
_ => None
}
- }
+ };
+
+ // Ok, now, this is pretty subtle. A "default" match is a match
+ // that needs to be considered if none of the actual checks on the
+ // value being considered succeed. The subtlety lies in that sometimes
+ // identifier/wildcard matches are *not* default matches. Consider:
+ // "match x { _ if something => foo, true => bar, false => baz }".
+ // There is a wildcard match, but it is *not* a default case. The boolean
+ // case on the value being considered is exhaustive. If the case is
+ // exhaustive, then there are no defaults.
+ //
+ // We detect whether the case is exhaustive in the following
+ // somewhat kludgy way: if the last wildcard/binding match has a
+ // guard, then by non-redundancy, we know that there aren't any
+ // non guarded matches, and thus by exhaustiveness, we know that
+ // we don't need any default cases. If the check *isn't* nonexhaustive
+ // (because chk is Some), then we need the defaults anyways.
+ let is_exhaustive = match matches.last_opt() {
+ Some(m) if m.data.arm.guard.is_some() && chk.is_none() => true,
+ _ => false
+ };
+
+ if is_exhaustive { ~[] } else { matches }
}
// <pcwalton> nmatsakis: what does enter_opt do?
variant_size: uint,
val: ValueRef)
-> ~[Match<'r>] {
- debug!("enter_opt(bcx=%s, m=%s, col=%u, val=%s)",
+ debug!("enter_opt(bcx=%s, m=%s, opt=%?, col=%u, val=%s)",
bcx.to_str(),
m.repr(bcx.tcx()),
+ *opt,
col,
bcx.val_to_str(val));
let _indenter = indenter();
let tcx = bcx.tcx();
let dummy = @ast::pat {id: 0, node: ast::pat_wild, span: dummy_sp()};
+ let mut i = 0;
do enter_match(bcx, tcx.def_map, m, col, val) |p| {
- match p.node {
+ let answer = match p.node {
ast::pat_enum(*) |
ast::pat_ident(_, _, None) if pat_is_const(tcx.def_map, p) => {
let const_def = tcx.def_map.get_copy(&p.id);
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)
}
}
}
ast::pat_vec(ref before, slice, ref after) => {
+ let (lo, hi) = match *opt {
+ vec_len(_, _, (lo, hi)) => (lo, hi),
+ _ => tcx.sess.span_bug(p.span,
+ "vec pattern but not vec opt")
+ };
+
match slice {
- Some(slice) => {
+ Some(slice) if i >= lo && i <= hi => {
let n = before.len() + after.len();
- let i = before.len();
- if opt_eq(tcx, &vec_len_ge(n, i), opt) {
+ let this_opt = vec_len(n, vec_len_ge(before.len()),
+ (lo, hi));
+ if opt_eq(tcx, &this_opt, opt) {
Some(vec::append_one((*before).clone(), slice) +
*after)
} else {
None
}
}
- None => {
+ None if i >= lo && i <= hi => {
let n = before.len();
- if opt_eq(tcx, &vec_len_eq(n), opt) {
+ if opt_eq(tcx, &vec_len(n, vec_len_eq, (lo,hi)), opt) {
Some((*before).clone())
} else {
None
}
}
+ _ => None
}
}
_ => {
assert_is_binding_or_wild(bcx, p);
- Some(vec::from_elem(variant_size, dummy))
+ // In most cases, a binding/wildcard match be
+ // considered to match against any Opt. However, when
+ // doing vector pattern matching, submatches are
+ // considered even if the eventual match might be from
+ // a different submatch. Thus, when a submatch fails
+ // when doing a vector match, we proceed to the next
+ // submatch. Thus, including a default match would
+ // cause the default match to fire spuriously.
+ match *opt {
+ vec_len(*) => None,
+ _ => Some(vec::from_elem(variant_size, dummy))
+ }
}
- }
+ };
+ i += 1;
+ answer
}
}
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)
}
if set.iter().any(|l| opt_eq(tcx, l, &val)) {return;}
set.push(val);
}
+ // Vector comparisions are special in that since the actual
+ // conditions over-match, we need to be careful about them. This
+ // means that in order to properly handle things in order, we need
+ // to not always merge conditions.
+ fn add_veclen_to_set(set: &mut ~[Opt], i: uint,
+ len: uint, vlo: VecLenOpt) {
+ match set.last_opt() {
+ // If the last condition in the list matches the one we want
+ // to add, then extend its range. Otherwise, make a new
+ // vec_len with a range just covering the new entry.
+ Some(&vec_len(len2, vlo2, (start, end)))
+ if len == len2 && vlo == vlo2 =>
+ set[set.len() - 1] = vec_len(len, vlo, (start, end+1)),
+ _ => set.push(vec_len(len, vlo, (i, i)))
+ }
+ }
let mut found = ~[];
- for br in m.iter() {
+ for (i, br) in m.iter().enumerate() {
let cur = br.pats[col];
match cur.node {
ast::pat_lit(l) => {
add_to_set(ccx.tcx, &mut found, range(l1, l2));
}
ast::pat_vec(ref before, slice, ref after) => {
- let opt = match slice {
- None => vec_len_eq(before.len()),
- Some(_) => vec_len_ge(before.len() + after.len(),
- before.len())
+ let (len, vec_opt) = match slice {
+ None => (before.len(), vec_len_eq),
+ Some(_) => (before.len() + after.len(),
+ vec_len_ge(before.len()))
};
- add_to_set(ccx.tcx, &mut found, opt);
+ add_veclen_to_set(&mut found, i, len, vec_opt);
}
_ => {}
}
}
let mut scores = vec::from_elem(m[0].pats.len(), 0u);
for br in m.iter() {
- let mut i = 0u;
- for p in br.pats.iter() { scores[i] += score(*p); i += 1u; }
+ for (i, p) in br.pats.iter().enumerate() {
+ scores[i] += score(*p);
+ }
}
let mut max_score = 0u;
let mut best_col = 0u;
- let mut i = 0u;
- for score in scores.iter() {
+ for (i, score) in scores.iter().enumerate() {
let score = *score;
// Irrefutable columns always go first, they'd only be duplicated in
// If no irrefutable ones are found, we pick the one with the biggest
// branching factor.
if score > max_score { max_score = score; best_col = i; }
- i += 1u;
}
return best_col;
}
test_val = Load(bcx, val);
kind = compare;
},
- vec_len_eq(*) | vec_len_ge(*) => {
+ vec_len(*) => {
let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id));
let unboxed = load_if_immediate(bcx, val, vt.vec_ty);
let (_, len) = tvec::get_base_and_len(
C_int(ccx, 0) // Placeholder for when not using a switch
};
- let defaults = enter_default(else_cx, dm, m, col, val);
+ let defaults = enter_default(else_cx, dm, m, col, val, chk);
let exhaustive = chk.is_none() && defaults.len() == 0u;
let len = opts.len();
- let mut i = 0u;
// Compile subtrees for each option
- for opt in opts.iter() {
- i += 1u;
+ for (i, opt) in opts.iter().enumerate() {
+ // In some cases in vector pattern matching, we need to override
+ // the failure case so that instead of failing, it proceeds to
+ // try more matching. branch_chk, then, is the proper failure case
+ // for the current conditional branch.
+ let mut branch_chk = chk;
let mut opt_cx = else_cx;
- if !exhaustive || i < len {
+ if !exhaustive || i+1 < len {
opt_cx = sub_block(bcx, "match_case");
match kind {
single => Br(bcx, opt_cx.llbb),
}
};
bcx = sub_block(after_cx, "compare_vec_len_next");
+
+ // If none of these subcases match, move on to the
+ // next condition.
+ branch_chk = Some::<mk_fail>(|| bcx.llbb);
CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
}
_ => ()
unpacked = argvals;
opt_cx = new_bcx;
}
- vec_len_eq(n) | vec_len_ge(n, _) => {
- let n = match *opt {
- vec_len_ge(*) => n + 1u,
- _ => n
- };
- let slice = match *opt {
- vec_len_ge(_, i) => Some(i),
- _ => None
+ vec_len(n, vt, _) => {
+ let (n, slice) = match vt {
+ vec_len_ge(i) => (n + 1u, Some(i)),
+ vec_len_eq => (n, None)
};
- let args = extract_vec_elems(opt_cx, pat_span, pat_id, n, slice,
- val, test_val);
+ let args = extract_vec_elems(opt_cx, pat_span, pat_id, n,
+ slice, val, test_val);
size = args.vals.len();
unpacked = args.vals.clone();
opt_cx = args.bcx;
}
let opt_ms = enter_opt(opt_cx, m, opt, col, size, val);
let opt_vals = vec::append(unpacked, vals_left);
- compile_submatch(opt_cx, opt_ms, opt_vals, chk);
+ compile_submatch(opt_cx, opt_ms, opt_vals, branch_chk);
}
// Compile the fall-through case, if any
}
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, }
}
ast::item_static(_, m, expr) => {
consts::trans_const(ccx, m, item.id);
- // Do static_assert checking. It can't really be done much earlier because we need to get
- // the value of the bool out of LLVM
- for attr in item.attrs.iter() {
- if "static_assert" == attr.name() {
- if m == ast::m_mutbl {
- ccx.sess.span_fatal(expr.span,
- "cannot have static_assert on a mutable static");
- }
- let v = ccx.const_values.get_copy(&item.id);
- unsafe {
- if !(llvm::LLVMConstIntGetZExtValue(v) as bool) {
- ccx.sess.span_fatal(expr.span, "static assertion failed");
- }
+ // Do static_assert checking. It can't really be done much earlier
+ // because we need to get the value of the bool out of LLVM
+ if attr::contains_name(item.attrs, "static_assert") {
+ if m == ast::m_mutbl {
+ ccx.sess.span_fatal(expr.span,
+ "cannot have static_assert on a mutable \
+ static");
+ }
+ let v = ccx.const_values.get_copy(&item.id);
+ unsafe {
+ if !(llvm::LLVMConstIntGetZExtValue(v) as bool) {
+ ccx.sess.span_fatal(expr.span, "static assertion failed");
}
}
}
};
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);
}
}
}
pub fn item_path(ccx: &CrateContext, id: &ast::NodeId) -> path {
- match ccx.tcx.items.get_copy(id) {
- ast_map::node_item(i, p) =>
- vec::append((*p).clone(), [path_name(i.ident)]),
- // separate map for paths?
- _ => fail!("item_path")
- }
+ ty::item_path(ccx.tcx, ast_util::local_def(*id))
}
fn exported_name(ccx: @mut CrateContext, path: path, ty: ty::t, attrs: &[ast::Attribute]) -> ~str {
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)
};
+ // Apply the `unnamed_addr` attribute if
+ // requested
+ if attr::contains_name(i.attrs,
+ "address_insignificant"){
+ lib::llvm::SetUnnamedAddr(g, true);
+ lib::llvm::SetLinkage(g,
+ lib::llvm::InternalLinkage);
+ }
+
ccx.item_symbols.insert(i.id, sym);
g
}
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)
}
ifn!("llvm.bswap.i32",[Type::i32()], Type::i32());
ifn!("llvm.bswap.i64",[Type::i64()], Type::i64());
+ ifn!("llvm.sadd.with.overflow.i8",
+ [Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
+ ifn!("llvm.sadd.with.overflow.i16",
+ [Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
+ ifn!("llvm.sadd.with.overflow.i32",
+ [Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
+ ifn!("llvm.sadd.with.overflow.i64",
+ [Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
+
+ ifn!("llvm.uadd.with.overflow.i8",
+ [Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
+ ifn!("llvm.uadd.with.overflow.i16",
+ [Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
+ ifn!("llvm.uadd.with.overflow.i32",
+ [Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
+ ifn!("llvm.uadd.with.overflow.i64",
+ [Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
+
+ ifn!("llvm.ssub.with.overflow.i8",
+ [Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
+ ifn!("llvm.ssub.with.overflow.i16",
+ [Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
+ ifn!("llvm.ssub.with.overflow.i32",
+ [Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
+ ifn!("llvm.ssub.with.overflow.i64",
+ [Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
+
+ ifn!("llvm.usub.with.overflow.i8",
+ [Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
+ ifn!("llvm.usub.with.overflow.i16",
+ [Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
+ ifn!("llvm.usub.with.overflow.i32",
+ [Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
+ ifn!("llvm.usub.with.overflow.i64",
+ [Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
+
+ ifn!("llvm.smul.with.overflow.i8",
+ [Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
+ ifn!("llvm.smul.with.overflow.i16",
+ [Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
+ ifn!("llvm.smul.with.overflow.i32",
+ [Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
+ ifn!("llvm.smul.with.overflow.i64",
+ [Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
+
+ ifn!("llvm.umul.with.overflow.i8",
+ [Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
+ ifn!("llvm.umul.with.overflow.i16",
+ [Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
+ ifn!("llvm.umul.with.overflow.i32",
+ [Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
+ ifn!("llvm.umul.with.overflow.i64",
+ [Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
+
return intrinsics;
}
}
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
+ }
+ }
+}
}
}
-pub fn InsertValue(cx: @mut Block, AggVal: ValueRef, EltVal: ValueRef, Index: uint) {
- if cx.unreachable { return; }
- B(cx).insert_value(AggVal, EltVal, Index)
+pub fn InsertValue(cx: @mut Block, AggVal: ValueRef, EltVal: ValueRef, Index: uint) -> ValueRef {
+ unsafe {
+ if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); }
+ B(cx).insert_value(AggVal, EltVal, Index)
+ }
}
pub fn IsNull(cx: @mut Block, Val: ValueRef) -> ValueRef {
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)
}
pub fn insert_value(&self, agg_val: ValueRef, elt: ValueRef,
- idx: uint) {
+ idx: uint) -> ValueRef {
self.count_insn("insertvalue");
unsafe {
llvm::LLVMBuildInsertValue(self.llbuilder, agg_val, elt, idx as c_uint,
- noname());
+ noname())
}
}
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);
llfn: ValueRef,
llself: ValueRef,
temp_cleanup: Option<ValueRef>,
- self_ty: ty::t,
self_mode: ty::SelfMode,
}
use middle::trans::type_::Type;
+use std::c_str::ToCStr;
use std::cast::transmute;
use std::cast;
use std::hashmap::{HashMap};
tydesc: ValueRef,
size: ValueRef,
align: ValueRef,
+ borrow_offset: ValueRef,
take_glue: Option<ValueRef>,
drop_glue: Option<ValueRef>,
free_glue: Option<ValueRef>,
}
pub fn out_arg_pos(&self) -> uint {
- assert!(self.has_immediate_return_value);
+ assert!(!self.has_immediate_return_value);
0u
}
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) {
t]);
}
-
// LLVM constant constructors.
pub fn C_null(t: Type) -> ValueRef {
unsafe {
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 driver::session;
use lib::llvm::{ContextRef, ModuleRef, ValueRef};
use lib::llvm::{llvm, TargetData, TypeNames};
-use lib::llvm::{mk_target_data};
+use lib::llvm::{mk_target_data, False};
use metadata::common::LinkMeta;
use middle::astencode;
use middle::resolve;
use middle::trans::builder::Builder;
use middle::trans::debuginfo;
use middle::trans::type_use;
+use middle::trans::common::{C_i32, C_null};
use middle::ty;
use middle::trans::type_::Type;
+use std::c_str::ToCStr;
use std::hash;
use std::hashmap::{HashMap, HashSet};
use std::local_data;
+use std::vec;
+use std::libc::c_uint;
use syntax::ast;
use middle::trans::common::{mono_id,ExternMap,tydesc_info,BuilderRef_res,Stats};
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);
pub fn builder(@mut self) -> Builder {
Builder::new(self)
}
+
+ pub fn const_inbounds_gepi(&self,
+ pointer: ValueRef,
+ indices: &[uint]) -> ValueRef {
+ debug!("const_inbounds_gepi: pointer=%s indices=%?",
+ self.tn.val_to_str(pointer), indices);
+ let v: ~[ValueRef] =
+ indices.iter().map(|i| C_i32(*i as i32)).collect();
+ unsafe {
+ llvm::LLVMConstInBoundsGEP(pointer,
+ vec::raw::to_ptr(v),
+ indices.len() as c_uint)
+ }
+ }
+
+ pub fn offsetof_gep(&self,
+ llptr_ty: Type,
+ indices: &[uint]) -> ValueRef {
+ /*!
+ * Returns the offset of applying the given GEP indices
+ * to an instance of `llptr_ty`. Similar to `offsetof` in C,
+ * except that `llptr_ty` must be a pointer type.
+ */
+
+ unsafe {
+ let null = C_null(llptr_ty);
+ llvm::LLVMConstPtrToInt(self.const_inbounds_gepi(null, indices),
+ self.int_type.to_ref())
+ }
+ }
}
#[unsafe_destructor]
// 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),
use middle::trans::tvec;
use middle::trans::type_of;
use middle::ty::struct_fields;
-use middle::ty::{AutoDerefRef, AutoAddEnv};
-use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn,
- AutoUnsafe};
+use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoUnsafe};
+use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
use middle::ty;
use util::common::indenter;
use util::ppaux::Repr;
datum.ty, Some(adjustment));
unpack_datum!(bcx, auto_borrow_fn(bcx, adjusted_ty, datum))
}
+ Some(AutoBorrowObj(*)) => {
+ unpack_datum!(bcx, auto_borrow_obj(
+ bcx, adj.autoderefs, expr, datum))
+ }
};
}
}
let DatumBlock { bcx, datum } = auto_slice(bcx, autoderefs, expr, datum);
auto_ref(bcx, datum)
}
+
+ fn auto_borrow_obj(mut bcx: @mut Block,
+ autoderefs: uint,
+ expr: @ast::expr,
+ source_datum: Datum) -> DatumBlock {
+ let tcx = bcx.tcx();
+ let target_obj_ty = expr_ty_adjusted(bcx, expr);
+ debug!("auto_borrow_obj(target=%s)",
+ target_obj_ty.repr(tcx));
+ let scratch = scratch_datum(bcx, target_obj_ty,
+ "__auto_borrow_obj", false);
+
+ // Convert a @Object, ~Object, or &Object pair into an &Object pair.
+
+ // Get a pointer to the source object, which is represented as
+ // a (vtable, data) pair.
+ let source_llval = source_datum.to_ref_llval(bcx);
+
+ // Set the vtable field of the new pair
+ let vtable_ptr = GEPi(bcx, source_llval, [0u, abi::trt_field_vtable]);
+ let vtable = Load(bcx, vtable_ptr);
+ Store(bcx, vtable, GEPi(bcx, scratch.val, [0u, abi::trt_field_vtable]));
+
+ // Load the data for the source, which is either an @T,
+ // ~T, or &T, depending on source_obj_ty.
+ let source_data_ptr = GEPi(bcx, source_llval, [0u, abi::trt_field_box]);
+ let source_data = Load(bcx, source_data_ptr); // always a ptr
+ let (source_store, source_mutbl) = match ty::get(source_datum.ty).sty {
+ ty::ty_trait(_, _, s, m, _) => (s, m),
+ _ => {
+ bcx.sess().span_bug(
+ expr.span,
+ fmt!("auto_borrow_trait_obj expected a trait, found %s",
+ source_datum.ty.repr(bcx.tcx())));
+ }
+ };
+ let target_data = match source_store {
+ ty::BoxTraitStore(*) => {
+ // For deref of @T or @mut T, create a dummy datum and
+ // use the datum's deref method. This is more work
+ // than just calling GEPi ourselves, but it ensures
+ // that any write guards will be appropriate
+ // processed. Note that we don't know the type T, so
+ // just substitute `i8`-- it doesn't really matter for
+ // our purposes right now.
+ let source_ty =
+ ty::mk_box(tcx,
+ ty::mt {
+ ty: ty::mk_i8(),
+ mutbl: source_mutbl});
+ let source_datum =
+ Datum {val: source_data,
+ ty: source_ty,
+ mode: ByValue};
+ let derefd_datum =
+ unpack_datum!(bcx,
+ source_datum.deref(bcx,
+ expr,
+ autoderefs));
+ derefd_datum.to_rptr(bcx).to_value_llval(bcx)
+ }
+ ty::UniqTraitStore(*) => {
+ // For a ~T box, there may or may not be a header,
+ // depending on whether the type T references managed
+ // boxes. However, since we do not *know* the type T
+ // for objects, this presents a hurdle. Our solution is
+ // to load the "borrow offset" from the type descriptor;
+ // this value will either be 0 or sizeof(BoxHeader), depending
+ // on the type T.
+ let llopaque =
+ PointerCast(bcx, source_data, Type::opaque().ptr_to());
+ let lltydesc_ptr_ptr =
+ PointerCast(bcx, vtable,
+ bcx.ccx().tydesc_type.ptr_to().ptr_to());
+ let lltydesc_ptr =
+ Load(bcx, lltydesc_ptr_ptr);
+ let borrow_offset_ptr =
+ GEPi(bcx, lltydesc_ptr,
+ [0, abi::tydesc_field_borrow_offset]);
+ let borrow_offset =
+ Load(bcx, borrow_offset_ptr);
+ InBoundsGEP(bcx, llopaque, [borrow_offset])
+ }
+ ty::RegionTraitStore(*) => {
+ source_data
+ }
+ };
+ Store(bcx, target_data,
+ GEPi(bcx, scratch.val, [0u, abi::trt_field_box]));
+
+ DatumBlock { bcx: bcx, datum: scratch }
+ }
}
pub fn trans_into(bcx: @mut Block, expr: @ast::expr, dest: Dest) -> @mut Block {
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)
Ret(bcx, Call(bcx, llfn, args.slice(0, num_args)));
}
+ fn with_overflow_instrinsic(bcx: @mut Block, name: &'static str) {
+ let first_real_arg = bcx.fcx.arg_pos(0u);
+ let a = get_param(bcx.fcx.llfn, first_real_arg);
+ let b = get_param(bcx.fcx.llfn, first_real_arg + 1);
+ let llfn = bcx.ccx().intrinsics.get_copy(&name);
+
+ // convert `i1` to a `bool`, and write to the out parameter
+ let val = Call(bcx, llfn, [a, b]);
+ let result = ExtractValue(bcx, val, 0);
+ let overflow = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool());
+ let retptr = get_param(bcx.fcx.llfn, bcx.fcx.out_arg_pos());
+ let ret = Load(bcx, retptr);
+ let ret = InsertValue(bcx, ret, result, 0);
+ let ret = InsertValue(bcx, ret, overflow, 1);
+ Store(bcx, ret, retptr);
+ RetVoid(bcx)
+ }
+
fn memcpy_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
let ccx = bcx.ccx();
let lltp_ty = type_of::type_of(ccx, tp_ty);
"visit_tydesc" => {
let td = get_param(decl, first_real_arg);
let visitor = get_param(decl, first_real_arg + 1u);
- //let llvisitorptr = alloca(bcx, val_ty(visitor));
- //Store(bcx, visitor, llvisitorptr);
let td = PointerCast(bcx, td, ccx.tydesc_type.ptr_to());
glue::call_tydesc_glue_full(bcx, visitor, td,
abi::tydesc_field_visit_glue, None);
"bswap16" => simple_llvm_intrinsic(bcx, "llvm.bswap.i16", 1),
"bswap32" => simple_llvm_intrinsic(bcx, "llvm.bswap.i32", 1),
"bswap64" => simple_llvm_intrinsic(bcx, "llvm.bswap.i64", 1),
+
+ "i8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i8"),
+ "i16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i16"),
+ "i32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i32"),
+ "i64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i64"),
+
+ "u8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i8"),
+ "u16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i16"),
+ "u32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i32"),
+ "u64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i64"),
+
+ "i8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i8"),
+ "i16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i16"),
+ "i32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i32"),
+ "i64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i64"),
+
+ "u8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i8"),
+ "u16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i16"),
+ "u32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i32"),
+ "u64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i64"),
+
+ "i8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i8"),
+ "i16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i16"),
+ "i32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i32"),
+ "i64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i64"),
+
+ "u8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i8"),
+ "u16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i16"),
+ "u32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i32"),
+ "u64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i64"),
+
_ => {
// Could we make this an enum rather than a string? does it get
// checked earlier?
use middle::trans::type_::Type;
+use std::c_str::ToCStr;
use std::libc::c_uint;
use syntax::ast;
let _icx = push_ctxt("make_visit_glue");
do with_scope(bcx, None, "visitor cleanup") |bcx| {
let mut bcx = bcx;
- let (visitor_trait, object_ty) = match ty::visitor_object_ty(bcx.tcx()){
+ let (visitor_trait, object_ty) = match ty::visitor_object_ty(bcx.tcx(),
+ ty::re_static) {
Ok(pair) => pair,
Err(s) => {
bcx.tcx().sess.fatal(s);
ppaux::ty_to_str(ccx.tcx, t));
}
+ let has_header = match ty::get(t).sty {
+ ty::ty_box(*) => true,
+ ty::ty_uniq(*) => ty::type_contents(ccx.tcx, t).contains_managed(),
+ _ => false
+ };
+
+ let borrow_offset = if has_header {
+ ccx.offsetof_gep(llty, [0u, abi::box_field_body])
+ } else {
+ C_uint(ccx, 0)
+ };
+
let llsize = llsize_of(ccx, llty);
let llalign = llalign_of(ccx, llty);
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)
}
tydesc: gvar,
size: llsize,
align: llalign,
+ borrow_offset: borrow_offset,
take_glue: None,
drop_glue: None,
free_glue: None,
}
};
+ debug!("ti.borrow_offset: %s",
+ ccx.tn.val_to_str(ti.borrow_offset));
+
let tydesc = C_named_struct(ccx.tydesc_type,
[ti.size, // size
- ti.align, // align
- take_glue, // take_glue
- drop_glue, // drop_glue
- free_glue, // free_glue
- visit_glue]); // visit_glue
+ ti.align, // align
+ take_glue, // take_glue
+ drop_glue, // drop_glue
+ free_glue, // free_glue
+ visit_glue, // visit_glue
+ ti.borrow_offset]); // borrow_offset
unsafe {
let gvar = ti.tydesc;
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;
llfn: callee_fn.llfn,
llself: val,
temp_cleanup: temp_cleanups.head_opt().map_move(|v| *v),
- self_ty: node_id_type(bcx, this.id),
self_mode: mentry.self_mode,
})
}
}
}
- typeck::method_trait(_, off, store) => {
+ typeck::method_trait(_, off) => {
trans_trait_callee(bcx,
callee_id,
off,
- this,
- store,
- mentry.explicit_self)
+ this)
}
}
}
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);
llfn: llfn_val,
llself: llself_val,
temp_cleanup: temp_cleanups.head_opt().map_move(|v| *v),
- self_ty: node_id_type(bcx, base.id),
self_mode: mentry.self_mode,
})
}
pub fn trans_trait_callee(bcx: @mut Block,
callee_id: ast::NodeId,
n_method: uint,
- self_expr: @ast::expr,
- store: ty::TraitStore,
- explicit_self: ast::explicit_self_)
+ self_expr: @ast::expr)
-> Callee {
- //!
- //
- // Create a method callee where the method is coming from a trait
- // instance (e.g., @Trait type). In this case, we must pull the
- // fn pointer out of the vtable that is packaged up with the
- // @/~/&Trait instance. @/~/&Traits are represented as a pair, so we
- // first evaluate the self expression (expected a by-ref result) and then
- // extract the self data and vtable out of the pair.
+ /*!
+ * Create a method callee where the method is coming from a trait
+ * object (e.g., @Trait type). In this case, we must pull the fn
+ * pointer out of the vtable that is packaged up with the object.
+ * Objects are represented as a pair, so we first evaluate the self
+ * expression and then extract the self data and vtable out of the
+ * pair.
+ */
let _icx = push_ctxt("impl::trans_trait_callee");
let mut bcx = bcx;
- let self_datum = unpack_datum!(bcx,
- expr::trans_to_datum(bcx, self_expr));
- let llpair = self_datum.to_ref_llval(bcx);
-
- let llpair = match explicit_self {
- ast::sty_region(*) => Load(bcx, llpair),
- ast::sty_static | ast::sty_value |
- ast::sty_box(_) | ast::sty_uniq => llpair
- };
+
+ let self_ty = expr_ty_adjusted(bcx, self_expr);
+ let self_scratch = scratch_datum(bcx, self_ty, "__trait_callee", false);
+ bcx = expr::trans_into(bcx, self_expr, expr::SaveIn(self_scratch.val));
+
+ // Arrange a temporary cleanup for the object in case something
+ // should go wrong before the method is actually *invoked*.
+ self_scratch.add_clean(bcx);
let callee_ty = node_id_type(bcx, callee_id);
trans_trait_callee_from_llval(bcx,
callee_ty,
n_method,
- llpair,
- store,
- explicit_self)
+ self_scratch.val,
+ Some(self_scratch.val))
}
pub fn trans_trait_callee_from_llval(bcx: @mut Block,
callee_ty: ty::t,
n_method: uint,
llpair: ValueRef,
- store: ty::TraitStore,
- explicit_self: ast::explicit_self_)
+ temp_cleanup: Option<ValueRef>)
-> Callee {
- //!
- //
- // Same as `trans_trait_callee()` above, except that it is given
- // a by-ref pointer to the @Trait pair.
+ /*!
+ * Same as `trans_trait_callee()` above, except that it is given
+ * a by-ref pointer to the object pair.
+ */
let _icx = push_ctxt("impl::trans_trait_callee");
let ccx = bcx.ccx();
- // Load the vtable from the @Trait pair
- debug!("(translating trait callee) loading vtable from pair %s",
- bcx.val_to_str(llpair));
- let llvtable = Load(bcx,
- PointerCast(bcx,
- GEPi(bcx, llpair,
- [0u, abi::trt_field_vtable]),
- Type::vtable().ptr_to().ptr_to()));
-
- // Load the box from the @Trait pair and GEP over the box header if
- // necessary:
- let mut llself;
+ // Load the data pointer from the object.
debug!("(translating trait callee) loading second index from pair");
let llboxptr = GEPi(bcx, llpair, [0u, abi::trt_field_box]);
let llbox = Load(bcx, llboxptr);
-
- // Munge `llself` appropriately for the type of `self` in the method.
- match explicit_self {
- ast::sty_static => {
- bcx.tcx().sess.bug("shouldn't see static method here");
- }
- ast::sty_value => {
- bcx.tcx().sess.bug("methods with by-value self should not be \
- called on objects");
- }
- ast::sty_region(*) => {
- match store {
- ty::UniqTraitStore
- if !ty::type_contents(bcx.tcx(), callee_ty).contains_managed() => {
- llself = llbox;
- }
- ty::BoxTraitStore |
- ty::UniqTraitStore => {
- llself = GEPi(bcx, llbox, [0u, abi::box_field_body]);
- }
- ty::RegionTraitStore(_) => {
- llself = llbox;
- }
- }
- }
- ast::sty_box(_) => {
- // Bump the reference count on the box.
- debug!("(translating trait callee) callee type is `%s`",
- bcx.ty_to_str(callee_ty));
- glue::incr_refcnt_of_boxed(bcx, llbox);
-
- // Pass a pointer to the box.
- match store {
- ty::BoxTraitStore => llself = llbox,
- _ => bcx.tcx().sess.bug("@self receiver with non-@Trait")
- }
- }
- ast::sty_uniq => {
- // Pass the unique pointer.
- match store {
- ty::UniqTraitStore => llself = llbox,
- _ => bcx.tcx().sess.bug("~self receiver with non-~Trait")
- }
-
- zero_mem(bcx, llboxptr, ty::mk_opaque_box(bcx.tcx()));
- }
- }
-
- llself = PointerCast(bcx, llself, Type::opaque_box(ccx).ptr_to());
- let scratch = scratch_datum(bcx, ty::mk_opaque_box(bcx.tcx()),
- "__trait_callee", false);
- Store(bcx, llself, scratch.val);
- scratch.add_clean(bcx);
+ let llself = PointerCast(bcx, llbox, Type::opaque_box(ccx).ptr_to());
// Load the function from the vtable and cast it to the expected type.
debug!("(translating trait callee) loading method");
let llcallee_ty = type_of_fn_from_ty(ccx, callee_ty);
-
- // Plus one in order to skip past the type descriptor.
+ let llvtable = Load(bcx,
+ PointerCast(bcx,
+ GEPi(bcx, llpair,
+ [0u, abi::trt_field_vtable]),
+ Type::vtable().ptr_to().ptr_to()));
let mptr = Load(bcx, GEPi(bcx, llvtable, [0u, n_method + 1]));
-
let mptr = PointerCast(bcx, mptr, llcallee_ty.ptr_to());
return Callee {
bcx: bcx,
data: Method(MethodData {
llfn: mptr,
- llself: scratch.to_value_llval(bcx),
- temp_cleanup: Some(scratch.val),
- self_ty: scratch.ty,
+ llself: llself,
+ temp_cleanup: temp_cleanup,
+
+ // We know that the func declaration is &self, ~self,
+ // or @self, and such functions are always by-copy
+ // (right now, at least).
self_mode: ty::ByCopy,
- /* XXX: Some(llbox) */
})
};
}
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 ]));
debug!("arg %u: %s", i, bcx.val_to_str(*a));
}
let bool_ty = ty::mk_bool();
- // XXX: Should not be BoxTraitStore!
let result = unpack_result!(bcx, callee::trans_call_inner(
self.bcx, None, mth_ty, bool_ty,
|bcx| meth::trans_trait_callee_from_llval(bcx,
mth_ty,
mth_idx,
v,
- ty::BoxTraitStore,
- ast::sty_region(
- None,
- ast::m_imm)),
+ None),
ArgVals(args), None, DontAutorefArg));
let result = bool_to_i1(bcx, result);
let next_bcx = sub_block(bcx, "next");
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 {
let int_ty = Type::int(arch);
- let elems = [
- int_ty, int_ty,
- glue_fn_ty, glue_fn_ty, glue_fn_ty, glue_fn_ty
- ];
+ // Must mirror:
+ //
+ // std::unstable::intrinsics::TyDesc
+ // type_desc in rt
+
+ let elems = [int_ty, // size
+ int_ty, // align
+ glue_fn_ty, // take
+ glue_fn_ty, // drop
+ glue_fn_ty, // free
+ glue_fn_ty, // visit
+ int_ty]; // borrow_offset
tydesc.set_struct_body(elems, false);
Type::struct_(Type::box_header_fields(ctx) + &[*ty], false)
}
+ pub fn opaque() -> Type {
+ Type::i8()
+ }
+
pub fn opaque_box(ctx: &CrateContext) -> Type {
- Type::box(ctx, &Type::i8())
+ Type::box(ctx, &Type::opaque())
}
pub fn unique(ctx: &CrateContext, ty: &Type) -> Type {
"bswap16" | "bswap32" | "bswap64" => 0,
+
+ "i8_add_with_overflow" | "u8_add_with_overflow" |
+ "i16_add_with_overflow" | "u16_add_with_overflow" |
+ "i32_add_with_overflow" | "u32_add_with_overflow" |
+ "i64_add_with_overflow" | "u64_add_with_overflow" => 0,
+
+ "i8_sub_with_overflow" | "u8_sub_with_overflow" |
+ "i16_sub_with_overflow" | "u16_sub_with_overflow" |
+ "i32_sub_with_overflow" | "u32_sub_with_overflow" |
+ "i64_sub_with_overflow" | "u64_sub_with_overflow" => 0,
+
+ "i8_mul_with_overflow" | "u8_mul_with_overflow" |
+ "i16_mul_with_overflow" | "u16_mul_with_overflow" |
+ "i32_mul_with_overflow" | "u32_mul_with_overflow" |
+ "i64_mul_with_overflow" | "u64_mul_with_overflow" => 0,
+
// would be cool to make these an enum instead of
// strings!
_ => fail!("unknown intrinsic in type_use")
--- /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() }
+ }
+}
AutoBorrowFn(Region),
/// Convert from T to *T
- AutoUnsafe(ast::mutability)
+ AutoUnsafe(ast::mutability),
+
+ /// Convert from @Trait/~Trait/&Trait to &Trait
+ AutoBorrowObj(Region, ast::mutability),
}
pub type ctxt = @ctxt_;
struct ctxt_ {
- diag: @syntax::diagnostic::span_handler,
+ diag: @mut syntax::diagnostic::span_handler,
interner: @mut HashMap<intern_key, ~t_box_>,
next_id: @mut uint,
cstore: @mut metadata::cstore::CStore,
&ty_self(_) => flags |= has_self as uint,
&ty_enum(_, ref substs) | &ty_struct(_, ref substs) |
&ty_trait(_, ref substs, _, _, _) => {
- flags |= sflags(substs);
+ flags |= sflags(substs);
+ match st {
+ ty_trait(_, _, RegionTraitStore(r), _, _) => {
+ flags |= rflags(r);
+ }
+ _ => {}
+ }
}
&ty_box(ref m) | &ty_uniq(ref m) | &ty_evec(ref m, _) |
&ty_ptr(ref m) | &ty_unboxed_vec(ref m) => {
AutoUnsafe(m) => {
mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m})
}
+
+ AutoBorrowObj(r, m) => {
+ borrow_obj(cx, span, r, m, adjusted_ty)
+ }
}
}
}
}
}
}
+
+ fn borrow_obj(cx: ctxt, span: span, r: Region,
+ m: ast::mutability, ty: ty::t) -> ty::t {
+ match get(ty).sty {
+ ty_trait(trt_did, ref trt_substs, _, _, b) => {
+ ty::mk_trait(cx, trt_did, trt_substs.clone(),
+ RegionTraitStore(r), m, b)
+ }
+ ref s => {
+ cx.sess.span_bug(
+ span,
+ fmt!("borrow-trait-obj associated with bad sty: %?",
+ s));
+ }
+ }
+ }
}
impl AutoRef {
ty::AutoBorrowVecRef(r, m) => ty::AutoBorrowVecRef(f(r), m),
ty::AutoBorrowFn(r) => ty::AutoBorrowFn(f(r)),
ty::AutoUnsafe(m) => ty::AutoUnsafe(m),
+ ty::AutoBorrowObj(r, m) => ty::AutoBorrowObj(f(r), m),
}
}
}
typeck::method_param(typeck::method_param {
trait_id: trt_id,
method_num: n_mth, _}) |
- typeck::method_trait(trt_id, n_mth, _) => {
+ typeck::method_trait(trt_id, n_mth) => {
// ...trait methods bounds, in contrast, include only the
// method bounds, so we must preprend the tps from the
// trait itself. This ought to be harmonized.
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")
}
}
-pub fn visitor_object_ty(tcx: ctxt) -> Result<(@TraitRef, t), ~str> {
+pub fn visitor_object_ty(tcx: ctxt,
+ region: ty::Region) -> Result<(@TraitRef, t), ~str> {
let trait_lang_item = match tcx.lang_items.require(TyVisitorTraitLangItem) {
Ok(id) => id,
Err(s) => { return Err(s); }
tps: ~[]
};
let trait_ref = @TraitRef { def_id: trait_lang_item, substs: substs };
- let mut static_trait_bound = EmptyBuiltinBounds();
- static_trait_bound.add(BoundStatic);
Ok((trait_ref,
mk_trait(tcx,
trait_ref.def_id,
trait_ref.substs.clone(),
- BoxTraitStore,
+ RegionTraitStore(region),
ast::m_imm,
- static_trait_bound)))
+ EmptyBuiltinBounds())))
}
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
use middle::typeck::{param_numbered, param_self, param_index};
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
use util::common::indenter;
+use util::ppaux::Repr;
use std::hashmap::HashSet;
use std::result;
check_traits: check_traits,
autoderef_receiver: autoderef_receiver,
};
- let mme = lcx.do_lookup(self_ty);
- debug!("method lookup for %s yielded %?", expr.repr(fcx.tcx()), mme);
- return mme;
+
+ let self_ty = structurally_resolved_type(fcx, self_expr.span, self_ty);
+ debug!("method lookup(self_ty=%s, expr=%s, self_expr=%s)",
+ self_ty.repr(fcx.tcx()), expr.repr(fcx.tcx()),
+ self_expr.repr(fcx.tcx()));
+
+ debug!("searching inherent candidates");
+ lcx.push_inherent_candidates(self_ty);
+ let mme = lcx.search(self_ty);
+ if mme.is_some() {
+ return mme;
+ }
+
+ debug!("searching extension candidates");
+ lcx.reset_candidates();
+ lcx.push_bound_candidates(self_ty);
+ lcx.push_extension_candidates();
+ return lcx.search(self_ty);
}
pub struct LookupContext<'self> {
*/
#[deriving(Clone)]
pub struct Candidate {
- rcvr_ty: ty::t,
+ rcvr_match_condition: RcvrMatchCondition,
rcvr_substs: ty::substs,
method_ty: @ty::Method,
origin: method_origin,
}
-impl<'self> LookupContext<'self> {
- pub fn do_lookup(&self, self_ty: ty::t) -> Option<method_map_entry> {
- let self_ty = structurally_resolved_type(self.fcx,
- self.self_expr.span,
- self_ty);
-
- debug!("do_lookup(self_ty=%s, expr=%s, self_expr=%s)",
- self.ty_to_str(self_ty),
- self.expr.repr(self.tcx()),
- self.self_expr.repr(self.tcx()));
-
- // Prepare the list of candidates
- self.push_inherent_candidates(self_ty);
- self.push_extension_candidates();
+/// This type represents the conditions under which the receiver is
+/// considered to "match" a given method candidate. Typically the test
+/// is whether the receiver is of a particular type. However, this
+/// type is the type of the receiver *after accounting for the
+/// method's self type* (e.g., if the method is an `@self` method, we
+/// have *already verified* that the receiver is of some type `@T` and
+/// now we must check that the type `T` is correct). Unfortunately,
+/// because traits are not types, this is a pain to do.
+#[deriving(Clone)]
+enum RcvrMatchCondition {
+ RcvrMatchesIfObject(ast::def_id),
+ RcvrMatchesIfSubtype(ty::t)
+}
+impl<'self> LookupContext<'self> {
+ fn search(&self, self_ty: ty::t) -> Option<method_map_entry> {
let mut self_ty = self_ty;
let mut autoderefs = 0;
loop {
self.search_for_autosliced_method(self_ty, autoderefs)
}
- pub fn deref(&self, ty: ty::t)
+ fn deref(&self, ty: ty::t)
-> Option<ty::t> {
match ty::deref(self.tcx(), ty, false) {
None => None,
// ______________________________________________________________________
// Candidate collection (see comment at start of file)
- pub fn push_inherent_candidates(&self, self_ty: ty::t) {
+ fn reset_candidates(&self) {
+ *self.inherent_candidates = ~[];
+ *self.extension_candidates = ~[];
+ }
+
+ fn push_inherent_candidates(&self, self_ty: ty::t) {
/*!
* Collect all inherent candidates into
* `self.inherent_candidates`. See comment at the start of
let mut self_ty = self_ty;
loop {
match get(self_ty).sty {
- ty_param(p) => {
- self.push_inherent_candidates_from_param(self_ty, p);
- }
- ty_trait(did, ref substs, store, _, _) => {
- self.push_inherent_candidates_from_trait(
- self_ty, did, substs, store);
+ ty_trait(did, ref substs, _, _, _) => {
+ self.push_inherent_candidates_from_trait(did, substs);
self.push_inherent_impl_candidates_for_type(did);
}
- ty_self(self_did) => {
- // Call is of the form "self.foo()" and appears in one
- // of a trait's default method implementations.
- self.push_inherent_candidates_from_self(
- self_ty, self_did);
- }
ty_enum(did, _) | ty_struct(did, _) => {
if self.check_traits == CheckTraitsAndInherentMethods {
self.push_inherent_impl_candidates_for_type(did);
}
}
- pub fn push_extension_candidates(&self) {
+ fn push_bound_candidates(&self, self_ty: ty::t) {
+ let mut self_ty = self_ty;
+ loop {
+ match get(self_ty).sty {
+ ty_param(p) => {
+ self.push_inherent_candidates_from_param(self_ty, p);
+ }
+ ty_self(self_did) => {
+ // Call is of the form "self.foo()" and appears in one
+ // of a trait's default method implementations.
+ self.push_inherent_candidates_from_self(
+ self_ty, self_did);
+ }
+ _ => { /* No bound methods in these types */ }
+ }
+
+ self_ty = match self.deref(self_ty) {
+ None => { return; }
+ Some(ty) => { ty }
+ }
+ }
+ }
+
+ fn push_extension_candidates(&self) {
// If the method being called is associated with a trait, then
// find all the impls of that trait. Each of those are
// candidates.
}
}
- pub fn push_inherent_candidates_from_trait(&self,
- self_ty: ty::t,
+ fn push_inherent_candidates_from_trait(&self,
did: def_id,
- substs: &ty::substs,
- store: ty::TraitStore) {
+ substs: &ty::substs) {
debug!("push_inherent_candidates_from_trait(did=%s, substs=%s)",
self.did_to_str(did),
substs_to_str(self.tcx(), substs));
};
let method = ms[index];
- /* FIXME(#5762) we should transform the vstore in accordance
- with the self type
-
- match method.self_type {
- ast::sty_region(_) => {
- return; // inapplicable
+ match method.explicit_self {
+ ast::sty_static => {
+ return; // not a method we can call with dot notation
}
- ast::sty_region(_) => vstore_slice(r)
- ast::sty_box(_) => vstore_box, // NDM mutability, as per #5762
- ast::sty_uniq(_) => vstore_uniq
+ _ => {}
}
- */
// It is illegal to invoke a method on a trait instance that
- // refers to the `self` type. Nonetheless, we substitute
- // `trait_ty` for `self` here, because it allows the compiler
- // to soldier on. An error will be reported should this
- // candidate be selected if the method refers to `self`.
+ // refers to the `self` type. An error will be reported by
+ // `enforce_object_limitations()` if the method refers
+ // to the `Self` type. Substituting ty_err here allows
+ // compiler to soldier on.
//
- // NB: `confirm_candidate()` also relies upon this substitution
- // for Self.
+ // NOTE: `confirm_candidate()` also relies upon this substitution
+ // for Self. (fix)
let rcvr_substs = substs {
- self_ty: Some(self_ty),
+ self_ty: Some(ty::mk_err()),
..(*substs).clone()
};
self.inherent_candidates.push(Candidate {
- rcvr_ty: self_ty,
+ rcvr_match_condition: RcvrMatchesIfObject(did),
rcvr_substs: rcvr_substs,
method_ty: method,
- origin: method_trait(did, index, store)
+ origin: method_trait(did, index)
});
}
- pub fn push_inherent_candidates_from_param(&self,
+ fn push_inherent_candidates_from_param(&self,
rcvr_ty: ty::t,
param_ty: param_ty) {
debug!("push_inherent_candidates_from_param(param_ty=%?)",
}
- pub fn push_inherent_candidates_from_self(&self,
+ fn push_inherent_candidates_from_self(&self,
self_ty: ty::t,
did: def_id) {
let tcx = self.tcx();
self_ty, &[trait_ref], param_self);
}
- pub fn push_inherent_candidates_from_bounds(&self,
+ fn push_inherent_candidates_from_bounds(&self,
self_ty: ty::t,
bounds: &[@TraitRef],
param: param_index) {
let method = trait_methods[pos];
let cand = Candidate {
- rcvr_ty: self_ty,
+ rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
rcvr_substs: bound_trait_ref.substs.clone(),
method_ty: method,
origin: method_param(
- method_param {
+ method_param {
trait_id: bound_trait_ref.def_id,
method_num: pos,
param_num: param,
}
- pub fn push_inherent_impl_candidates_for_type(&self, did: def_id) {
+ fn push_inherent_impl_candidates_for_type(&self, did: def_id) {
let opt_impl_infos = self.tcx().inherent_impls.find(&did);
for impl_infos in opt_impl_infos.iter() {
for impl_info in impl_infos.iter() {
}
}
- pub fn push_candidates_from_impl(&self,
+ fn push_candidates_from_impl(&self,
candidates: &mut ~[Candidate],
impl_info: &ty::Impl) {
if !self.impl_dups.insert(impl_info.did) {
} = impl_self_ty(&vcx, location_info, impl_info.did);
candidates.push(Candidate {
- rcvr_ty: impl_ty,
+ rcvr_match_condition: RcvrMatchesIfSubtype(impl_ty),
rcvr_substs: impl_substs,
method_ty: method,
origin: method_static(method.def_id)
// ______________________________________________________________________
// Candidate selection (see comment at start of file)
- pub fn search_for_autoderefd_method(&self,
+ fn search_for_autoderefd_method(&self,
self_ty: ty::t,
autoderefs: uint)
-> Option<method_map_entry> {
}
}
- pub fn consider_reborrow(&self,
+ fn consider_reborrow(&self,
self_ty: ty::t,
autoderefs: uint)
-> (ty::t, ty::AutoAdjustment) {
/*!
- *
* In the event that we are invoking a method with a receiver
* of a borrowed type like `&T`, `&mut T`, or `&mut [T]`,
* we will "reborrow" the receiver implicitly. For example, if
autoderefs: autoderefs,
autoref: Some(ty::AutoBorrowVec(region, self_mt.mutbl))}))
}
+ ty_trait(did, ref substs, ty::RegionTraitStore(_), mutbl, bounds) => {
+ let region =
+ self.infcx().next_region_var(
+ infer::Autoref(self.expr.span));
+ (ty::mk_trait(tcx, did, substs.clone(),
+ ty::RegionTraitStore(region),
+ mutbl, bounds),
+ ty::AutoDerefRef(ty::AutoDerefRef {
+ autoderefs: autoderefs,
+ autoref: Some(ty::AutoBorrowObj(region, mutbl))}))
+ }
_ => {
(self_ty,
ty::AutoDerefRef(ty::AutoDerefRef {
}
}
- pub fn search_for_autosliced_method(&self,
+ fn search_for_autosliced_method(&self,
self_ty: ty::t,
autoderefs: uint)
-> Option<method_map_entry> {
* `~[]` to `&[]`. */
let tcx = self.tcx();
- match ty::get(self_ty).sty {
+ let sty = ty::get(self_ty).sty.clone();
+ match sty {
ty_evec(mt, vstore_box) |
ty_evec(mt, vstore_uniq) |
ty_evec(mt, vstore_slice(_)) | // NDM(#3148)
})
}
- ty_trait(*) | ty_closure(*) => {
- // NDM---eventually these should be some variant of autoref
+ ty_trait(trt_did, trt_substs, _, _, b) => {
+ // Coerce ~/@/&Trait instances to &Trait.
+
+ self.search_for_some_kind_of_autorefd_method(
+ AutoBorrowObj, autoderefs, [m_const, m_imm, m_mutbl],
+ |trt_mut, reg| {
+ ty::mk_trait(tcx, trt_did, trt_substs.clone(),
+ RegionTraitStore(reg), trt_mut, b)
+ })
+ }
+
+ ty_closure(*) => {
+ // This case should probably be handled similarly to
+ // Trait instances.
None
}
}
}
- pub fn search_for_autoptrd_method(&self, self_ty: ty::t, autoderefs: uint)
+ fn search_for_autoptrd_method(&self, self_ty: ty::t, autoderefs: uint)
-> Option<method_map_entry> {
/*!
*
}
}
- pub fn search_for_some_kind_of_autorefd_method(
+ fn search_for_some_kind_of_autorefd_method(
&self,
kind: &fn(Region, ast::mutability) -> ty::AutoRef,
autoderefs: uint,
return None;
}
- pub fn search_for_method(&self, rcvr_ty: ty::t)
+ fn search_for_method(&self, rcvr_ty: ty::t)
-> Option<method_map_entry> {
debug!("search_for_method(rcvr_ty=%s)", self.ty_to_str(rcvr_ty));
let _indenter = indenter();
}
}
- pub fn consider_candidates(&self,
+ fn consider_candidates(&self,
rcvr_ty: ty::t,
candidates: &mut ~[Candidate])
-> 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);
Some(self.confirm_candidate(rcvr_ty, &relevant_candidates[0]))
}
- pub fn merge_candidates(&self, candidates: &[Candidate]) -> ~[Candidate] {
+ fn merge_candidates(&self, candidates: &[Candidate]) -> ~[Candidate] {
let mut merged = ~[];
let mut i = 0;
while i < candidates.len() {
return merged;
}
- pub fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
+ fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
-> method_map_entry {
let tcx = self.tcx();
let fty = self.fn_ty_from_origin(&candidate.origin);
self.cand_to_str(candidate),
self.ty_to_str(fty));
- self.enforce_trait_instance_limitations(fty, candidate);
+ self.enforce_object_limitations(fty, candidate);
self.enforce_drop_trait_limitations(candidate);
// static methods should never have gotten this far:
assert!(candidate.method_ty.explicit_self != sty_static);
let transformed_self_ty = match candidate.origin {
- method_trait(*) => {
- match candidate.method_ty.explicit_self {
- sty_region(*) => {
- // FIXME(#5762) again, preserving existing
- // behavior here which (for &self) desires
- // &@Trait where @Trait is the type of the
- // receiver. Here we fetch the method's
- // transformed_self_ty which will be something
- // like &'a Self. We then perform a
- // substitution which will replace Self with
- // @Trait.
- let t = candidate.method_ty.transformed_self_ty.unwrap();
- ty::subst(tcx, &candidate.rcvr_substs, t)
- }
- _ => {
- candidate.rcvr_ty
- }
- }
+ method_trait(trait_def_id, _) => {
+ self.construct_transformed_self_ty_for_object(
+ trait_def_id, candidate)
}
_ => {
let t = candidate.method_ty.transformed_self_ty.unwrap();
self.fcx.write_ty(self.callee_id, fty);
self.fcx.write_substs(self.callee_id, all_substs);
method_map_entry {
- self_ty: rcvr_ty,
+ self_ty: transformed_self_ty,
self_mode: self_mode,
explicit_self: candidate.method_ty.explicit_self,
origin: candidate.origin,
}
}
- pub fn enforce_trait_instance_limitations(&self,
- method_fty: ty::t,
- candidate: &Candidate) {
+ fn construct_transformed_self_ty_for_object(&self,
+ trait_def_id: ast::def_id,
+ candidate: &Candidate) -> ty::t
+ {
/*!
+ * This is a bit tricky. We have a match against a trait method
+ * being invoked on an object, and we want to generate the
+ * self-type. As an example, consider a trait
+ *
+ * trait Foo {
+ * fn r_method<'a>(&'a self);
+ * fn m_method(@mut self);
+ * }
*
- * There are some limitations to calling functions through a
- * trait instance, because (a) the self type is not known
+ * Now, assuming that `r_method` is being called, we want the
+ * result to be `&'a Foo`. Assuming that `m_method` is being
+ * called, we want the result to be `@mut Foo`. Of course,
+ * this transformation has already been done as part of
+ * `candidate.method_ty.transformed_self_ty`, but there the
+ * type is expressed in terms of `Self` (i.e., `&'a Self`, `@mut Self`).
+ * Because objects are not standalone types, we can't just substitute
+ * `s/Self/Foo/`, so we must instead perform this kind of hokey
+ * match below.
+ */
+
+ let substs = ty::substs {regions: candidate.rcvr_substs.regions.clone(),
+ self_ty: None,
+ tps: candidate.rcvr_substs.tps.clone()};
+ match candidate.method_ty.explicit_self {
+ ast::sty_static => {
+ self.bug(~"static method for object type receiver");
+ }
+ ast::sty_value => {
+ ty::mk_err() // error reported in `enforce_object_limitations()`
+ }
+ ast::sty_region(*) | ast::sty_box(*) | ast::sty_uniq(*) => {
+ let transformed_self_ty =
+ candidate.method_ty.transformed_self_ty.clone().unwrap();
+ match ty::get(transformed_self_ty).sty {
+ ty::ty_rptr(r, mt) => { // must be sty_region
+ ty::mk_trait(self.tcx(), trait_def_id,
+ substs, RegionTraitStore(r), mt.mutbl,
+ ty::EmptyBuiltinBounds())
+ }
+ ty::ty_box(mt) => { // must be sty_box
+ ty::mk_trait(self.tcx(), trait_def_id,
+ substs, BoxTraitStore, mt.mutbl,
+ ty::EmptyBuiltinBounds())
+ }
+ ty::ty_uniq(mt) => { // must be sty_uniq
+ ty::mk_trait(self.tcx(), trait_def_id,
+ substs, UniqTraitStore, mt.mutbl,
+ ty::EmptyBuiltinBounds())
+ }
+ _ => {
+ self.bug(
+ fmt!("'impossible' transformed_self_ty: %s",
+ transformed_self_ty.repr(self.tcx())));
+ }
+ }
+ }
+ }
+ }
+
+ fn enforce_object_limitations(&self,
+ method_fty: ty::t,
+ candidate: &Candidate)
+ {
+ /*!
+ * There are some limitations to calling functions through an
+ * object, because (a) the self type is not known
* (that's the whole point of a trait instance, after all, to
* obscure the self type) and (b) the call must go through a
- * vtable and hence cannot be monomorphized. */
+ * vtable and hence cannot be monomorphized.
+ */
match candidate.origin {
method_static(*) | method_param(*) => {
method_trait(*) => {}
}
- if ty::type_has_self(method_fty) {
+ match candidate.method_ty.explicit_self {
+ ast::sty_static => { // reason (a) above
+ self.tcx().sess.span_err(
+ self.expr.span,
+ "cannot call a method without a receiver \
+ through an object");
+ }
+
+ ast::sty_value => { // reason (a) above
+ self.tcx().sess.span_err(
+ self.expr.span,
+ "cannot call a method with a by-value receiver \
+ through an object");
+ }
+
+ ast::sty_region(*) | ast::sty_box(*) | ast::sty_uniq(*) => {}
+ }
+
+ if ty::type_has_self(method_fty) { // reason (a) above
self.tcx().sess.span_err(
self.expr.span,
"cannot call a method whose type contains a \
- self-type through a boxed trait");
+ self-type through an object");
}
- if candidate.method_ty.generics.has_type_params() {
+ if candidate.method_ty.generics.has_type_params() { // reason (b) above
self.tcx().sess.span_err(
self.expr.span,
- "cannot call a generic method through a boxed trait");
+ "cannot call a generic method through an object");
}
}
- pub fn enforce_drop_trait_limitations(&self, candidate: &Candidate) {
+ fn enforce_drop_trait_limitations(&self, candidate: &Candidate) {
// No code can call the finalize method explicitly.
let bad;
match candidate.origin {
// XXX: does this properly enforce this on everything now
// that self has been merged in? -sully
method_param(method_param { trait_id: trait_id, _ }) |
- method_trait(trait_id, _, _) => {
+ method_trait(trait_id, _) => {
bad = self.tcx().destructor_for_type.contains_key(&trait_id);
}
}
// `rcvr_ty` is the type of the expression. It may be a subtype of a
// candidate method's `self_ty`.
- pub fn is_relevant(&self, rcvr_ty: ty::t, candidate: &Candidate) -> bool {
+ fn is_relevant(&self, rcvr_ty: ty::t, candidate: &Candidate) -> bool {
debug!("is_relevant(rcvr_ty=%s, candidate=%s)",
self.ty_to_str(rcvr_ty), self.cand_to_str(candidate));
- // Check for calls to object methods. We resolve these differently.
- //
- // FIXME(#5762)---we don't check that an @self method is only called
- // on an @Trait object here and so forth
- match candidate.origin {
- method_trait(*) => {
- match candidate.method_ty.explicit_self {
- sty_static | sty_value => {
- return false;
- }
- sty_region(*) => {
- // just echoing current behavior here, which treats
- // an &self method on an @Trait object as requiring
- // an &@Trait receiver (wacky)
- }
- sty_box(*) | sty_uniq(*) => {
- return self.fcx.can_mk_subty(rcvr_ty,
- candidate.rcvr_ty).is_ok();
- }
- };
- }
- _ => {}
- }
-
- let result = match candidate.method_ty.explicit_self {
+ return match candidate.method_ty.explicit_self {
sty_static => {
debug!("(is relevant?) explicit self is static");
false
}
sty_value => {
- debug!("(is relevant?) explicit self is by-value");
- self.fcx.can_mk_subty(rcvr_ty, candidate.rcvr_ty).is_ok()
+ rcvr_matches_ty(self.fcx, rcvr_ty, candidate)
}
sty_region(_, m) => {
match ty::get(rcvr_ty).sty {
ty::ty_rptr(_, mt) => {
mutability_matches(mt.mutbl, m) &&
- self.fcx.can_mk_subty(mt.ty, candidate.rcvr_ty).is_ok()
+ rcvr_matches_ty(self.fcx, mt.ty, candidate)
+ }
+
+ ty::ty_trait(self_did, _, RegionTraitStore(_), self_m, _) => {
+ mutability_matches(self_m, m) &&
+ rcvr_matches_object(self_did, candidate)
}
_ => false
match ty::get(rcvr_ty).sty {
ty::ty_box(mt) => {
mutability_matches(mt.mutbl, m) &&
- self.fcx.can_mk_subty(mt.ty, candidate.rcvr_ty).is_ok()
+ rcvr_matches_ty(self.fcx, mt.ty, candidate)
+ }
+
+ ty::ty_trait(self_did, _, BoxTraitStore, self_m, _) => {
+ mutability_matches(self_m, m) &&
+ rcvr_matches_object(self_did, candidate)
}
_ => false
debug!("(is relevant?) explicit self is a unique pointer");
match ty::get(rcvr_ty).sty {
ty::ty_uniq(mt) => {
- mutability_matches(mt.mutbl, ast::m_imm) &&
- self.fcx.can_mk_subty(mt.ty, candidate.rcvr_ty).is_ok()
+ rcvr_matches_ty(self.fcx, mt.ty, candidate)
+ }
+
+ ty::ty_trait(self_did, _, UniqTraitStore, _, _) => {
+ rcvr_matches_object(self_did, candidate)
}
_ => false
}
};
- debug!("(is relevant?) %s", if result { "yes" } else { "no" });
+ fn rcvr_matches_object(self_did: ast::def_id,
+ candidate: &Candidate) -> bool {
+ match candidate.rcvr_match_condition {
+ RcvrMatchesIfObject(desired_did) => {
+ self_did == desired_did
+ }
+ RcvrMatchesIfSubtype(_) => {
+ false
+ }
+ }
+ }
- return result;
+ fn rcvr_matches_ty(fcx: @mut FnCtxt,
+ rcvr_ty: ty::t,
+ candidate: &Candidate) -> bool {
+ match candidate.rcvr_match_condition {
+ RcvrMatchesIfObject(_) => {
+ false
+ }
+ RcvrMatchesIfSubtype(of_type) => {
+ fcx.can_mk_subty(rcvr_ty, of_type).is_ok()
+ }
+ }
+ }
fn mutability_matches(self_mutbl: ast::mutability,
candidate_mutbl: ast::mutability) -> bool {
}
}
- pub fn fn_ty_from_origin(&self, origin: &method_origin) -> ty::t {
+ fn fn_ty_from_origin(&self, origin: &method_origin) -> ty::t {
return match *origin {
method_static(did) => {
ty::lookup_item_type(self.tcx(), did).ty
method_param(ref mp) => {
type_of_trait_method(self.tcx(), mp.trait_id, mp.method_num)
}
- method_trait(did, idx, _) => {
+ method_trait(did, idx) => {
type_of_trait_method(self.tcx(), did, idx)
}
};
}
}
- pub fn report_candidate(&self, idx: uint, origin: &method_origin) {
+ fn report_candidate(&self, idx: uint, origin: &method_origin) {
match *origin {
method_static(impl_did) => {
self.report_static_candidate(idx, impl_did)
method_param(ref mp) => {
self.report_param_candidate(idx, (*mp).trait_id)
}
- method_trait(trait_did, _, _) => {
+ method_trait(trait_did, _) => {
self.report_trait_candidate(idx, trait_did)
}
}
}
- pub fn report_static_candidate(&self, idx: uint, did: def_id) {
+ fn report_static_candidate(&self, idx: uint, did: def_id) {
let span = if did.crate == ast::LOCAL_CRATE {
match self.tcx().items.find(&did.node) {
Some(&ast_map::node_method(m, _, _)) => m.span,
ty::item_path_str(self.tcx(), did)));
}
- pub fn report_param_candidate(&self, idx: uint, did: def_id) {
+ fn report_param_candidate(&self, idx: uint, did: def_id) {
self.tcx().sess.span_note(
self.expr.span,
fmt!("candidate #%u derives from the bound `%s`",
ty::item_path_str(self.tcx(), did)));
}
- pub fn report_trait_candidate(&self, idx: uint, did: def_id) {
+ fn report_trait_candidate(&self, idx: uint, did: def_id) {
self.tcx().sess.span_note(
self.expr.span,
fmt!("candidate #%u derives from the type of the receiver, \
ty::item_path_str(self.tcx(), did)));
}
- pub fn infcx(&self) -> @mut infer::InferCtxt {
+ fn infcx(&self) -> @mut infer::InferCtxt {
self.fcx.inh.infcx
}
- pub fn tcx(&self) -> ty::ctxt {
+ fn tcx(&self) -> ty::ctxt {
self.fcx.tcx()
}
- pub fn ty_to_str(&self, t: ty::t) -> ~str {
+ fn ty_to_str(&self, t: ty::t) -> ~str {
self.fcx.infcx().ty_to_str(t)
}
- pub fn cand_to_str(&self, cand: &Candidate) -> ~str {
+ fn cand_to_str(&self, cand: &Candidate) -> ~str {
fmt!("Candidate(rcvr_ty=%s, rcvr_substs=%s, origin=%?)",
- self.ty_to_str(cand.rcvr_ty),
+ cand.rcvr_match_condition.repr(self.tcx()),
ty::substs_to_str(self.tcx(), &cand.rcvr_substs),
cand.origin)
}
- pub fn did_to_str(&self, did: def_id) -> ~str {
+ fn did_to_str(&self, did: def_id) -> ~str {
ty::item_path_str(self.tcx(), did)
}
- pub fn bug(&self, s: ~str) -> ! {
- self.tcx().sess.bug(s)
+ fn bug(&self, s: ~str) -> ! {
+ self.tcx().sess.span_bug(self.self_expr.span, s)
}
}
_ => ty::ByCopy,
}
}
+
+impl Repr for RcvrMatchCondition {
+ fn repr(&self, tcx: ty::ctxt) -> ~str {
+ match *self {
+ RcvrMatchesIfObject(d) => {
+ fmt!("RcvrMatchesIfObject(%s)", d.repr(tcx))
+ }
+ RcvrMatchesIfSubtype(t) => {
+ fmt!("RcvrMatchesIfSubtype(%s)", t.repr(tcx))
+ }
+ }
+ }
+}
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
Ok(t) => t,
Err(s) => { tcx.sess.span_fatal(it.span, s); }
};
- let visitor_object_ty = match ty::visitor_object_ty(tcx) {
+ let region = ty::re_bound(ty::br_anon(0));
+ let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
Ok((_, vot)) => vot,
Err(s) => { tcx.sess.span_fatal(it.span, s); }
};
"bswap16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
"bswap32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
"bswap64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
+
+ "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" =>
+ (0, ~[ty::mk_i8(), ty::mk_i8()],
+ ty::mk_tup(tcx, ~[ty::mk_i8(), ty::mk_bool()])),
+
+ "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" =>
+ (0, ~[ty::mk_i16(), ty::mk_i16()],
+ ty::mk_tup(tcx, ~[ty::mk_i16(), ty::mk_bool()])),
+
+ "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" =>
+ (0, ~[ty::mk_i32(), ty::mk_i32()],
+ ty::mk_tup(tcx, ~[ty::mk_i32(), ty::mk_bool()])),
+
+ "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" =>
+ (0, ~[ty::mk_i64(), ty::mk_i64()],
+ ty::mk_tup(tcx, ~[ty::mk_i64(), ty::mk_bool()])),
+
+ "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" =>
+ (0, ~[ty::mk_u8(), ty::mk_u8()],
+ ty::mk_tup(tcx, ~[ty::mk_u8(), ty::mk_bool()])),
+
+ "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" =>
+ (0, ~[ty::mk_u16(), ty::mk_u16()],
+ ty::mk_tup(tcx, ~[ty::mk_u16(), ty::mk_bool()])),
+
+ "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=>
+ (0, ~[ty::mk_u32(), ty::mk_u32()],
+ ty::mk_tup(tcx, ~[ty::mk_u32(), ty::mk_bool()])),
+
+ "u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" =>
+ (0, ~[ty::mk_u64(), ty::mk_u64()],
+ ty::mk_tup(tcx, ~[ty::mk_u64(), ty::mk_bool()])),
+
ref other => {
tcx.sess.span_err(it.span,
fmt!("unrecognized intrinsic function: `%s`",
ty::AutoBorrowVec(r, _) |
ty::AutoBorrowVecRef(r, _) |
- ty::AutoBorrowFn(r) => {
+ ty::AutoBorrowFn(r) |
+ ty::AutoBorrowObj(r, _) => {
// In each of these cases, what is being borrowed is
// not the (autoderef'd) expr itself but rather the
// contents of the autoderef'd expression (i.e., what
Some(ty::AutoPtr(r, _)) |
Some(ty::AutoBorrowVec(r, _)) |
Some(ty::AutoBorrowVecRef(r, _)) |
- Some(ty::AutoBorrowFn(r)) => {
+ Some(ty::AutoBorrowFn(r)) |
+ Some(ty::AutoBorrowObj(r, _)) => {
// If there is an autoref, then the result of this
// expression will be some sort of borrowed pointer.
expr_ct.cat.guarantor = 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,
*/
-use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowFn};
+use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowFn, AutoBorrowObj};
use middle::ty::{AutoDerefRef};
use middle::ty::{vstore_slice, vstore_box, vstore_uniq};
use middle::ty::{mt};
};
}
+ ty::ty_trait(_, _, ty::RegionTraitStore(*), _, _) => {
+ return do self.unpack_actual_value(a) |sty_a| {
+ self.coerce_borrowed_object(a, sty_a, b)
+ };
+ }
+
ty::ty_ptr(mt_b) => {
return do self.unpack_actual_value(a) |sty_a| {
self.coerce_unsafe_ptr(a, sty_a, b, mt_b)
})))
}
+ fn coerce_borrowed_object(&self,
+ a: ty::t,
+ sty_a: &ty::sty,
+ b: ty::t) -> CoerceResult
+ {
+ debug!("coerce_borrowed_object(a=%s, sty_a=%?, b=%s)",
+ a.inf_str(self.infcx), sty_a,
+ b.inf_str(self.infcx));
+
+ let tcx = self.infcx.tcx;
+ let r_a = self.infcx.next_region_var(Coercion(self.trace));
+ let trt_mut;
+
+ let a_borrowed = match *sty_a {
+ ty::ty_trait(_, _, ty::RegionTraitStore(_), _, _) => {
+ return self.subtype(a, b);
+ }
+ ty::ty_trait(did, ref substs, _, m, b) => {
+ trt_mut = m;
+ ty::mk_trait(tcx, did, substs.clone(),
+ ty::RegionTraitStore(r_a), m, b)
+ }
+ _ => {
+ return self.subtype(a, b);
+ }
+ };
+
+ if_ok!(self.tys(a_borrowed, b));
+ Ok(Some(@AutoDerefRef(AutoDerefRef {
+ autoderefs: 0,
+ autoref: Some(AutoBorrowObj(r_a, trt_mut))
+ })))
+ }
+
pub fn coerce_borrowed_fn(&self,
a: ty::t,
sty_a: &ty::sty,
method_param(method_param),
// method invoked on a trait instance
- method_trait(ast::def_id, uint, ty::TraitStore),
+ method_trait(ast::def_id, uint),
}
");
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);
let ch_capture = ch.clone();
let mut task_builder = task::task();
task_builder.supervised();
- task_builder.opts.stack_size = Some(STACK_SIZE);
+
+ // XXX: Hacks on hacks. If the env is trying to override the stack size
+ // then *don't* set it explicitly.
+ if os::getenv("RUST_MIN_STACK").is_none() {
+ task_builder.opts.stack_size = Some(STACK_SIZE);
+ }
+
match do task_builder.try {
let ch = ch_capture.clone();
let ch_capture = ch.clone();
&typeck::method_param(ref p) => {
p.repr(tcx)
}
- &typeck::method_trait(def_id, n, st) => {
- fmt!("method_trait(%s, %?, %s)", def_id.repr(tcx), n,
- st.repr(tcx))
+ &typeck::method_trait(def_id, n) => {
+ fmt!("method_trait(%s, %?)", def_id.repr(tcx), n)
}
}
}
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]
--- /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"));
+ }
+ }
+
}
#[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;
- }
-}
#[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 that has a `.peek()` method
+ /// that returns a optional reference to the next element.
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// let a = [100, 200, 300];
+ /// let mut it = xs.iter().map(|&x|x).peekable();
+ /// assert_eq!(it.peek().unwrap(), &100);
+ /// assert_eq!(it.next().unwrap(), 100);
+ /// assert_eq!(it.next().unwrap(), 200);
+ /// assert_eq!(it.peek().unwrap(), &300);
+ /// assert_eq!(it.peek().unwrap(), &300);
+ /// assert_eq!(it.next().unwrap(), 300);
+ /// assert!(it.peek().is_none());
+ /// assert!(it.next().is_none());
+ /// ~~~
+ fn peekable(self) -> Peekable<A, Self> {
+ Peekable{iter: self, peeked: None}
+ }
/// 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)
+ /// .inspect(|&x| debug!("filtering %u", x))
/// .filter(|&x| x % 2 == 0)
- /// .peek_(|&x| debug!("%u made it through", x))
+ /// .inspect(|&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 inspect<'r>(self, f: &'r fn(&A)) -> Inspect<'r, A, Self> {
+ Inspect{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));
}
}
+/// An iterator with a `peek()` that returns an optional reference to the next element.
+pub struct Peekable<A, T> {
+ priv iter: T,
+ priv peeked: Option<A>,
+}
+
+impl<A, T: Iterator<A>> Iterator<A> for Peekable<A, T> {
+ #[inline]
+ fn next(&mut self) -> Option<A> {
+ if self.peeked.is_some() { self.peeked.take() }
+ else { self.iter.next() }
+ }
+}
+
+impl<'self, A, T: Iterator<A>> Peekable<A, T> {
+ /// Return a reference to the next element of the iterator with out advancing it,
+ /// or None if the iterator is exhausted.
+ #[inline]
+ pub fn peek(&'self mut self) -> Option<&'self A> {
+ match self.peeked {
+ Some(ref value) => Some(value),
+ None => {
+ self.peeked = self.iter.next();
+ match self.peeked {
+ Some(ref value) => Some(value),
+ None => None,
+ }
+ },
+ }
+ }
+}
+
/// An iterator which rejects elements while `predicate` is true
pub struct SkipWhile<'self, A, T> {
priv iter: T,
/// An iterator that calls a function with a reference to each
/// element before yielding it.
-pub struct Peek<'self, A, T> {
+pub struct Inspect<'self, A, T> {
priv iter: T,
priv f: &'self fn(&A)
}
-impl<'self, A, T> Peek<'self, A, T> {
+impl<'self, A, T> Inspect<'self, A, T> {
#[inline]
- fn do_peek(&self, elt: Option<A>) -> Option<A> {
+ fn do_inspect(&self, elt: Option<A>) -> Option<A> {
match elt {
Some(ref a) => (self.f)(a),
None => ()
}
}
-impl<'self, A, T: Iterator<A>> Iterator<A> for Peek<'self, A, T> {
+impl<'self, A, T: Iterator<A>> Iterator<A> for Inspect<'self, A, T> {
#[inline]
fn next(&mut self) -> Option<A> {
let next = self.iter.next();
- self.do_peek(next)
+ self.do_inspect(next)
}
#[inline]
}
}
-impl<'self, A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for Peek<'self, A, T> {
+impl<'self, A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A>
+for Inspect<'self, A, T> {
#[inline]
fn next_back(&mut self) -> Option<A> {
let next = self.iter.next_back();
- self.do_peek(next)
+ self.do_inspect(next)
}
}
-impl<'self, A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Peek<'self, A, T> {
+impl<'self, A, T: RandomAccessIterator<A>> RandomAccessIterator<A>
+for Inspect<'self, A, T> {
#[inline]
fn indexable(&self) -> uint {
self.iter.indexable()
#[inline]
fn idx(&self, index: uint) -> Option<A> {
- self.do_peek(self.iter.idx(index))
+ self.do_inspect(self.iter.idx(index))
}
}
fn idx(&self, _: uint) -> Option<A> { Some(self.element.clone()) }
}
+/// Functions for lexicographical ordering of sequences.
+///
+/// Lexicographical ordering through `<`, `<=`, `>=`, `>` requires
+/// that the elements implement both `Eq` and `Ord`.
+///
+/// If two sequences are equal up until the point where one ends,
+/// the shorter sequence compares less.
+pub mod order {
+ use cmp;
+ use cmp::{TotalEq, TotalOrd, Ord, Eq};
+ use option::{Some, None};
+ use super::Iterator;
+
+ /// Compare `a` and `b` for equality using `TotalOrd`
+ pub fn equals<A: TotalEq, T: Iterator<A>>(mut a: T, mut b: T) -> bool {
+ loop {
+ match (a.next(), b.next()) {
+ (None, None) => return true,
+ (None, _) | (_, None) => return false,
+ (Some(x), Some(y)) => if !x.equals(&y) { return false },
+ }
+ }
+ }
+
+ /// Order `a` and `b` lexicographically using `TotalOrd`
+ pub fn cmp<A: TotalOrd, T: Iterator<A>>(mut a: T, mut b: T) -> cmp::Ordering {
+ loop {
+ match (a.next(), b.next()) {
+ (None, None) => return cmp::Equal,
+ (None, _ ) => return cmp::Less,
+ (_ , None) => return cmp::Greater,
+ (Some(x), Some(y)) => match x.cmp(&y) {
+ cmp::Equal => (),
+ non_eq => return non_eq,
+ },
+ }
+ }
+ }
+
+ /// Compare `a` and `b` for equality (Using partial equality, `Eq`)
+ pub fn eq<A: Eq, T: Iterator<A>>(mut a: T, mut b: T) -> bool {
+ loop {
+ match (a.next(), b.next()) {
+ (None, None) => return true,
+ (None, _) | (_, None) => return false,
+ (Some(x), Some(y)) => if !x.eq(&y) { return false },
+ }
+ }
+ }
+
+ /// Compare `a` and `b` for nonequality (Using partial equality, `Eq`)
+ pub fn ne<A: Eq, T: Iterator<A>>(mut a: T, mut b: T) -> bool {
+ loop {
+ match (a.next(), b.next()) {
+ (None, None) => return false,
+ (None, _) | (_, None) => return true,
+ (Some(x), Some(y)) => if x.ne(&y) { return true },
+ }
+ }
+ }
+
+ /// Return `a` < `b` lexicographically (Using partial order, `Ord`)
+ pub fn lt<A: Eq + Ord, T: Iterator<A>>(mut a: T, mut b: T) -> bool {
+ loop {
+ match (a.next(), b.next()) {
+ (None, None) => return false,
+ (None, _ ) => return true,
+ (_ , None) => return false,
+ (Some(x), Some(y)) => if x.ne(&y) { return x.lt(&y) },
+ }
+ }
+ }
+
+ /// Return `a` <= `b` lexicographically (Using partial order, `Ord`)
+ pub fn le<A: Eq + Ord, T: Iterator<A>>(mut a: T, mut b: T) -> bool {
+ loop {
+ match (a.next(), b.next()) {
+ (None, None) => return true,
+ (None, _ ) => return true,
+ (_ , None) => return false,
+ (Some(x), Some(y)) => if x.ne(&y) { return x.le(&y) },
+ }
+ }
+ }
+
+ /// Return `a` > `b` lexicographically (Using partial order, `Ord`)
+ pub fn gt<A: Eq + Ord, T: Iterator<A>>(mut a: T, mut b: T) -> bool {
+ loop {
+ match (a.next(), b.next()) {
+ (None, None) => return false,
+ (None, _ ) => return false,
+ (_ , None) => return true,
+ (Some(x), Some(y)) => if x.ne(&y) { return x.gt(&y) },
+ }
+ }
+ }
+
+ /// Return `a` >= `b` lexicographically (Using partial order, `Ord`)
+ pub fn ge<A: Eq + Ord, T: Iterator<A>>(mut a: T, mut b: T) -> bool {
+ loop {
+ match (a.next(), b.next()) {
+ (None, None) => return true,
+ (None, _ ) => return false,
+ (_ , None) => return true,
+ (Some(x), Some(y)) => if x.ne(&y) { return x.ge(&y) },
+ }
+ }
+ }
+
+ #[test]
+ fn test_lt() {
+ use vec::ImmutableVector;
+
+ let empty: [int, ..0] = [];
+ let xs = [1,2,3];
+ let ys = [1,2,0];
+
+ assert!(!lt(xs.iter(), ys.iter()));
+ assert!(!le(xs.iter(), ys.iter()));
+ assert!( gt(xs.iter(), ys.iter()));
+ assert!( ge(xs.iter(), ys.iter()));
+
+ assert!( lt(ys.iter(), xs.iter()));
+ assert!( le(ys.iter(), xs.iter()));
+ assert!(!gt(ys.iter(), xs.iter()));
+ assert!(!ge(ys.iter(), xs.iter()));
+
+ assert!( lt(empty.iter(), xs.iter()));
+ assert!( le(empty.iter(), xs.iter()));
+ assert!(!gt(empty.iter(), xs.iter()));
+ assert!(!ge(empty.iter(), xs.iter()));
+
+ // Sequence with NaN
+ let u = [1.0, 2.0];
+ let v = [0.0/0.0, 3.0];
+
+ assert!(!lt(u.iter(), v.iter()));
+ assert!(!le(u.iter(), v.iter()));
+ assert!(!gt(u.iter(), v.iter()));
+ assert!(!ge(u.iter(), v.iter()));
+
+ let a = [0.0/0.0];
+ let b = [1.0];
+ let c = [2.0];
+
+ assert!(lt(a.iter(), b.iter()) == (a[0] < b[0]));
+ assert!(le(a.iter(), b.iter()) == (a[0] <= b[0]));
+ assert!(gt(a.iter(), b.iter()) == (a[0] > b[0]));
+ assert!(ge(a.iter(), b.iter()) == (a[0] >= b[0]));
+
+ assert!(lt(c.iter(), b.iter()) == (c[0] < b[0]));
+ assert!(le(c.iter(), b.iter()) == (c[0] <= b[0]));
+ assert!(gt(c.iter(), b.iter()) == (c[0] > b[0]));
+ assert!(ge(c.iter(), b.iter()) == (c[0] >= b[0]));
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
#[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]);
}
}
}
+ #[test]
+ fn test_iterator_peekable() {
+ let xs = ~[0u, 1, 2, 3, 4, 5];
+ let mut it = xs.iter().map(|&x|x).peekable();
+ assert_eq!(it.peek().unwrap(), &0);
+ assert_eq!(it.next().unwrap(), 0);
+ assert_eq!(it.next().unwrap(), 1);
+ assert_eq!(it.next().unwrap(), 2);
+ assert_eq!(it.peek().unwrap(), &3);
+ assert_eq!(it.peek().unwrap(), &3);
+ assert_eq!(it.next().unwrap(), 3);
+ assert_eq!(it.next().unwrap(), 4);
+ assert_eq!(it.peek().unwrap(), &5);
+ assert_eq!(it.next().unwrap(), 5);
+ assert!(it.peek().is_none());
+ assert!(it.next().is_none());
+ }
+
#[test]
fn test_iterator_take_while() {
let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19];
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]);
}
#[test]
- fn test_peek() {
+ fn test_inspect() {
let xs = [1u, 2, 3, 4];
let mut n = 0;
let ys = xs.iter()
- .transform(|&x| x)
- .peek_(|_| n += 1)
+ .map(|&x| x)
+ .inspect(|_| 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]
}
#[test]
- fn test_random_access_peek() {
+ fn test_random_access_inspect() {
let xs = [1, 2, 3, 4, 5];
- // test .transform and .peek_ that don't implement Clone
- let it = xs.iter().peek_(|_| {});
+ // test .map and .inspect that don't implement Clone
+ let it = xs.iter().inspect(|_| {});
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);
+ 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);
- }
-}
#[cfg(not(test))]
impl Zero for () {
+ #[inline]
fn zero() -> () { () }
+ #[inline]
fn is_zero(&self) -> bool { true }
}
use cmp::{Eq, ApproxEq, Ord};
use ops::{Add, Sub, Mul, Div, Rem, Neg};
use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr};
-use option::Option;
+use option::{Option, Some, None};
+#[cfg(not(stage0))]
+use unstable::intrinsics;
pub mod strconv;
impl Saturating for u32 {}
impl Saturating for u64 {}
+pub trait CheckedAdd: Add<Self, Self> {
+ fn checked_add(&self, v: &Self) -> Option<Self>;
+}
+
+#[cfg(not(stage0))]
+impl CheckedAdd for i8 {
+ #[inline]
+ fn checked_add(&self, v: &i8) -> Option<i8> {
+ unsafe {
+ let (x, y) = intrinsics::i8_add_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedAdd for i16 {
+ #[inline]
+ fn checked_add(&self, v: &i16) -> Option<i16> {
+ unsafe {
+ let (x, y) = intrinsics::i16_add_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedAdd for i32 {
+ #[inline]
+ fn checked_add(&self, v: &i32) -> Option<i32> {
+ unsafe {
+ let (x, y) = intrinsics::i32_add_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedAdd for i64 {
+ #[inline]
+ fn checked_add(&self, v: &i64) -> Option<i64> {
+ unsafe {
+ let (x, y) = intrinsics::i64_add_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0), target_word_size = "32")]
+impl CheckedAdd for int {
+ #[inline]
+ fn checked_add(&self, v: &int) -> Option<int> {
+ unsafe {
+ let (x, y) = intrinsics::i32_add_with_overflow(*self as i32, *v as i32);
+ if y { None } else { Some(x as int) }
+ }
+ }
+}
+
+#[cfg(not(stage0), target_word_size = "64")]
+impl CheckedAdd for int {
+ #[inline]
+ fn checked_add(&self, v: &int) -> Option<int> {
+ unsafe {
+ let (x, y) = intrinsics::i64_add_with_overflow(*self as i64, *v as i64);
+ if y { None } else { Some(x as int) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedAdd for u8 {
+ #[inline]
+ fn checked_add(&self, v: &u8) -> Option<u8> {
+ unsafe {
+ let (x, y) = intrinsics::u8_add_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedAdd for u16 {
+ #[inline]
+ fn checked_add(&self, v: &u16) -> Option<u16> {
+ unsafe {
+ let (x, y) = intrinsics::u16_add_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedAdd for u32 {
+ #[inline]
+ fn checked_add(&self, v: &u32) -> Option<u32> {
+ unsafe {
+ let (x, y) = intrinsics::u32_add_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedAdd for u64 {
+ #[inline]
+ fn checked_add(&self, v: &u64) -> Option<u64> {
+ unsafe {
+ let (x, y) = intrinsics::u64_add_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0), target_word_size = "32")]
+impl CheckedAdd for uint {
+ #[inline]
+ fn checked_add(&self, v: &uint) -> Option<uint> {
+ unsafe {
+ let (x, y) = intrinsics::u32_add_with_overflow(*self as u32, *v as u32);
+ if y { None } else { Some(x as uint) }
+ }
+ }
+}
+
+#[cfg(not(stage0), target_word_size = "64")]
+impl CheckedAdd for uint {
+ #[inline]
+ fn checked_add(&self, v: &uint) -> Option<uint> {
+ unsafe {
+ let (x, y) = intrinsics::u64_add_with_overflow(*self as u64, *v as u64);
+ if y { None } else { Some(x as uint) }
+ }
+ }
+}
+
+pub trait CheckedSub: Sub<Self, Self> {
+ fn checked_sub(&self, v: &Self) -> Option<Self>;
+}
+
+#[cfg(not(stage0))]
+impl CheckedSub for i8 {
+ #[inline]
+ fn checked_sub(&self, v: &i8) -> Option<i8> {
+ unsafe {
+ let (x, y) = intrinsics::i8_sub_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedSub for i16 {
+ #[inline]
+ fn checked_sub(&self, v: &i16) -> Option<i16> {
+ unsafe {
+ let (x, y) = intrinsics::i16_sub_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedSub for i32 {
+ #[inline]
+ fn checked_sub(&self, v: &i32) -> Option<i32> {
+ unsafe {
+ let (x, y) = intrinsics::i32_sub_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedSub for i64 {
+ #[inline]
+ fn checked_sub(&self, v: &i64) -> Option<i64> {
+ unsafe {
+ let (x, y) = intrinsics::i64_sub_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0), target_word_size = "32")]
+impl CheckedSub for int {
+ #[inline]
+ fn checked_sub(&self, v: &int) -> Option<int> {
+ unsafe {
+ let (x, y) = intrinsics::i32_sub_with_overflow(*self as i32, *v as i32);
+ if y { None } else { Some(x as int) }
+ }
+ }
+}
+
+#[cfg(not(stage0), target_word_size = "64")]
+impl CheckedSub for int {
+ #[inline]
+ fn checked_sub(&self, v: &int) -> Option<int> {
+ unsafe {
+ let (x, y) = intrinsics::i64_sub_with_overflow(*self as i64, *v as i64);
+ if y { None } else { Some(x as int) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedSub for u8 {
+ #[inline]
+ fn checked_sub(&self, v: &u8) -> Option<u8> {
+ unsafe {
+ let (x, y) = intrinsics::u8_sub_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedSub for u16 {
+ #[inline]
+ fn checked_sub(&self, v: &u16) -> Option<u16> {
+ unsafe {
+ let (x, y) = intrinsics::u16_sub_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedSub for u32 {
+ #[inline]
+ fn checked_sub(&self, v: &u32) -> Option<u32> {
+ unsafe {
+ let (x, y) = intrinsics::u32_sub_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedSub for u64 {
+ #[inline]
+ fn checked_sub(&self, v: &u64) -> Option<u64> {
+ unsafe {
+ let (x, y) = intrinsics::u64_sub_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0), target_word_size = "32")]
+impl CheckedSub for uint {
+ #[inline]
+ fn checked_sub(&self, v: &uint) -> Option<uint> {
+ unsafe {
+ let (x, y) = intrinsics::u32_sub_with_overflow(*self as u32, *v as u32);
+ if y { None } else { Some(x as uint) }
+ }
+ }
+}
+
+#[cfg(not(stage0), target_word_size = "64")]
+impl CheckedSub for uint {
+ #[inline]
+ fn checked_sub(&self, v: &uint) -> Option<uint> {
+ unsafe {
+ let (x, y) = intrinsics::u64_sub_with_overflow(*self as u64, *v as u64);
+ if y { None } else { Some(x as uint) }
+ }
+ }
+}
+
+pub trait CheckedMul: Mul<Self, Self> {
+ fn checked_mul(&self, v: &Self) -> Option<Self>;
+}
+
+#[cfg(not(stage0))]
+impl CheckedMul for i8 {
+ #[inline]
+ fn checked_mul(&self, v: &i8) -> Option<i8> {
+ unsafe {
+ let (x, y) = intrinsics::i8_mul_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedMul for i16 {
+ #[inline]
+ fn checked_mul(&self, v: &i16) -> Option<i16> {
+ unsafe {
+ let (x, y) = intrinsics::i16_mul_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedMul for i32 {
+ #[inline]
+ fn checked_mul(&self, v: &i32) -> Option<i32> {
+ unsafe {
+ let (x, y) = intrinsics::i32_mul_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+// FIXME: #8449: should not be disabled on 32-bit
+#[cfg(not(stage0), target_word_size = "64")]
+impl CheckedMul for i64 {
+ #[inline]
+ fn checked_mul(&self, v: &i64) -> Option<i64> {
+ unsafe {
+ let (x, y) = intrinsics::i64_mul_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0), target_word_size = "32")]
+impl CheckedMul for int {
+ #[inline]
+ fn checked_mul(&self, v: &int) -> Option<int> {
+ unsafe {
+ let (x, y) = intrinsics::i32_mul_with_overflow(*self as i32, *v as i32);
+ if y { None } else { Some(x as int) }
+ }
+ }
+}
+
+#[cfg(not(stage0), target_word_size = "64")]
+impl CheckedMul for int {
+ #[inline]
+ fn checked_mul(&self, v: &int) -> Option<int> {
+ unsafe {
+ let (x, y) = intrinsics::i64_mul_with_overflow(*self as i64, *v as i64);
+ if y { None } else { Some(x as int) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedMul for u8 {
+ #[inline]
+ fn checked_mul(&self, v: &u8) -> Option<u8> {
+ unsafe {
+ let (x, y) = intrinsics::u8_mul_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedMul for u16 {
+ #[inline]
+ fn checked_mul(&self, v: &u16) -> Option<u16> {
+ unsafe {
+ let (x, y) = intrinsics::u16_mul_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0))]
+impl CheckedMul for u32 {
+ #[inline]
+ fn checked_mul(&self, v: &u32) -> Option<u32> {
+ unsafe {
+ let (x, y) = intrinsics::u32_mul_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+// FIXME: #8449: should not be disabled on 32-bit
+#[cfg(not(stage0), target_word_size = "64")]
+impl CheckedMul for u64 {
+ #[inline]
+ fn checked_mul(&self, v: &u64) -> Option<u64> {
+ unsafe {
+ let (x, y) = intrinsics::u64_mul_with_overflow(*self, *v);
+ if y { None } else { Some(x) }
+ }
+ }
+}
+
+#[cfg(not(stage0), target_word_size = "32")]
+impl CheckedMul for uint {
+ #[inline]
+ fn checked_mul(&self, v: &uint) -> Option<uint> {
+ unsafe {
+ let (x, y) = intrinsics::u32_mul_with_overflow(*self as u32, *v as u32);
+ if y { None } else { Some(x as uint) }
+ }
+ }
+}
+
+#[cfg(not(stage0), target_word_size = "64")]
+impl CheckedMul for uint {
+ #[inline]
+ fn checked_mul(&self, v: &uint) -> Option<uint> {
+ unsafe {
+ let (x, y) = intrinsics::u64_mul_with_overflow(*self as u64, *v as u64);
+ if y { None } else { Some(x as uint) }
+ }
+ }
+}
+
/// Helper function for testing numeric operations
#[cfg(test)]
pub fn test_num<T:Num + NumCast>(ten: T, two: T) {
#[cfg(test)]
mod tests {
+ use prelude::*;
+ use uint;
use super::*;
macro_rules! test_cast_20(
assert_eq!(max_value.saturating_sub(-max_value), max_value);
assert_eq!((max_value-2).saturating_sub(-1), max_value-1);
}
+
+ #[test]
+ fn test_checked_add() {
+ let five_less = uint::max_value - 5;
+ assert_eq!(five_less.checked_add(&0), Some(uint::max_value - 5));
+ assert_eq!(five_less.checked_add(&1), Some(uint::max_value - 4));
+ assert_eq!(five_less.checked_add(&2), Some(uint::max_value - 3));
+ assert_eq!(five_less.checked_add(&3), Some(uint::max_value - 2));
+ assert_eq!(five_less.checked_add(&4), Some(uint::max_value - 1));
+ assert_eq!(five_less.checked_add(&5), Some(uint::max_value));
+ assert_eq!(five_less.checked_add(&6), None);
+ assert_eq!(five_less.checked_add(&7), None);
+ }
+
+ #[test]
+ fn test_checked_sub() {
+ assert_eq!(5u.checked_sub(&0), Some(5));
+ assert_eq!(5u.checked_sub(&1), Some(4));
+ assert_eq!(5u.checked_sub(&2), Some(3));
+ assert_eq!(5u.checked_sub(&3), Some(2));
+ assert_eq!(5u.checked_sub(&4), Some(1));
+ assert_eq!(5u.checked_sub(&5), Some(0));
+ assert_eq!(5u.checked_sub(&6), None);
+ assert_eq!(5u.checked_sub(&7), None);
+ }
+
+ #[test]
+ fn test_checked_mul() {
+ let third = uint::max_value / 3;
+ assert_eq!(third.checked_mul(&0), Some(0));
+ assert_eq!(third.checked_mul(&1), Some(third));
+ assert_eq!(third.checked_mul(&2), Some(third * 2));
+ assert_eq!(third.checked_mul(&3), Some(third * 3));
+ assert_eq!(third.checked_mul(&4), None);
+ }
}
use util;
use num::Zero;
use iterator::Iterator;
+use iterator;
use str::{StrSlice, OwnedStr};
use to_str::ToStr;
use clone::DeepClone;
Some(T),
}
-impl<T:Ord> Ord for Option<T> {
+impl<T: Eq + Ord> Ord for Option<T> {
fn lt(&self, other: &Option<T>) -> bool {
- match (self, other) {
- (&None, &None) => false,
- (&None, &Some(_)) => true,
- (&Some(_), &None) => false,
- (&Some(ref a), &Some(ref b)) => *a < *b
- }
+ iterator::order::lt(self.iter(), other.iter())
}
fn le(&self, other: &Option<T>) -> bool {
- match (self, other) {
- (&None, &None) => true,
- (&None, &Some(_)) => true,
- (&Some(_), &None) => false,
- (&Some(ref a), &Some(ref b)) => *a <= *b
- }
+ iterator::order::le(self.iter(), other.iter())
}
fn ge(&self, other: &Option<T>) -> bool {
- !(self < other)
+ iterator::order::ge(self.iter(), other.iter())
}
fn gt(&self, other: &Option<T>) -> bool {
- !(self <= other)
+ iterator::order::gt(self.iter(), other.iter())
}
}
/// 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}
}
assert!(it.next().is_none());
}
+ #[test]
+ fn test_ord() {
+ let small = Some(1.0);
+ let big = Some(5.0);
+ let nan = Some(0.0/0.0);
+ assert!(!(nan < big));
+ assert!(!(nan > big));
+ assert!(small < big);
+ assert!(None < big);
+ assert!(big > None);
+ }
+
#[test]
fn test_mutate() {
let mut x = Some(3i);
#[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::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
pub use num::{Orderable, Signed, Unsigned, Round};
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
pub use num::{Integer, Fractional, Real, RealExt};
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};
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
+pub use tuple::{CloneableTuple1, ImmutableTuple1};
pub use tuple::{CloneableTuple2, CloneableTuple3, CloneableTuple4, CloneableTuple5};
pub use tuple::{CloneableTuple6, CloneableTuple7, CloneableTuple8, CloneableTuple9};
pub use tuple::{CloneableTuple10, CloneableTuple11, CloneableTuple12};
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))]
}
#[inline]
+ #[cfg(stage0)]
pub fn visit_ptr_inner(&self, ptr: *c_void, inner: *TyDesc) -> bool {
unsafe {
let u = ReprVisitor(ptr, self.writer);
}
}
+ #[inline]
+ #[cfg(not(stage0))]
+ pub fn visit_ptr_inner(&self, ptr: *c_void, inner: *TyDesc) -> bool {
+ unsafe {
+ let u = ReprVisitor(ptr, self.writer);
+ let v = reflect::MovePtrAdaptor(u);
+ visit_tydesc(inner, &v as &TyVisitor);
+ true
+ }
+ }
+
#[inline]
pub fn write<T:Repr>(&self) -> bool {
do self.get |v:&T| {
fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
}
+#[cfg(stage0)]
pub fn write_repr<T>(writer: @Writer, object: &T) {
unsafe {
let ptr = ptr::to_unsafe_ptr(object) as *c_void;
}
}
+#[cfg(not(stage0))]
+pub fn write_repr<T>(writer: @Writer, object: &T) {
+ unsafe {
+ let ptr = ptr::to_unsafe_ptr(object) as *c_void;
+ let tydesc = get_tydesc::<T>();
+ let u = ReprVisitor(ptr, writer);
+ let v = reflect::MovePtrAdaptor(u);
+ visit_tydesc(tydesc, &v as &TyVisitor)
+ }
+}
+
#[cfg(test)]
struct P {a: int, b: float}
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;
//! 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>;
};
// 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 iterator::{Iterator, IteratorUtil, range};
+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
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
+ }
}
}
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 {
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);
}
}
}
// 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;
// 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"]
/// Allocates a new string with the specified capacity. The string returned is
/// the empty string, but has capacity for much more.
+#[cfg(stage0)]
#[inline]
pub fn with_capacity(capacity: uint) -> ~str {
let mut buf = ~"";
buf
}
+/// Allocates a new string with the specified capacity. The string returned is
+/// the empty string, but has capacity for much more.
+#[cfg(not(stage0))]
+#[inline]
+pub fn with_capacity(capacity: uint) -> ~str {
+ unsafe {
+ cast::transmute(vec::with_capacity::<~[u8]>(capacity))
+ }
+}
+
/// As char_len but for a slice of a string
///
/// # Arguments
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)
+ }
+
+ #[lang="strdup_uniq"]
+ #[cfg(not(test))]
+ #[allow(missing_doc)]
+ #[inline]
+ pub unsafe fn strdup_uniq(ptr: *u8, len: uint) -> ~str {
+ from_buf_len(ptr, len)
}
- /// 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> 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";
#[cfg(test)]
mod bench {
use extra::test::BenchHarness;
- use str;
+ use super::*;
#[bench]
fn is_utf8_100_ascii(bh: &mut BenchHarness) {
assert_eq!(100, s.len());
do bh.iter {
- str::is_utf8(s);
+ is_utf8(s);
}
}
let s = bytes!("𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰");
assert_eq!(100, s.len());
do bh.iter {
- str::is_utf8(s);
+ is_utf8(s);
}
}
s.map_chars(|c| ((c as uint) + 1) as char);
}
}
+
+ #[bench]
+ fn bench_with_capacity(bh: &mut BenchHarness) {
+ do bh.iter {
+ with_capacity(100);
+ }
+ }
}
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;
// 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")
}
}
}
-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()
}
}
}
$(fn $get_fn(&self) -> $T;)+
}
- impl<$($T:Clone),+> $cloneable_trait<$($T),+> for ($($T),+) {
+ impl<$($T:Clone),+> $cloneable_trait<$($T),+> for ($($T,)+) {
$(
#[inline]
fn $get_fn(&self) -> $T {
$(fn $get_ref_fn<'a>(&'a self) -> &'a $T;)+
}
- impl<$($T),+> $immutable_trait<$($T),+> for ($($T),+) {
+ impl<$($T),+> $immutable_trait<$($T),+> for ($($T,)+) {
$(
#[inline]
fn $get_ref_fn<'a>(&'a self) -> &'a $T {
)+
}
- impl<$($T:Clone),+> Clone for ($($T),+) {
- fn clone(&self) -> ($($T),+) {
- ($(self.$get_ref_fn().clone()),+)
+ impl<$($T:Clone),+> Clone for ($($T,)+) {
+ fn clone(&self) -> ($($T,)+) {
+ ($(self.$get_ref_fn().clone(),)+)
}
}
#[cfg(not(test))]
- impl<$($T:Eq),+> Eq for ($($T),+) {
+ impl<$($T:Eq),+> Eq for ($($T,)+) {
#[inline]
- fn eq(&self, other: &($($T),+)) -> bool {
+ fn eq(&self, other: &($($T,)+)) -> bool {
$(*self.$get_ref_fn() == *other.$get_ref_fn())&&+
}
#[inline]
- fn ne(&self, other: &($($T),+)) -> bool {
- !(*self == *other)
+ fn ne(&self, other: &($($T,)+)) -> bool {
+ $(*self.$get_ref_fn() != *other.$get_ref_fn())||+
}
}
#[cfg(not(test))]
- impl<$($T:TotalEq),+> TotalEq for ($($T),+) {
+ impl<$($T:TotalEq),+> TotalEq for ($($T,)+) {
#[inline]
- fn equals(&self, other: &($($T),+)) -> bool {
+ fn equals(&self, other: &($($T,)+)) -> bool {
$(self.$get_ref_fn().equals(other.$get_ref_fn()))&&+
}
}
#[cfg(not(test))]
- impl<$($T:Ord),+> Ord for ($($T),+) {
+ impl<$($T:Ord + Eq),+> Ord for ($($T,)+) {
#[inline]
- fn lt(&self, other: &($($T),+)) -> bool {
- lexical_lt!($(self.$get_ref_fn(), other.$get_ref_fn()),+)
+ fn lt(&self, other: &($($T,)+)) -> bool {
+ lexical_ord!(lt, $(self.$get_ref_fn(), other.$get_ref_fn()),+)
}
#[inline]
- fn le(&self, other: &($($T),+)) -> bool { !(*other).lt(&(*self)) }
+ fn le(&self, other: &($($T,)+)) -> bool {
+ lexical_ord!(le, $(self.$get_ref_fn(), other.$get_ref_fn()),+)
+ }
#[inline]
- fn ge(&self, other: &($($T),+)) -> bool { !(*self).lt(other) }
+ fn ge(&self, other: &($($T,)+)) -> bool {
+ lexical_ord!(ge, $(self.$get_ref_fn(), other.$get_ref_fn()),+)
+ }
#[inline]
- fn gt(&self, other: &($($T),+)) -> bool { (*other).lt(&(*self)) }
+ fn gt(&self, other: &($($T,)+)) -> bool {
+ lexical_ord!(gt, $(self.$get_ref_fn(), other.$get_ref_fn()),+)
+ }
}
#[cfg(not(test))]
- impl<$($T:TotalOrd),+> TotalOrd for ($($T),+) {
+ impl<$($T:TotalOrd),+> TotalOrd for ($($T,)+) {
#[inline]
- fn cmp(&self, other: &($($T),+)) -> Ordering {
+ fn cmp(&self, other: &($($T,)+)) -> Ordering {
lexical_cmp!($(self.$get_ref_fn(), other.$get_ref_fn()),+)
}
}
#[cfg(not(test))]
- impl<$($T:Zero),+> Zero for ($($T),+) {
+ impl<$($T:Zero),+> Zero for ($($T,)+) {
#[inline]
- fn zero() -> ($($T),+) {
- ($(Zero::zero::<$T>()),+)
+ fn zero() -> ($($T,)+) {
+ ($(Zero::zero::<$T>(),)+)
}
#[inline]
fn is_zero(&self) -> bool {
}
}
-// Constructs an expression that performs a lexical less-than
-// ordering. The values are interleaved, so the macro invocation for
-// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_lt!(a1, b1, a2, b2,
+// Constructs an expression that performs a lexical ordering using method $rel.
+// The values are interleaved, so the macro invocation for
+// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, a1, b1, a2, b2,
// a3, b3)` (and similarly for `lexical_cmp`)
-macro_rules! lexical_lt {
- ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
- if *$a < *$b { true }
- else if !(*$b < *$a) { lexical_lt!($($rest_a, $rest_b),+) }
- else { false }
+macro_rules! lexical_ord {
+ ($rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
+ if *$a != *$b { lexical_ord!($rel, $a, $b) }
+ else { lexical_ord!($rel, $($rest_a, $rest_b),+) }
};
- ($a:expr, $b:expr) => { *$a < *$b };
+ ($rel: ident, $a:expr, $b:expr) => { (*$a) . $rel ($b) };
}
macro_rules! lexical_cmp {
tuple_impls! {
+ (CloneableTuple1, ImmutableTuple1) {
+ (n0, n0_ref) -> A { (ref a,) => a }
+ }
+
(CloneableTuple2, ImmutableTuple2) {
(n0, n0_ref) -> A { (ref a,_) => a }
(n1, n1_ref) -> B { (_,ref b) => b }
fn test_tuple_cmp() {
let (small, big) = ((1u, 2u, 3u), (3u, 2u, 1u));
+ let nan = 0.0/0.0;
+
// Eq
assert_eq!(small, small);
assert_eq!(big, big);
assert!(big >= small);
assert!(big >= big);
+ assert!(!((1.0, 2.0) < (nan, 3.0)));
+ assert!(!((1.0, 2.0) <= (nan, 3.0)));
+ assert!(!((1.0, 2.0) > (nan, 3.0)));
+ assert!(!((1.0, 2.0) >= (nan, 3.0)));
+ assert!(((1.0, 2.0) < (2.0, nan)));
+ assert!(!((2.0, 2.0) < (2.0, nan)));
+
// TotalEq
assert!(small.equals(&small));
assert!(big.equals(&big));
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);
}
pub type GlueFn = extern "Rust" fn(*i8);
-// NB: this has to be kept in sync with the Rust ABI.
+// NB: this has to be kept in sync with `type_desc` in `rt`
#[lang="ty_desc"]
#[cfg(not(test))]
pub struct TyDesc {
+ // sizeof(T)
size: uint,
+
+ // alignof(T)
align: uint,
+
+ // Called on a copy of a value of type `T` *after* memcpy
take_glue: GlueFn,
+
+ // Called when a value of type `T` is no longer needed
drop_glue: GlueFn,
+
+ // Called by drop glue when a value of type `T` can be freed
free_glue: GlueFn,
+
+ // Called by reflection visitor to visit a value of type `T`
visit_glue: GlueFn,
+
+ // If T represents a box pointer (`@U` or `~U`), then
+ // `borrow_offset` is the amount that the pointer must be adjusted
+ // to find the payload. This is always derivable from the type
+ // `U`, but in the case of `@Trait` or `~Trait` objects, the type
+ // `U` is unknown.
+ borrow_offset: uint,
}
#[lang="opaque"]
/// Returns `true` if a type is managed (will be allocated on the local heap)
pub fn contains_managed<T>() -> bool;
+ #[cfg(stage0)]
pub fn visit_tydesc(td: *TyDesc, tv: @TyVisitor);
+ #[cfg(not(stage0))]
+ pub fn visit_tydesc(td: *TyDesc, tv: &TyVisitor);
+
pub fn frame_address(f: &once fn(*u8));
/// Get the address of the `__morestack` stack growth function.
pub fn bswap16(x: i16) -> i16;
pub fn bswap32(x: i32) -> i32;
pub fn bswap64(x: i64) -> i64;
+
+ #[cfg(not(stage0))]
+ pub fn i8_add_with_overflow(x: i8, y: i8) -> (i8, bool);
+ #[cfg(not(stage0))]
+ pub fn i16_add_with_overflow(x: i16, y: i16) -> (i16, bool);
+ #[cfg(not(stage0))]
+ pub fn i32_add_with_overflow(x: i32, y: i32) -> (i32, bool);
+ #[cfg(not(stage0))]
+ pub fn i64_add_with_overflow(x: i64, y: i64) -> (i64, bool);
+
+ #[cfg(not(stage0))]
+ pub fn u8_add_with_overflow(x: u8, y: u8) -> (u8, bool);
+ #[cfg(not(stage0))]
+ pub fn u16_add_with_overflow(x: u16, y: u16) -> (u16, bool);
+ #[cfg(not(stage0))]
+ pub fn u32_add_with_overflow(x: u32, y: u32) -> (u32, bool);
+ #[cfg(not(stage0))]
+ pub fn u64_add_with_overflow(x: u64, y: u64) -> (u64, bool);
+
+ #[cfg(not(stage0))]
+ pub fn i8_sub_with_overflow(x: i8, y: i8) -> (i8, bool);
+ #[cfg(not(stage0))]
+ pub fn i16_sub_with_overflow(x: i16, y: i16) -> (i16, bool);
+ #[cfg(not(stage0))]
+ pub fn i32_sub_with_overflow(x: i32, y: i32) -> (i32, bool);
+ #[cfg(not(stage0))]
+ pub fn i64_sub_with_overflow(x: i64, y: i64) -> (i64, bool);
+
+ #[cfg(not(stage0))]
+ pub fn u8_sub_with_overflow(x: u8, y: u8) -> (u8, bool);
+ #[cfg(not(stage0))]
+ pub fn u16_sub_with_overflow(x: u16, y: u16) -> (u16, bool);
+ #[cfg(not(stage0))]
+ pub fn u32_sub_with_overflow(x: u32, y: u32) -> (u32, bool);
+ #[cfg(not(stage0))]
+ pub fn u64_sub_with_overflow(x: u64, y: u64) -> (u64, bool);
+
+ #[cfg(not(stage0))]
+ pub fn i8_mul_with_overflow(x: i8, y: i8) -> (i8, bool);
+ #[cfg(not(stage0))]
+ pub fn i16_mul_with_overflow(x: i16, y: i16) -> (i16, bool);
+ #[cfg(not(stage0))]
+ pub fn i32_mul_with_overflow(x: i32, y: i32) -> (i32, bool);
+ #[cfg(not(stage0))]
+ pub fn i64_mul_with_overflow(x: i64, y: i64) -> (i64, bool);
+
+ #[cfg(not(stage0))]
+ pub fn u8_mul_with_overflow(x: u8, y: u8) -> (u8, bool);
+ #[cfg(not(stage0))]
+ pub fn u16_mul_with_overflow(x: u16, y: u16) -> (u16, bool);
+ #[cfg(not(stage0))]
+ pub fn u32_mul_with_overflow(x: u32, y: u32) -> (u32, bool);
+ #[cfg(not(stage0))]
+ pub fn u64_mul_with_overflow(x: u64, y: u64) -> (u64, bool);
}
#[cfg(target_endian = "little")] pub fn to_le16(x: i16) -> i16 { x }
//! 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 str;
+use libc::{c_char, c_void, size_t, uintptr_t};
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
borrowck::check_not_borrowed(a, file, line)
}
-#[lang="strdup_uniq"]
-#[inline]
-pub unsafe fn strdup_uniq(ptr: *c_uchar, len: uint) -> ~str {
- str::raw::from_buf_len(ptr, len)
-}
-
#[lang="annihilate"]
pub unsafe fn annihilate() {
::cleanup::annihilate()
pub fn start(main: *u8, argc: int, argv: **c_char,
crate_map: *u8) -> int {
use rt;
- use os;
unsafe {
- let use_old_rt = os::getenv("RUST_OLDRT").is_some();
- if use_old_rt {
- return rust_start(main as *c_void, argc as c_int, argv,
- crate_map as *c_void) as int;
- } else {
- return do rt::start(argc, argv as **u8, crate_map) {
- let main: extern "Rust" fn() = transmute(main);
- main();
- };
- }
- }
-
- extern {
- fn rust_start(main: *c_void, argc: c_int, argv: **c_char,
- crate_map: *c_void) -> c_int;
+ return do rt::start(argc, argv as **u8, crate_map) {
+ let main: extern "Rust" fn() = transmute(main);
+ main();
+ };
}
}
// 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);
#[cfg(not(test))]
pub mod traits {
- use super::Vector;
+ use super::*;
use clone::Clone;
- use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Equal, Equiv};
+ use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Equiv};
+ use iterator::order;
use ops::Add;
- use option::{Some, None};
impl<'self,T:Eq> Eq for &'self [T] {
fn eq(&self, other: & &'self [T]) -> bool {
self.len() == other.len() &&
- self.iter().zip(other.iter()).all(|(s,o)| *s == *o)
+ order::eq(self.iter(), other.iter())
+ }
+ fn ne(&self, other: & &'self [T]) -> bool {
+ self.len() != other.len() ||
+ order::ne(self.iter(), other.iter())
}
- #[inline]
- fn ne(&self, other: & &'self [T]) -> bool { !self.eq(other) }
}
impl<T:Eq> Eq for ~[T] {
impl<'self,T:TotalEq> TotalEq for &'self [T] {
fn equals(&self, other: & &'self [T]) -> bool {
self.len() == other.len() &&
- self.iter().zip(other.iter()).all(|(s,o)| s.equals(o))
+ order::equals(self.iter(), other.iter())
}
}
impl<'self,T:TotalOrd> TotalOrd for &'self [T] {
fn cmp(&self, other: & &'self [T]) -> Ordering {
- for (s,o) in self.iter().zip(other.iter()) {
- match s.cmp(o) {
- Equal => {},
- non_eq => { return non_eq; }
- }
- }
- self.len().cmp(&other.len())
+ order::cmp(self.iter(), other.iter())
}
}
fn cmp(&self, other: &@[T]) -> Ordering { self.as_slice().cmp(&other.as_slice()) }
}
- impl<'self,T:Ord> Ord for &'self [T] {
+ impl<'self, T: Eq + Ord> Ord for &'self [T] {
fn lt(&self, other: & &'self [T]) -> bool {
- for (s,o) in self.iter().zip(other.iter()) {
- if *s < *o { return true; }
- if *s > *o { return false; }
- }
- self.len() < other.len()
+ order::lt(self.iter(), other.iter())
}
#[inline]
- fn le(&self, other: & &'self [T]) -> bool { !(*other < *self) }
+ fn le(&self, other: & &'self [T]) -> bool {
+ order::le(self.iter(), other.iter())
+ }
#[inline]
- fn ge(&self, other: & &'self [T]) -> bool { !(*self < *other) }
+ fn ge(&self, other: & &'self [T]) -> bool {
+ order::ge(self.iter(), other.iter())
+ }
#[inline]
- fn gt(&self, other: & &'self [T]) -> bool { *other < *self }
+ fn gt(&self, other: & &'self [T]) -> bool {
+ order::gt(self.iter(), other.iter())
+ }
}
- impl<T:Ord> Ord for ~[T] {
+ impl<T: Eq + Ord> Ord for ~[T] {
#[inline]
fn lt(&self, other: &~[T]) -> bool { self.as_slice() < other.as_slice() }
#[inline]
fn gt(&self, other: &~[T]) -> bool { self.as_slice() > other.as_slice() }
}
- impl<T:Ord> Ord for @[T] {
+ impl<T: Eq + Ord> Ord for @[T] {
#[inline]
fn lt(&self, other: &@[T]) -> bool { self.as_slice() < other.as_slice() }
#[inline]
impl<'self,T:Clone, V: Vector<T>> Add<V, ~[T]> for &'self [T] {
#[inline]
fn add(&self, rhs: &V) -> ~[T] {
- let mut res = self.to_owned();
+ let mut res = with_capacity(self.len() + rhs.as_slice().len());
+ res.push_all(*self);
res.push_all(rhs.as_slice());
res
}
}
+
impl<T:Clone, V: Vector<T>> Add<V, ~[T]> for ~[T] {
#[inline]
fn add(&self, rhs: &V) -> ~[T] {
- let mut res = self.to_owned();
- res.push_all(rhs.as_slice());
- res
+ self.as_slice() + rhs.as_slice()
}
}
}
}
/// 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;
}
}
}
}
+
+ #[bench]
+ fn add(b: &mut BenchHarness) {
+ let xs: &[int] = [5, ..10];
+ let ys: &[int] = [5, ..10];
+ do b.iter() {
+ xs + ys;
+ }
+ }
}
#[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 struct Ctx {
map: map,
path: path,
- diag: @span_handler,
+ diag: @mut span_handler,
}
impl Ctx {
}
}
- visit::visit_expr(self as @Visitor<()>, ex, ());
+ visit::visit_expr(self as @mut Visitor<()>, ex, ());
}
fn map_fn(@mut self,
for a in decl.inputs.iter() {
self.map.insert(a.id, node_arg);
}
- visit::visit_fn(self as @Visitor<()>, fk, decl, body, sp, id, ());
+ visit::visit_fn(self as @mut Visitor<()>, fk, decl, body, sp, id, ());
}
fn map_stmt(@mut self, stmt: @stmt) {
self.map.insert(stmt_id(stmt), node_stmt(stmt));
- visit::visit_stmt(self as @Visitor<()>, stmt, ());
+ visit::visit_stmt(self as @mut Visitor<()>, stmt, ());
}
fn map_block(@mut self, b: &Block) {
// clone is FIXME #2543
self.map.insert(b.id, node_block((*b).clone()));
- visit::visit_block(self as @Visitor<()>, b, ());
+ visit::visit_block(self as @mut Visitor<()>, b, ());
}
fn map_pat(@mut self, pat: @pat) {
_ => ()
}
- visit::visit_pat(self as @Visitor<()>, pat, ());
+ visit::visit_pat(self as @mut Visitor<()>, pat, ());
}
}
}
_ => self.path.push(path_name(i.ident))
}
- visit::visit_item(self as @Visitor<()>, i, ());
+ visit::visit_item(self as @mut Visitor<()>, i, ());
self.path.pop();
}
fn visit_pat(@mut self, pat: @pat, _: ()) {
self.map_pat(pat);
- visit::visit_pat(self as @Visitor<()>, pat, ())
+ visit::visit_pat(self as @mut Visitor<()>, pat, ())
}
fn visit_expr(@mut self, expr: @expr, _: ()) {
// XXX: Methods below can become default methods.
fn visit_mod(@mut self, module: &_mod, _: span, _: NodeId, _: ()) {
- visit::visit_mod(self as @Visitor<()>, module, ())
+ visit::visit_mod(self as @mut Visitor<()>, module, ())
}
fn visit_view_item(@mut self, view_item: &view_item, _: ()) {
- visit::visit_view_item(self as @Visitor<()>, view_item, ())
+ visit::visit_view_item(self as @mut Visitor<()>, view_item, ())
}
fn visit_foreign_item(@mut self, foreign_item: @foreign_item, _: ()) {
- visit::visit_foreign_item(self as @Visitor<()>, foreign_item, ())
+ visit::visit_foreign_item(self as @mut Visitor<()>, foreign_item, ())
}
fn visit_local(@mut self, local: @Local, _: ()) {
- visit::visit_local(self as @Visitor<()>, local, ())
+ visit::visit_local(self as @mut Visitor<()>, local, ())
}
fn visit_arm(@mut self, arm: &arm, _: ()) {
- visit::visit_arm(self as @Visitor<()>, arm, ())
+ visit::visit_arm(self as @mut Visitor<()>, arm, ())
}
fn visit_decl(@mut self, decl: @decl, _: ()) {
- visit::visit_decl(self as @Visitor<()>, decl, ())
+ visit::visit_decl(self as @mut Visitor<()>, decl, ())
}
fn visit_expr_post(@mut self, _: @expr, _: ()) {
}
fn visit_ty(@mut self, typ: &Ty, _: ()) {
- visit::visit_ty(self as @Visitor<()>, typ, ())
+ visit::visit_ty(self as @mut Visitor<()>, typ, ())
}
fn visit_generics(@mut self, generics: &Generics, _: ()) {
- visit::visit_generics(self as @Visitor<()>, generics, ())
+ visit::visit_generics(self as @mut Visitor<()>, generics, ())
}
fn visit_fn(@mut self,
span: span,
node_id: NodeId,
_: ()) {
- visit::visit_fn(self as @Visitor<()>,
+ visit::visit_fn(self as @mut Visitor<()>,
function_kind,
function_declaration,
block,
}
fn visit_ty_method(@mut self, ty_method: &TypeMethod, _: ()) {
- visit::visit_ty_method(self as @Visitor<()>, ty_method, ())
+ visit::visit_ty_method(self as @mut Visitor<()>, ty_method, ())
}
fn visit_trait_method(@mut self, trait_method: &trait_method, _: ()) {
- visit::visit_trait_method(self as @Visitor<()>, trait_method, ())
+ visit::visit_trait_method(self as @mut Visitor<()>, trait_method, ())
}
fn visit_struct_def(@mut self,
generics: &Generics,
node_id: NodeId,
_: ()) {
- visit::visit_struct_def(self as @Visitor<()>,
+ visit::visit_struct_def(self as @mut Visitor<()>,
struct_def,
ident,
generics,
}
fn visit_struct_field(@mut self, struct_field: @struct_field, _: ()) {
- visit::visit_struct_field(self as @Visitor<()>, struct_field, ())
+ visit::visit_struct_field(self as @mut Visitor<()>, struct_field, ())
}
}
-pub fn map_crate(diag: @span_handler, c: &Crate) -> map {
+pub fn map_crate(diag: @mut span_handler, c: &Crate) -> map {
let cx = @mut Ctx {
map: @mut HashMap::new(),
path: ~[],
diag: diag,
};
- visit::visit_crate(cx as @Visitor<()>, c, ());
+ visit::visit_crate(cx as @mut Visitor<()>, c, ());
cx.map
}
// Used for items loaded from external crate that are being inlined into this
// crate. The `path` should be the path to the item but should not include
// the item itself.
-pub fn map_decoded_item(diag: @span_handler,
+pub fn map_decoded_item(diag: @mut span_handler,
map: map,
path: path,
ii: &inlined_item) {
}
// visit the item / method contents and add those to the map:
- ii.accept((), cx as @Visitor<()>);
+ ii.accept((), cx as @mut Visitor<()>);
}
pub fn node_id_to_str(map: map, id: NodeId, itr: @ident_interner) -> ~str {
}
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
pub trait inlined_item_utils {
fn ident(&self) -> ident;
fn id(&self) -> ast::NodeId;
- fn accept<E: Clone>(&self, e: E, v: @Visitor<E>);
+ fn accept<E: Clone>(&self, e: E, v: @mut Visitor<E>);
}
impl inlined_item_utils for inlined_item {
}
}
- fn accept<E: Clone>(&self, e: E, v: @Visitor<E>) {
+ fn accept<E: Clone>(&self, e: E, v: @mut Visitor<E>) {
match *self {
ii_item(i) => v.visit_item(i, e),
ii_foreign(i) => v.visit_foreign_item(i, e),
node_id: NodeId,
env: ()) {
(self.visit_callback)(node_id);
- visit::visit_mod(self as @Visitor<()>, module, env)
+ visit::visit_mod(self as @mut Visitor<()>, module, env)
}
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) => {
}
}
}
- visit::visit_view_item(self as @Visitor<()>, view_item, env)
+ visit::visit_view_item(self as @mut Visitor<()>, view_item, env)
}
fn visit_foreign_item(@mut self, foreign_item: @foreign_item, env: ()) {
(self.visit_callback)(foreign_item.id);
- visit::visit_foreign_item(self as @Visitor<()>, foreign_item, env)
+ visit::visit_foreign_item(self as @mut Visitor<()>, foreign_item, env)
}
fn visit_item(@mut self, item: @item, env: ()) {
_ => {}
}
- visit::visit_item(self as @Visitor<()>, item, env);
+ visit::visit_item(self as @mut Visitor<()>, item, env);
self.visited_outermost = false
}
fn visit_local(@mut self, local: @Local, env: ()) {
(self.visit_callback)(local.id);
- visit::visit_local(self as @Visitor<()>, local, env)
+ visit::visit_local(self as @mut Visitor<()>, local, env)
}
fn visit_block(@mut self, block: &Block, env: ()) {
(self.visit_callback)(block.id);
- visit::visit_block(self as @Visitor<()>, block, env)
+ visit::visit_block(self as @mut Visitor<()>, block, env)
}
fn visit_stmt(@mut self, statement: @stmt, env: ()) {
(self.visit_callback)(ast_util::stmt_id(statement));
- visit::visit_stmt(self as @Visitor<()>, statement, env)
+ visit::visit_stmt(self as @mut Visitor<()>, statement, env)
}
// XXX: Default
fn visit_arm(@mut self, arm: &arm, env: ()) {
- visit::visit_arm(self as @Visitor<()>, arm, env)
+ visit::visit_arm(self as @mut Visitor<()>, arm, env)
}
fn visit_pat(@mut self, pattern: @pat, env: ()) {
(self.visit_callback)(pattern.id);
- visit::visit_pat(self as @Visitor<()>, pattern, env)
+ visit::visit_pat(self as @mut Visitor<()>, pattern, env)
}
// XXX: Default
fn visit_decl(@mut self, declaration: @decl, env: ()) {
- visit::visit_decl(self as @Visitor<()>, declaration, env)
+ visit::visit_decl(self as @mut Visitor<()>, declaration, env)
}
fn visit_expr(@mut self, expression: @expr, env: ()) {
}
}
(self.visit_callback)(expression.id);
- visit::visit_expr(self as @Visitor<()>, expression, env)
+ visit::visit_expr(self as @mut Visitor<()>, expression, env)
}
// XXX: Default
ty_path(_, _, id) => (self.visit_callback)(id),
_ => {}
}
- visit::visit_ty(self as @Visitor<()>, typ, env)
+ visit::visit_ty(self as @mut Visitor<()>, typ, env)
}
fn visit_generics(@mut self, generics: &Generics, env: ()) {
self.visit_generics_helper(generics);
- visit::visit_generics(self as @Visitor<()>, generics, env)
+ visit::visit_generics(self as @mut Visitor<()>, generics, env)
}
fn visit_fn(@mut self,
(self.visit_callback)(argument.id)
}
- visit::visit_fn(self as @Visitor<()>,
+ visit::visit_fn(self as @mut Visitor<()>,
function_kind,
function_declaration,
block,
// XXX: Default
fn visit_ty_method(@mut self, type_method: &TypeMethod, env: ()) {
- visit::visit_ty_method(self as @Visitor<()>, type_method, env)
+ visit::visit_ty_method(self as @mut Visitor<()>, type_method, env)
}
// XXX: Default
fn visit_trait_method(@mut self, trait_method: &trait_method, env: ()) {
- visit::visit_trait_method(self as @Visitor<()>, trait_method, env)
+ visit::visit_trait_method(self as @mut Visitor<()>, trait_method, env)
}
// XXX: Default
generics: &Generics,
node_id: NodeId,
env: ()) {
- visit::visit_struct_def(self as @Visitor<()>,
+ visit::visit_struct_def(self as @mut Visitor<()>,
struct_definition,
identifier,
generics,
fn visit_struct_field(@mut self, struct_field: @struct_field, env: ()) {
(self.visit_callback)(struct_field.node.id);
- visit::visit_struct_field(self as @Visitor<()>, struct_field, env)
+ visit::visit_struct_field(self as @mut Visitor<()>, struct_field, env)
}
}
pub fn id_visitor(vfn: @fn(NodeId), pass_through_items: bool)
- -> @Visitor<()> {
- let visitor = @IdVisitor {
+ -> @mut Visitor<()> {
+ let visitor = @mut IdVisitor {
visit_callback: vfn,
pass_through_items: pass_through_items,
visited_outermost: false,
};
- visitor as @Visitor<()>
+ visitor as @mut Visitor<()>
}
pub fn visit_ids_for_inlined_item(item: &inlined_item, vfn: @fn(NodeId)) {
callback: f,
};
let visitor = @mut SimpleVisitorVisitor {
- simple_visitor: data as @SimpleVisitor,
+ simple_visitor: data as @mut SimpleVisitor,
};
- visit::visit_crate(visitor as @Visitor<()>, self, ());
+ visit::visit_crate(visitor as @mut Visitor<()>, self, ());
true
}
}
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 {
no_cfgs || some_cfg_matches
}
-pub fn require_unique_names(diagnostic: @span_handler,
+pub fn require_unique_names(diagnostic: @mut span_handler,
metas: &[@MetaItem]) {
let mut set = HashSet::new();
for meta in metas.iter() {
fn span_note(@mut self, sp: span, msg: &str);
fn span_bug(@mut self, sp: span, msg: &str) -> !;
fn span_unimpl(@mut self, sp: span, msg: &str) -> !;
- fn handler(@mut self) -> @handler;
+ fn handler(@mut self) -> @mut handler;
}
struct HandlerT {
}
struct CodemapT {
- handler: @handler,
+ handler: @mut handler,
cm: @codemap::CodeMap,
}
fn span_unimpl(@mut self, sp: span, msg: &str) -> ! {
self.span_bug(sp, ~"unimplemented " + msg);
}
- fn handler(@mut self) -> @handler {
+ fn handler(@mut self) -> @mut handler {
self.handler
}
}
fmt!("internal compiler error: %s", msg)
}
-pub fn mk_span_handler(handler: @handler, cm: @codemap::CodeMap)
- -> @span_handler {
- @mut CodemapT { handler: handler, cm: cm } as @span_handler
+pub fn mk_span_handler(handler: @mut handler, cm: @codemap::CodeMap)
+ -> @mut span_handler {
+ @mut CodemapT { handler: handler, cm: cm } as @mut span_handler
}
-pub fn mk_handler(emitter: Option<Emitter>) -> @handler {
+pub fn mk_handler(emitter: Option<Emitter>) -> @mut handler {
let emit: Emitter = match emitter {
Some(e) => e,
None => {
}
};
- @mut HandlerT { err_count: 0, emit: emit } as @handler
+ @mut HandlerT { err_count: 0, emit: emit } as @mut handler
}
#[deriving(Eq)]
}
}
-pub fn expect<T:Clone>(diag: @span_handler,
+pub fn expect<T:Clone>(diag: @mut span_handler,
opt: Option<T>,
msg: &fn() -> ~str) -> T {
match opt {
// 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) {
}
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);
}
}
// use the default traversal for non-pat_idents
- _ => visit::visit_pat(self as @Visitor<()>, pattern, ())
+ _ => visit::visit_pat(self as @mut Visitor<()>, pattern, ())
}
}
// XXX: Methods below can become default methods.
fn visit_mod(@mut self, module: &ast::_mod, _: span, _: NodeId, _: ()) {
- visit::visit_mod(self as @Visitor<()>, module, ())
+ visit::visit_mod(self as @mut Visitor<()>, module, ())
}
fn visit_view_item(@mut self, view_item: &ast::view_item, _: ()) {
- visit::visit_view_item(self as @Visitor<()>, view_item, ())
+ visit::visit_view_item(self as @mut Visitor<()>, view_item, ())
}
fn visit_item(@mut self, item: @ast::item, _: ()) {
- visit::visit_item(self as @Visitor<()>, item, ())
+ visit::visit_item(self as @mut Visitor<()>, item, ())
}
fn visit_foreign_item(@mut self,
foreign_item: @ast::foreign_item,
_: ()) {
- visit::visit_foreign_item(self as @Visitor<()>, foreign_item, ())
+ visit::visit_foreign_item(self as @mut Visitor<()>, foreign_item, ())
}
fn visit_local(@mut self, local: @ast::Local, _: ()) {
- visit::visit_local(self as @Visitor<()>, local, ())
+ visit::visit_local(self as @mut Visitor<()>, local, ())
}
fn visit_block(@mut self, block: &ast::Block, _: ()) {
- visit::visit_block(self as @Visitor<()>, block, ())
+ visit::visit_block(self as @mut Visitor<()>, block, ())
}
fn visit_stmt(@mut self, stmt: @ast::stmt, _: ()) {
- visit::visit_stmt(self as @Visitor<()>, stmt, ())
+ visit::visit_stmt(self as @mut Visitor<()>, stmt, ())
}
fn visit_arm(@mut self, arm: &ast::arm, _: ()) {
- visit::visit_arm(self as @Visitor<()>, arm, ())
+ visit::visit_arm(self as @mut Visitor<()>, arm, ())
}
fn visit_decl(@mut self, decl: @ast::decl, _: ()) {
- visit::visit_decl(self as @Visitor<()>, decl, ())
+ visit::visit_decl(self as @mut Visitor<()>, decl, ())
}
fn visit_expr(@mut self, expr: @ast::expr, _: ()) {
- visit::visit_expr(self as @Visitor<()>, expr, ())
+ visit::visit_expr(self as @mut Visitor<()>, expr, ())
}
fn visit_expr_post(@mut self, _: @ast::expr, _: ()) {
}
fn visit_ty(@mut self, typ: &ast::Ty, _: ()) {
- visit::visit_ty(self as @Visitor<()>, typ, ())
+ visit::visit_ty(self as @mut Visitor<()>, typ, ())
}
fn visit_generics(@mut self, generics: &ast::Generics, _: ()) {
- visit::visit_generics(self as @Visitor<()>, generics, ())
+ visit::visit_generics(self as @mut Visitor<()>, generics, ())
}
fn visit_fn(@mut self,
span: span,
node_id: NodeId,
_: ()) {
- visit::visit_fn(self as @Visitor<()>,
+ visit::visit_fn(self as @mut Visitor<()>,
function_kind,
function_declaration,
block,
}
fn visit_ty_method(@mut self, ty_method: &ast::TypeMethod, _: ()) {
- visit::visit_ty_method(self as @Visitor<()>, ty_method, ())
+ visit::visit_ty_method(self as @mut Visitor<()>, ty_method, ())
}
fn visit_trait_method(@mut self,
trait_method: &ast::trait_method,
_: ()) {
- visit::visit_trait_method(self as @Visitor<()>, trait_method, ())
+ visit::visit_trait_method(self as @mut Visitor<()>, trait_method, ())
}
fn visit_struct_def(@mut self,
generics: &ast::Generics,
node_id: NodeId,
_: ()) {
- visit::visit_struct_def(self as @Visitor<()>,
+ visit::visit_struct_def(self as @mut Visitor<()>,
struct_def,
ident,
generics,
fn visit_struct_field(@mut self,
struct_field: @ast::struct_field,
_: ()) {
- visit::visit_struct_field(self as @Visitor<()>, struct_field, ())
+ visit::visit_struct_field(self as @mut Visitor<()>, struct_field, ())
}
}
// return a visitor that extracts the pat_ident paths
// from a given pattern and puts them in a mutable
// array (passed in to the traversal)
-pub fn new_name_finder(idents: @mut ~[ast::ident]) -> @Visitor<()> {
+pub fn new_name_finder(idents: @mut ~[ast::ident]) -> @mut Visitor<()> {
let context = @mut NewNameFinderContext {
ident_accumulator: idents,
};
- context as @Visitor<()>
+ context as @mut Visitor<()>
}
pub fn expand_block(extsbox: @mut SyntaxEnv,
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 () {
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"), ~[
let st = ast::item_static(ty, ast::m_imm, method);
let static_name = self.ecx.ident_of(fmt!("__static_method_%u",
self.method_statics.len()));
- let item = self.ecx.item(sp, static_name, ~[], st);
+ // Flag these statics as `address_insignificant` so LLVM can
+ // merge duplicate globals as much as possible (which we're
+ // generating a whole lot of).
+ let unnamed = self.ecx.meta_word(self.fmtsp, @"address_insignificant");
+ let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
+ let item = self.ecx.item(sp, static_name, ~[unnamed], st);
self.method_statics.push(item);
self.ecx.expr_ident(sp, static_name)
};
let ty = self.ecx.ty(self.fmtsp, ty);
let st = ast::item_static(ty, ast::m_imm, fmt);
let static_name = self.ecx.ident_of("__static_fmtstr");
- let item = self.ecx.item(self.fmtsp, static_name, ~[], st);
+ // see above comment for `address_insignificant` and why we do it
+ let unnamed = self.ecx.meta_word(self.fmtsp, @"address_insignificant");
+ let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
+ let item = self.ecx.item(self.fmtsp, static_name, ~[unnamed], st);
let decl = respan(self.fmtsp, ast::decl_item(item));
lets.push(@respan(self.fmtsp, ast::stmt_decl(@decl, self.ecx.next_id())));
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, ~[
if ty == Unknown {
ty = Known(@"?");
}
+
let argptr = self.ecx.expr_addr_of(sp, self.ecx.expr_ident(sp, ident));
match ty {
Known(tyname) => {
};
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) => {
let tt_rdr = new_tt_reader(cx.parse_sess().span_diagnostic,
None,
tt.to_owned());
- let rdr = tt_rdr as @reader;
+ let rdr = tt_rdr as @mut reader;
let rust_parser = Parser(sess, cfg.clone(), rdr.dup());
if rust_parser.is_keyword(keywords::True) {
use parse::lexer::*; //resolve bug?
use parse::ParseSess;
use parse::parser::Parser;
+use parse::attr::parser_attr;
use parse::token::{Token, EOF, to_str, nonterminal, get_ident_interner, ident_to_str};
use parse::token;
pub fn parse_or_else(
sess: @mut ParseSess,
cfg: ast::CrateConfig,
- rdr: @reader,
+ rdr: @mut reader,
ms: ~[matcher]
) -> HashMap<ident, @named_match> {
match parse(sess, cfg, rdr, ms) {
pub fn parse(
sess: @mut ParseSess,
cfg: ast::CrateConfig,
- rdr: @reader,
+ rdr: @mut reader,
ms: &[matcher]
) -> parse_result {
let mut cur_eis = ~[];
Some(i) => token::nt_item(i),
None => p.fatal("expected an item keyword")
},
- "block" => token::nt_block(p.parse_block()),
+ "block" => token::nt_block(~p.parse_block()),
"stmt" => token::nt_stmt(p.parse_stmt(~[])),
"pat" => token::nt_pat(p.parse_pat()),
"expr" => token::nt_expr(p.parse_expr()),
- "ty" => token::nt_ty(p.parse_ty(false /* no need to disambiguate*/)),
+ "ty" => token::nt_ty(~p.parse_ty(false /* no need to disambiguate*/)),
// this could be handled like a token, since it is one
"ident" => match *p.token {
- token::IDENT(sn,b) => { p.bump(); token::nt_ident(sn,b) }
+ token::IDENT(sn,b) => { p.bump(); token::nt_ident(~sn,b) }
_ => p.fatal(~"expected ident, found "
+ token::to_str(get_ident_interner(), p.token))
},
- "path" => token::nt_path(p.parse_path_with_tps(false)),
+ "path" => token::nt_path(~p.parse_path_with_tps(false)),
+ "attr" => token::nt_attr(@p.parse_attribute(false)),
"tt" => {
*p.quote_depth += 1u; //but in theory, non-quoted tts might be useful
let res = token::nt_tt(@p.parse_token_tree());
arg.clone());
let argument_map = parse_or_else(cx.parse_sess(),
cx.cfg(),
- arg_reader as @reader,
+ arg_reader as @mut reader,
argument_gram);
// Extract the arguments:
s_d,
None,
arg.to_owned()
- ) as @reader;
+ ) as @mut reader;
match parse(cx.parse_sess(), cx.cfg(), arg_rdr, *mtcs) {
success(named_matches) => {
let rhs = match rhses[i] {
rhs);
let p = @Parser(cx.parse_sess(),
cx.cfg(),
- trncbr as @reader);
+ trncbr as @mut reader);
// Let the context choose how to interpret the result.
// Weird, but useful for X-macros.
}
pub struct TtReader {
- sp_diag: @span_handler,
+ sp_diag: @mut span_handler,
// the unzipped tree:
stack: @mut TtFrame,
/* for MBE-style macro transcription */
/** This can do Macro-By-Example transcription. On the other hand, if
* `src` contains no `tt_seq`s and `tt_nonterminal`s, `interp` can (and
* should) be none. */
-pub fn new_tt_reader(sp_diag: @span_handler,
+pub fn new_tt_reader(sp_diag: @mut span_handler,
interp: Option<HashMap<ident,@named_match>>,
src: ~[ast::token_tree])
-> @mut TtReader {
/* sidestep the interpolation tricks for ident because
(a) idents can be in lots of places, so it'd be a pain
(b) we actually can, since it's a token. */
- matched_nonterminal(nt_ident(sn,b)) => {
+ matched_nonterminal(nt_ident(~sn,b)) => {
r.cur_span = sp; r.cur_tok = IDENT(sn,b);
r.stack.idx += 1u;
return ret_val;
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)
}
}
// except according to those terms.
use ast;
-use codemap::spanned;
+use codemap::{spanned, mk_sp};
use codemap::BytePos;
use parse::common::*; //resolve bug?
use parse::token;
use parse::parser::Parser;
+use parse::token::INTERPOLATED;
// a parser that can parse attributes.
pub trait parser_attr {
fn parse_outer_attributes(&self) -> ~[ast::Attribute];
- fn parse_attribute(&self, style: ast::AttrStyle) -> ast::Attribute;
- fn parse_attribute_naked(
- &self,
- style: ast::AttrStyle,
- lo: BytePos
- ) -> ast::Attribute;
+ fn parse_attribute(&self, permit_inner: bool) -> ast::Attribute;
fn parse_inner_attrs_and_next(&self) ->
(~[ast::Attribute], ~[ast::Attribute]);
fn parse_meta_item(&self) -> @ast::MetaItem;
fn parse_outer_attributes(&self) -> ~[ast::Attribute] {
let mut attrs: ~[ast::Attribute] = ~[];
loop {
+ debug!("parse_outer_attributes: self.token=%?",
+ self.token);
match *self.token {
+ token::INTERPOLATED(token::nt_attr(*)) => {
+ attrs.push(self.parse_attribute(false));
+ }
token::POUND => {
if self.look_ahead(1, |t| *t != token::LBRACKET) {
break;
}
- attrs.push(self.parse_attribute(ast::AttrOuter));
+ attrs.push(self.parse_attribute(false));
}
token::DOC_COMMENT(s) => {
let attr = ::attr::mk_sugared_doc_attr(
return attrs;
}
- // matches attribute = # attribute_naked
- fn parse_attribute(&self, style: ast::AttrStyle) -> ast::Attribute {
- let lo = self.span.lo;
- self.expect(&token::POUND);
- return self.parse_attribute_naked(style, lo);
+ // matches attribute = # [ meta_item ]
+ //
+ // if permit_inner is true, then a trailing `;` indicates an inner
+ // attribute
+ fn parse_attribute(&self, permit_inner: bool) -> ast::Attribute {
+ debug!("parse_attributes: permit_inner=%? self.token=%?",
+ permit_inner, self.token);
+ let (span, value) = match *self.token {
+ INTERPOLATED(token::nt_attr(attr)) => {
+ assert!(attr.node.style == ast::AttrOuter);
+ self.bump();
+ (attr.span, attr.node.value)
+ }
+ token::POUND => {
+ let lo = self.span.lo;
+ self.bump();
+ self.expect(&token::LBRACKET);
+ let meta_item = self.parse_meta_item();
+ self.expect(&token::RBRACKET);
+ let hi = self.span.hi;
+ (mk_sp(lo, hi), meta_item)
+ }
+ _ => {
+ self.fatal(fmt!("expected `#` but found `%s`",
+ self.this_token_to_str()));
+ }
+ };
+ let style = if permit_inner && *self.token == token::SEMI {
+ self.bump();
+ ast::AttrInner
+ } else {
+ ast::AttrOuter
+ };
+ return spanned {
+ span: span,
+ node: ast::Attribute_ {
+ style: style,
+ value: value,
+ is_sugared_doc: false
+ }
+ };
}
- // matches attribute_naked = [ meta_item ]
- fn parse_attribute_naked(&self, style: ast::AttrStyle, lo: BytePos) ->
- ast::Attribute {
- self.expect(&token::LBRACKET);
- let meta_item = self.parse_meta_item();
- self.expect(&token::RBRACKET);
- let hi = self.span.hi;
- return spanned(lo, hi, ast::Attribute_ { style: style,
- value: meta_item, is_sugared_doc: false }); }
-
// Parse attributes that appear after the opening of an item, each
// terminated by a semicolon. In addition to a vector of inner attributes,
// this function also returns a vector that may contain the first outer
// matches inner_attrs* outer_attr?
// you can make the 'next' field an Option, but the result is going to be
// more useful as a vector.
- fn parse_inner_attrs_and_next(&self) ->
- (~[ast::Attribute], ~[ast::Attribute]) {
+ fn parse_inner_attrs_and_next(&self)
+ -> (~[ast::Attribute], ~[ast::Attribute]) {
let mut inner_attrs: ~[ast::Attribute] = ~[];
let mut next_outer_attrs: ~[ast::Attribute] = ~[];
loop {
- match *self.token {
- token::POUND => {
- if self.look_ahead(1, |t| *t != token::LBRACKET) {
- // This is an extension
- break;
+ let attr = match *self.token {
+ token::INTERPOLATED(token::nt_attr(*)) => {
+ self.parse_attribute(true)
+ }
+ token::POUND => {
+ if self.look_ahead(1, |t| *t != token::LBRACKET) {
+ // This is an extension
+ break;
+ }
+ self.parse_attribute(true)
}
- let attr = self.parse_attribute(ast::AttrInner);
- if *self.token == token::SEMI {
+ token::DOC_COMMENT(s) => {
self.bump();
- inner_attrs.push(attr);
- } else {
- // It's not really an inner attribute
- let outer_attr =
- spanned(attr.span.lo, attr.span.hi,
- ast::Attribute_ { style: ast::AttrOuter,
- value: attr.node.value,
- is_sugared_doc: false });
- next_outer_attrs.push(outer_attr);
- break;
+ ::attr::mk_sugared_doc_attr(self.id_to_str(s),
+ self.span.lo,
+ self.span.hi)
}
- }
- token::DOC_COMMENT(s) => {
- let attr = ::attr::mk_sugared_doc_attr(
- self.id_to_str(s),
- self.span.lo,
- self.span.hi
- );
- self.bump();
- if attr.node.style == ast::AttrInner {
- inner_attrs.push(attr);
- } else {
- next_outer_attrs.push(attr);
- break;
+ _ => {
+ break;
}
- }
- _ => break
+ };
+ if attr.node.style == ast::AttrInner {
+ inner_attrs.push(attr);
+ } else {
+ next_outer_attrs.push(attr);
+ break;
}
}
(inner_attrs, next_outer_attrs)
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);
while level > 0 {
debug!("=== block comment level %d", level);
if is_eof(rdr) {
- (rdr as @reader).fatal(~"unterminated block comment");
+ (rdr as @mut reader).fatal(~"unterminated block comment");
}
if rdr.curr == '\n' {
trim_whitespace_prefix_and_push_line(&mut lines, curr_line,
// it appears this function is called only from pprust... that's
// probably not a good thing.
pub fn gather_comments_and_literals(span_diagnostic:
- @diagnostic::span_handler,
+ @mut diagnostic::span_handler,
path: @str,
srdr: @io::Reader)
-> (~[cmnt], ~[lit]) {
fn is_eof(@mut self) -> bool;
fn next_token(@mut self) -> TokenAndSpan;
fn fatal(@mut self, ~str) -> !;
- fn span_diag(@mut self) -> @span_handler;
+ fn span_diag(@mut self) -> @mut span_handler;
fn peek(@mut self) -> TokenAndSpan;
- fn dup(@mut self) -> @reader;
+ fn dup(@mut self) -> @mut reader;
}
#[deriving(Clone, Eq)]
}
pub struct StringReader {
- span_diagnostic: @span_handler,
+ span_diagnostic: @mut span_handler,
src: @str,
// The absolute offset within the codemap of the next character to read
pos: BytePos,
peek_span: span
}
-pub fn new_string_reader(span_diagnostic: @span_handler,
+pub fn new_string_reader(span_diagnostic: @mut span_handler,
filemap: @codemap::FileMap)
-> @mut StringReader {
let r = new_low_level_string_reader(span_diagnostic, filemap);
}
/* For comments.rs, which hackily pokes into 'pos' and 'curr' */
-pub fn new_low_level_string_reader(span_diagnostic: @span_handler,
+pub fn new_low_level_string_reader(span_diagnostic: @mut span_handler,
filemap: @codemap::FileMap)
-> @mut StringReader {
// Force the initial reader bump to start on a fresh line
let initial_char = '\n';
let r = @mut StringReader {
- span_diagnostic: span_diagnostic, src: filemap.src,
+ span_diagnostic: span_diagnostic,
+ src: filemap.src,
pos: filemap.start_pos,
last_pos: filemap.start_pos,
col: CharPos(0),
fn fatal(@mut self, m: ~str) -> ! {
self.span_diagnostic.span_fatal(self.peek_span, m)
}
- fn span_diag(@mut self) -> @span_handler { self.span_diagnostic }
+ fn span_diag(@mut self) -> @mut span_handler { self.span_diagnostic }
fn peek(@mut self) -> TokenAndSpan {
// XXX(pcwalton): Bad copy!
TokenAndSpan {
sp: self.peek_span,
}
}
- fn dup(@mut self) -> @reader { dup_string_reader(self) as @reader }
+ fn dup(@mut self) -> @mut reader { dup_string_reader(self) as @mut reader }
}
impl reader for TtReader {
fn is_eof(@mut self) -> bool { self.cur_tok == token::EOF }
- fn next_token(@mut self) -> TokenAndSpan { tt_next_token(self) }
+ fn next_token(@mut self) -> TokenAndSpan {
+ let r = tt_next_token(self);
+ debug!("TtReader: r=%?", r);
+ return r;
+ }
fn fatal(@mut self, m: ~str) -> ! {
self.sp_diag.span_fatal(self.cur_span, m);
}
- fn span_diag(@mut self) -> @span_handler { self.sp_diag }
+ fn span_diag(@mut self) -> @mut span_handler { self.sp_diag }
fn peek(@mut self) -> TokenAndSpan {
TokenAndSpan {
tok: self.cur_tok.clone(),
sp: self.cur_span,
}
}
- fn dup(@mut self) -> @reader { dup_tt_reader(self) as @reader }
+ fn dup(@mut self) -> @mut reader { dup_tt_reader(self) as @mut reader }
}
// EFFECT: advance peek_tok and peek_span to refer to the next token.
pub struct ParseSess {
cm: @codemap::CodeMap, // better be the same as the one in the reader!
next_id: NodeId,
- span_diagnostic: @span_handler, // better be the same as the one in the reader!
+ span_diagnostic: @mut span_handler, // better be the same as the one in the reader!
/// Used to determine and report recursive mod inclusions
included_mod_stack: ~[Path],
}
}
}
-pub fn new_parse_sess_special_handler(sh: @span_handler,
+pub fn new_parse_sess_special_handler(sh: @mut span_handler,
cm: @codemap::CodeMap)
-> @mut ParseSess {
@mut ParseSess {
// parsing tt's probably shouldn't require a parser at all.
let cfg = ~[];
let srdr = lexer::new_string_reader(sess.span_diagnostic, filemap);
- let p1 = Parser(sess, cfg, srdr as @reader);
+ let p1 = Parser(sess, cfg, srdr as @mut reader);
p1.parse_all_token_trees()
}
tts: ~[ast::token_tree],
cfg: ast::CrateConfig) -> Parser {
let trdr = lexer::new_tt_reader(sess.span_diagnostic, None, tts);
- Parser(sess, cfg, trdr as @reader)
+ Parser(sess, cfg, trdr as @mut reader)
}
// abort if necessary
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[macro_escape];
+
use abi;
use abi::AbiSet;
use ast::{Sigil, BorrowedSigil, ManagedSigil, OwnedSigil};
Some($p.mk_expr(
($p).span.lo,
($p).span.hi,
- expr_path(/* bad */ (*pt).clone())))
+ expr_path(/* bad */ (**pt).clone())))
}
_ => None
};
_ => None
};
match __found__ {
- Some(INTERPOLATED(token::$constructor(x))) => {
- return (~[], x.clone())
+ Some(INTERPOLATED(token::$constructor(ref x))) => {
+ return (~[], (**x).clone())
}
_ => {}
}
pub fn Parser(sess: @mut ParseSess,
cfg: ast::CrateConfig,
- rdr: @reader)
+ rdr: @mut reader)
-> Parser {
let tok0 = rdr.next_token();
let interner = get_ident_interner();
token: @mut tok0.tok,
span: @mut span,
last_span: @mut span,
+ last_token: @mut None,
buffer: @mut ([
placeholder.clone(),
placeholder.clone(),
span: @mut span,
// the span of the prior token:
last_span: @mut span,
+ // the previous token or None (only stashed sometimes).
+ last_token: @mut Option<~token::Token>,
buffer: @mut [TokenAndSpan, ..4],
buffer_start: @mut int,
buffer_end: @mut int,
tokens_consumed: @mut uint,
restriction: @mut restriction,
quote_depth: @mut uint, // not (yet) related to the quasiquoter
- reader: @reader,
+ reader: @mut reader,
interner: @token::ident_interner,
/// The set of seen errors about obsolete syntax. Used to suppress
/// extra detail when the same error is seen twice
}
}
+ // Expect next token to be edible or inedible token. If edible,
+ // then consume it; if inedible, then return without consuming
+ // anything. Signal a fatal error if next token is unexpected.
+ pub fn expect_one_of(&self, edible: &[token::Token], inedible: &[token::Token]) {
+ fn tokens_to_str(p:&Parser, tokens: &[token::Token]) -> ~str {
+ let mut i = tokens.iter();
+ // This might be a sign we need a connect method on Iterator.
+ let b = i.next().map_default(~"", |t| p.token_to_str(*t));
+ i.fold(b, |b,a| b + " " + p.token_to_str(a))
+ }
+ if edible.contains(self.token) {
+ self.bump();
+ } else if inedible.contains(self.token) {
+ // leave it in the input
+ } else {
+ let expected = vec::append(edible.to_owned(), inedible);
+ let expect = tokens_to_str(self, expected);
+ let actual = self.this_token_to_str();
+ self.fatal(
+ if expected.len() != 1 {
+ fmt!("expected one of `%s` but found `%s`", expect, actual)
+ } else {
+ fmt!("expected `%s` but found `%s`", expect, actual)
+ }
+ )
+ }
+ }
+
+ // Check for erroneous `ident { }`; if matches, signal error and
+ // recover (without consuming any expected input token). Returns
+ // true if and only if input was consumed for recovery.
+ pub fn check_for_erroneous_unit_struct_expecting(&self, expected: &[token::Token]) -> bool {
+ if *self.token == token::LBRACE
+ && expected.iter().all(|t| *t != token::LBRACE)
+ && self.look_ahead(1, |t| *t == token::RBRACE) {
+ // matched; signal non-fatal error and recover.
+ self.span_err(*self.span,
+ "Unit-like struct construction is written with no trailing `{ }`");
+ self.eat(&token::LBRACE);
+ self.eat(&token::RBRACE);
+ true
+ } else {
+ false
+ }
+ }
+
+ // Commit to parsing a complete expression `e` expected to be
+ // followed by some token from the set edible + inedible. Recover
+ // from anticipated input errors, discarding erroneous characters.
+ pub fn commit_expr(&self, e: @expr, edible: &[token::Token], inedible: &[token::Token]) {
+ debug!("commit_expr %?", e);
+ match e.node {
+ expr_path(*) => {
+ // might be unit-struct construction; check for recoverableinput error.
+ let expected = vec::append(edible.to_owned(), inedible);
+ self.check_for_erroneous_unit_struct_expecting(expected);
+ }
+ _ => {}
+ }
+ self.expect_one_of(edible, inedible)
+ }
+
+ pub fn commit_expr_expecting(&self, e: @expr, edible: token::Token) {
+ self.commit_expr(e, &[edible], &[])
+ }
+
+ // Commit to parsing a complete statement `s`, which expects to be
+ // followed by some token from the set edible + inedible. Check
+ // for recoverable input errors, discarding erroneous characters.
+ pub fn commit_stmt(&self, s: @stmt, edible: &[token::Token], inedible: &[token::Token]) {
+ debug!("commit_stmt %?", s);
+ let _s = s; // unused, but future checks might want to inspect `s`.
+ if self.last_token.map_default(false, |t|is_ident_or_path(*t)) {
+ let expected = vec::append(edible.to_owned(), inedible);
+ self.check_for_erroneous_unit_struct_expecting(expected);
+ }
+ self.expect_one_of(edible, inedible)
+ }
+
+ pub fn commit_stmt_expecting(&self, s: @stmt, edible: token::Token) {
+ self.commit_stmt(s, &[edible], &[])
+ }
+
pub fn parse_ident(&self) -> ast::ident {
self.check_strict_keywords();
self.check_reserved_keywords();
// advance the parser by one token
pub fn bump(&self) {
*self.last_span = *self.span;
+ // Stash token for error recovery (sometimes; clone is not necessarily cheap).
+ *self.last_token = if is_ident_or_path(self.token) {
+ Some(~(*self.token).clone())
+ } else {
+ None
+ };
let next = if *self.buffer_start == *self.buffer_end {
self.reader.next_token()
} else {
// Useless second parameter for compatibility with quasiquote macros.
// Bleh!
pub fn parse_ty(&self, _: bool) -> Ty {
- maybe_whole!(self, nt_ty);
+ maybe_whole!(deref self, nt_ty);
let lo = self.span.lo;
// parse a path that doesn't have type parameters attached
pub fn parse_path_without_tps(&self) -> ast::Path {
- maybe_whole!(self, nt_path);
+ maybe_whole!(deref self, nt_path);
let (ids,is_global,sp) = self.parse_path();
ast::Path { span: sp,
global: is_global,
before_tps: Option<&fn()>) -> ast::Path {
debug!("parse_path_with_tps(colons=%b)", colons);
- maybe_whole!(self, nt_path);
+ maybe_whole!(deref self, nt_path);
let lo = self.span.lo;
let path = self.parse_path_without_tps();
if colons && !self.eat(&token::MOD_SEP) {
return self.mk_expr(lo, hi, expr_lit(lit));
}
let mut es = ~[self.parse_expr()];
+ self.commit_expr(*es.last(), &[], &[token::COMMA, token::RPAREN]);
while *self.token == token::COMMA {
self.bump();
if *self.token != token::RPAREN {
es.push(self.parse_expr());
+ self.commit_expr(*es.last(), &[], &[token::COMMA, token::RPAREN]);
}
else {
trailing_comma = true;
}
}
hi = self.span.hi;
- self.expect(&token::RPAREN);
+ self.commit_expr_expecting(*es.last(), token::RPAREN);
return if es.len() == 1 && !trailing_comma {
self.mk_expr(lo, self.span.hi, expr_paren(es[0]))
break;
}
- self.expect(&token::COMMA);
+ self.commit_expr(fields.last().expr, &[token::COMMA], &[token::RBRACE]);
if self.eat(&token::DOTDOT) {
base = Some(self.parse_expr());
}
hi = pth.span.hi;
- self.expect(&token::RBRACE);
+ self.commit_expr_expecting(fields.last().expr, token::RBRACE);
ex = expr_struct(pth, fields, base);
return self.mk_expr(lo, hi, ex);
}
self.bump();
let ix = self.parse_expr();
hi = ix.span.hi;
- self.expect(&token::RBRACKET);
+ self.commit_expr_expecting(ix, token::RBRACKET);
e = self.mk_expr(lo, hi, self.mk_index(e, ix));
}
fn parse_match_expr(&self) -> @expr {
let lo = self.last_span.lo;
let discriminant = self.parse_expr();
- self.expect(&token::LBRACE);
+ self.commit_expr_expecting(discriminant, token::LBRACE);
let mut arms: ~[arm] = ~[];
while *self.token != token::RBRACE {
let pats = self.parse_pats();
&& *self.token != token::RBRACE;
if require_comma {
- self.expect(&token::COMMA);
+ self.commit_expr(expr, &[token::COMMA], &[token::RBRACE]);
} else {
self.eat(&token::COMMA);
}
// parse a block. No inner attrs are allowed.
pub fn parse_block(&self) -> Block {
- maybe_whole!(self, nt_block);
+ maybe_whole!(deref self, nt_block);
let lo = self.span.lo;
if self.eat_keyword(keywords::Unsafe) {
match stmt.node {
stmt_expr(e, stmt_id) => {
// expression without semicolon
- let has_semi;
+ if classify::stmt_ends_with_semi(stmt) {
+ // Just check for errors and recover; do not eat semicolon yet.
+ self.commit_stmt(stmt, &[], &[token::SEMI, token::RBRACE]);
+ }
+
match *self.token {
token::SEMI => {
- has_semi = true;
+ self.bump();
+ stmts.push(@codemap::spanned {
+ node: stmt_semi(e, stmt_id),
+ span: stmt.span,
+ });
}
token::RBRACE => {
- has_semi = false;
expr = Some(e);
}
- ref t => {
- has_semi = false;
- if classify::stmt_ends_with_semi(stmt) {
- self.fatal(
- fmt!(
- "expected `;` or `}` after \
- expression but found `%s`",
- self.token_to_str(t)
- )
- );
- }
+ _ => {
stmts.push(stmt);
}
}
-
- if has_semi {
- self.bump();
- stmts.push(@codemap::spanned {
- node: stmt_semi(e, stmt_id),
- span: stmt.span,
- });
- }
}
stmt_mac(ref m, _) => {
// statement macro; might be an expr
stmts.push(stmt);
if classify::stmt_ends_with_semi(stmt) {
- self.expect(&token::SEMI);
+ self.commit_stmt_expecting(stmt, token::SEMI);
}
}
}
}
}
if fields.len() == 0 {
- self.fatal(fmt!("Unit-like struct should be written as `struct %s;`",
+ self.fatal(fmt!("Unit-like struct definition should be written as `struct %s;`",
get_ident_interner().get(class_name.name)));
}
self.bump();
let ty = self.parse_ty(false);
self.expect(&token::EQ);
let e = self.parse_expr();
- self.expect(&token::SEMI);
+ self.commit_expr_expecting(e, token::SEMI);
(id, item_static(ty, m, e), None)
}
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(),
attrs: ~[Attribute],
macros_allowed: bool)
-> item_or_view_item {
- maybe_whole!(iovi self, nt_item);
+ match *self.token {
+ INTERPOLATED(token::nt_item(item)) => {
+ self.bump();
+ let new_attrs = vec::append(attrs, item.attrs);
+ return iovi_item(@ast::item {
+ attrs: new_attrs,
+ ..(*item).clone()});
+ }
+ _ => {}
+ }
+
let lo = self.span.lo;
let visibility = self.parse_non_priv_visibility();
} 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");
};
/// For interpolation during macro expansion.
pub enum nonterminal {
nt_item(@ast::item),
- nt_block(ast::Block),
+ nt_block(~ast::Block),
nt_stmt(@ast::stmt),
nt_pat( @ast::pat),
nt_expr(@ast::expr),
- nt_ty( ast::Ty),
- nt_ident(ast::ident, bool),
- nt_path( ast::Path),
+ nt_ty( ~ast::Ty),
+ nt_ident(~ast::ident, bool),
+ nt_attr(@ast::Attribute), // #[foo]
+ nt_path(~ast::Path),
nt_tt( @ast::token_tree), //needs @ed to break a circularity
nt_matchers(~[ast::matcher])
}
INTERPOLATED(ref nt) => {
match nt {
&nt_expr(e) => ::print::pprust::expr_to_str(e, input),
+ &nt_attr(e) => ::print::pprust::attribute_to_str(e, input),
_ => {
~"an interpolated " +
match (*nt) {
nt_block(*) => ~"block",
nt_stmt(*) => ~"statement",
nt_pat(*) => ~"pattern",
+ nt_attr(*) => fail!("should have been handled"),
nt_expr(*) => fail!("should have been handled above"),
nt_ty(*) => ~"type",
nt_ident(*) => ~"identifier",
// copy forward.
pub fn print_crate(cm: @CodeMap,
intr: @ident_interner,
- span_diagnostic: @diagnostic::span_handler,
+ span_diagnostic: @mut diagnostic::span_handler,
crate: &ast::Crate,
filename: @str,
input: @io::Reader,
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));
fn visit_struct_field(@mut self, @struct_field, E);
}
-pub fn visit_crate<E:Clone>(visitor: @Visitor<E>, crate: &Crate, env: E) {
+pub fn visit_crate<E:Clone>(visitor: @mut Visitor<E>, crate: &Crate, env: E) {
visitor.visit_mod(&crate.module, crate.span, CRATE_NODE_ID, env)
}
-pub fn visit_mod<E:Clone>(visitor: @Visitor<E>, module: &_mod, env: E) {
+pub fn visit_mod<E:Clone>(visitor: @mut Visitor<E>, module: &_mod, env: E) {
for view_item in module.view_items.iter() {
visitor.visit_view_item(view_item, env.clone())
}
}
}
-pub fn visit_view_item<E:Clone>(_: @Visitor<E>, _: &view_item, _: E) {
+pub fn visit_view_item<E:Clone>(_: @mut Visitor<E>, _: &view_item, _: E) {
// Empty!
}
-pub fn visit_local<E:Clone>(visitor: @Visitor<E>, local: &Local, env: E) {
+pub fn visit_local<E:Clone>(visitor: @mut Visitor<E>, local: &Local, env: E) {
visitor.visit_pat(local.pat, env.clone());
visitor.visit_ty(&local.ty, env.clone());
match local.init {
}
}
-fn visit_trait_ref<E:Clone>(visitor: @Visitor<E>,
+fn visit_trait_ref<E:Clone>(visitor: @mut Visitor<E>,
trait_ref: &ast::trait_ref,
env: E) {
visit_path(visitor, &trait_ref.path, env)
}
-pub fn visit_item<E:Clone>(visitor: @Visitor<E>, item: &item, env: E) {
+pub fn visit_item<E:Clone>(visitor: @mut Visitor<E>, item: &item, env: E) {
match item.node {
item_static(ref typ, _, expr) => {
visitor.visit_ty(typ, env.clone());
}
}
-pub fn visit_enum_def<E:Clone>(visitor: @Visitor<E>,
+pub fn visit_enum_def<E:Clone>(visitor: @mut Visitor<E>,
enum_definition: &ast::enum_def,
generics: &Generics,
env: E) {
}
}
-pub fn skip_ty<E>(_: @Visitor<E>, _: &Ty, _: E) {
+pub fn skip_ty<E>(_: @mut Visitor<E>, _: &Ty, _: E) {
// Empty!
}
-pub fn visit_ty<E:Clone>(visitor: @Visitor<E>, typ: &Ty, env: E) {
+pub fn visit_ty<E:Clone>(visitor: @mut Visitor<E>, typ: &Ty, env: E) {
match typ.node {
ty_box(ref mutable_type) | ty_uniq(ref mutable_type) |
ty_vec(ref mutable_type) | ty_ptr(ref mutable_type) |
}
}
-pub fn visit_path<E:Clone>(visitor: @Visitor<E>, path: &Path, env: E) {
+pub fn visit_path<E:Clone>(visitor: @mut Visitor<E>, path: &Path, env: E) {
for typ in path.types.iter() {
visitor.visit_ty(typ, env.clone())
}
}
-pub fn visit_pat<E:Clone>(visitor: @Visitor<E>, pattern: &pat, env: E) {
+pub fn visit_pat<E:Clone>(visitor: @mut Visitor<E>, pattern: &pat, env: E) {
match pattern.node {
pat_enum(ref path, ref children) => {
visit_path(visitor, path, env.clone());
}
}
-pub fn visit_foreign_item<E:Clone>(visitor: @Visitor<E>,
+pub fn visit_foreign_item<E:Clone>(visitor: @mut Visitor<E>,
foreign_item: &foreign_item,
env: E) {
match foreign_item.node {
}
}
-pub fn visit_ty_param_bounds<E:Clone>(visitor: @Visitor<E>,
+pub fn visit_ty_param_bounds<E:Clone>(visitor: @mut Visitor<E>,
bounds: &OptVec<TyParamBound>,
env: E) {
for bound in bounds.iter() {
}
}
-pub fn visit_generics<E:Clone>(visitor: @Visitor<E>,
+pub fn visit_generics<E:Clone>(visitor: @mut Visitor<E>,
generics: &Generics,
env: E) {
for type_parameter in generics.ty_params.iter() {
}
}
-pub fn visit_fn_decl<E:Clone>(visitor: @Visitor<E>,
+pub fn visit_fn_decl<E:Clone>(visitor: @mut Visitor<E>,
function_declaration: &fn_decl,
env: E) {
for argument in function_declaration.inputs.iter() {
// visit_fn() and check for fk_method(). I named this visit_method_helper()
// because it is not a default impl of any method, though I doubt that really
// clarifies anything. - Niko
-pub fn visit_method_helper<E:Clone>(visitor: @Visitor<E>,
+pub fn visit_method_helper<E:Clone>(visitor: @mut Visitor<E>,
method: &method,
env: E) {
visitor.visit_fn(&fk_method(method.ident, &method.generics, method),
env)
}
-pub fn visit_fn<E:Clone>(visitor: @Visitor<E>,
+pub fn visit_fn<E:Clone>(visitor: @mut Visitor<E>,
function_kind: &fn_kind,
function_declaration: &fn_decl,
function_body: &Block,
visitor.visit_block(function_body, env)
}
-pub fn visit_ty_method<E:Clone>(visitor: @Visitor<E>,
+pub fn visit_ty_method<E:Clone>(visitor: @mut Visitor<E>,
method_type: &TypeMethod,
env: E) {
for argument_type in method_type.decl.inputs.iter() {
visitor.visit_ty(&method_type.decl.output, env.clone())
}
-pub fn visit_trait_method<E:Clone>(visitor: @Visitor<E>,
+pub fn visit_trait_method<E:Clone>(visitor: @mut Visitor<E>,
trait_method: &trait_method,
env: E) {
match *trait_method {
}
}
-pub fn visit_struct_def<E:Clone>(visitor: @Visitor<E>,
+pub fn visit_struct_def<E:Clone>(visitor: @mut Visitor<E>,
struct_definition: @struct_def,
_: ast::ident,
_: &Generics,
}
}
-pub fn visit_struct_field<E:Clone>(visitor: @Visitor<E>,
+pub fn visit_struct_field<E:Clone>(visitor: @mut Visitor<E>,
struct_field: &struct_field,
env: E) {
visitor.visit_ty(&struct_field.node.ty, env)
}
-pub fn visit_block<E:Clone>(visitor: @Visitor<E>, block: &Block, env: E) {
+pub fn visit_block<E:Clone>(visitor: @mut Visitor<E>, block: &Block, env: E) {
for view_item in block.view_items.iter() {
visitor.visit_view_item(view_item, env.clone())
}
visit_expr_opt(visitor, block.expr, env)
}
-pub fn visit_stmt<E>(visitor: @Visitor<E>, statement: &stmt, env: E) {
+pub fn visit_stmt<E>(visitor: @mut Visitor<E>, statement: &stmt, env: E) {
match statement.node {
stmt_decl(declaration, _) => visitor.visit_decl(declaration, env),
stmt_expr(expression, _) | stmt_semi(expression, _) => {
}
}
-pub fn visit_decl<E:Clone>(visitor: @Visitor<E>, declaration: &decl, env: E) {
+pub fn visit_decl<E:Clone>(visitor: @mut Visitor<E>, declaration: &decl, env: E) {
match declaration.node {
decl_local(ref local) => visitor.visit_local(*local, env),
decl_item(item) => visitor.visit_item(item, env),
}
}
-pub fn visit_expr_opt<E>(visitor: @Visitor<E>,
+pub fn visit_expr_opt<E>(visitor: @mut Visitor<E>,
optional_expression: Option<@expr>,
env: E) {
match optional_expression {
}
}
-pub fn visit_exprs<E:Clone>(visitor: @Visitor<E>,
+pub fn visit_exprs<E:Clone>(visitor: @mut Visitor<E>,
expressions: &[@expr],
env: E) {
for expression in expressions.iter() {
}
}
-pub fn visit_mac<E>(_: @Visitor<E>, _: &mac, _: E) {
+pub fn visit_mac<E>(_: @mut Visitor<E>, _: &mac, _: E) {
// Empty!
}
-pub fn visit_expr<E:Clone>(visitor: @Visitor<E>, expression: @expr, env: E) {
+pub fn visit_expr<E:Clone>(visitor: @mut Visitor<E>, expression: @expr, env: E) {
match expression.node {
expr_vstore(subexpression, _) => {
visitor.visit_expr(subexpression, env.clone())
visitor.visit_expr_post(expression, env.clone())
}
-pub fn visit_arm<E:Clone>(visitor: @Visitor<E>, arm: &arm, env: E) {
+pub fn visit_arm<E:Clone>(visitor: @mut Visitor<E>, arm: &arm, env: E) {
for pattern in arm.pats.iter() {
visitor.visit_pat(*pattern, env.clone())
}
}
pub struct SimpleVisitorVisitor {
- simple_visitor: @SimpleVisitor,
+ simple_visitor: @mut SimpleVisitor,
}
impl Visitor<()> for SimpleVisitorVisitor {
node_id: NodeId,
env: ()) {
self.simple_visitor.visit_mod(module, span, node_id);
- visit_mod(self as @Visitor<()>, module, env)
+ visit_mod(self as @mut Visitor<()>, module, env)
}
fn visit_view_item(@mut self, view_item: &view_item, env: ()) {
self.simple_visitor.visit_view_item(view_item);
- visit_view_item(self as @Visitor<()>, view_item, env)
+ visit_view_item(self as @mut Visitor<()>, view_item, env)
}
fn visit_foreign_item(@mut self, foreign_item: @foreign_item, env: ()) {
self.simple_visitor.visit_foreign_item(foreign_item);
- visit_foreign_item(self as @Visitor<()>, foreign_item, env)
+ visit_foreign_item(self as @mut Visitor<()>, foreign_item, env)
}
fn visit_item(@mut self, item: @item, env: ()) {
self.simple_visitor.visit_item(item);
- visit_item(self as @Visitor<()>, item, env)
+ visit_item(self as @mut Visitor<()>, item, env)
}
fn visit_local(@mut self, local: @Local, env: ()) {
self.simple_visitor.visit_local(local);
- visit_local(self as @Visitor<()>, local, env)
+ visit_local(self as @mut Visitor<()>, local, env)
}
fn visit_block(@mut self, block: &Block, env: ()) {
self.simple_visitor.visit_block(block);
- visit_block(self as @Visitor<()>, block, env)
+ visit_block(self as @mut Visitor<()>, block, env)
}
fn visit_stmt(@mut self, statement: @stmt, env: ()) {
self.simple_visitor.visit_stmt(statement);
- visit_stmt(self as @Visitor<()>, statement, env)
+ visit_stmt(self as @mut Visitor<()>, statement, env)
}
fn visit_arm(@mut self, arm: &arm, env: ()) {
self.simple_visitor.visit_arm(arm);
- visit_arm(self as @Visitor<()>, arm, env)
+ visit_arm(self as @mut Visitor<()>, arm, env)
}
fn visit_pat(@mut self, pattern: @pat, env: ()) {
self.simple_visitor.visit_pat(pattern);
- visit_pat(self as @Visitor<()>, pattern, env)
+ visit_pat(self as @mut Visitor<()>, pattern, env)
}
fn visit_decl(@mut self, declaration: @decl, env: ()) {
self.simple_visitor.visit_decl(declaration);
- visit_decl(self as @Visitor<()>, declaration, env)
+ visit_decl(self as @mut Visitor<()>, declaration, env)
}
fn visit_expr(@mut self, expression: @expr, env: ()) {
self.simple_visitor.visit_expr(expression);
- visit_expr(self as @Visitor<()>, expression, env)
+ visit_expr(self as @mut Visitor<()>, expression, env)
}
fn visit_expr_post(@mut self, expression: @expr, _: ()) {
self.simple_visitor.visit_expr_post(expression)
}
fn visit_ty(@mut self, typ: &Ty, env: ()) {
self.simple_visitor.visit_ty(typ);
- visit_ty(self as @Visitor<()>, typ, env)
+ visit_ty(self as @mut Visitor<()>, typ, env)
}
fn visit_generics(@mut self, generics: &Generics, env: ()) {
self.simple_visitor.visit_generics(generics);
- visit_generics(self as @Visitor<()>, generics, env)
+ visit_generics(self as @mut Visitor<()>, generics, env)
}
fn visit_fn(@mut self,
function_kind: &fn_kind,
block,
span,
node_id);
- visit_fn(self as @Visitor<()>,
+ visit_fn(self as @mut Visitor<()>,
function_kind,
function_declaration,
block,
}
fn visit_ty_method(@mut self, method_type: &TypeMethod, env: ()) {
self.simple_visitor.visit_ty_method(method_type);
- visit_ty_method(self as @Visitor<()>, method_type, env)
+ visit_ty_method(self as @mut Visitor<()>, method_type, env)
}
fn visit_trait_method(@mut self, trait_method: &trait_method, env: ()) {
self.simple_visitor.visit_trait_method(trait_method);
- visit_trait_method(self as @Visitor<()>, trait_method, env)
+ visit_trait_method(self as @mut Visitor<()>, trait_method, env)
}
fn visit_struct_def(@mut self,
struct_definition: @struct_def,
identifier,
generics,
node_id);
- visit_struct_def(self as @Visitor<()>,
+ visit_struct_def(self as @mut Visitor<()>,
struct_definition,
identifier,
generics,
}
fn visit_struct_field(@mut self, struct_field: @struct_field, env: ()) {
self.simple_visitor.visit_struct_field(struct_field);
- visit_struct_field(self as @Visitor<()>, struct_field, env)
+ visit_struct_field(self as @mut Visitor<()>, struct_field, env)
}
}
// 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.
glue_fn *drop_glue;
glue_fn *free_glue;
glue_fn *visit_glue;
+ size_t borrow_offset;
};
extern "C" type_desc *rust_clone_type_desc(type_desc*);
*/
#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
- }
}
//
NULL, // drop_glue
NULL, // free_glue
NULL, // visit_glue
+ 0, // borrow_offset
};
//
#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
LLVMRustWriteOutputFile(LLVMPassManagerRef PMR,
LLVMModuleRef M,
const char *triple,
+ const char *cpu,
const char *feature,
const char *path,
TargetMachine::CodeGenFileType FileType,
std::string Err;
std::string Trip(Triple::normalize(triple));
std::string FeaturesStr(feature);
- std::string CPUStr("generic");
+ std::string CPUStr(cpu);
const Target *TheTarget = TargetRegistry::lookupTarget(Trip, Err);
TargetMachine *Target =
TheTarget->createTargetMachine(Trip, CPUStr, FeaturesStr,
unwrapDI<DIArray>(Elements),
RunTimeLang));
}
+
+extern "C" void LLVMSetUnnamedAddr(LLVMValueRef Value, LLVMBool Unnamed) {
+ unwrap<GlobalValue>(Value)->setUnnamedAddr(Unnamed);
+}
LLVMDIBuilderCreateEnumerator
LLVMDIBuilderCreateEnumerationType
LLVMDIBuilderCreateUnionType
+LLVMSetUnnamedAddr
#[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 }
// 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
+}
--- /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.
+
+// Check that `&mut` objects cannot be borrowed twice, just like
+// other `&mut` pointers.
+
+trait Foo {
+ fn f1<'a>(&'a mut self) -> &'a ();
+ fn f2(&mut self);
+}
+
+fn test(x: &mut Foo) {
+ let _y = x.f1();
+ x.f2(); //~ ERROR cannot borrow `*x` as mutable more than once at a time
+}
+
+fn main() {}
}
pub fn main() {
- let x = [
+ let x = ~[
Foo { string: ~"foo" },
Foo { string: ~"bar" },
Foo { string: ~"baz" }
--- /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.
+
+trait Foo {
+ fn borrowed<'a>(&'a self) -> &'a ();
+}
+
+fn borrowed_receiver<'a>(x: &'a Foo) -> &'a () {
+ x.borrowed()
+}
+
+fn managed_receiver(x: @Foo) -> &() {
+ x.borrowed() //~ ERROR cannot root managed value long enough
+}
+
+fn managed_receiver_1(x: @Foo) {
+ *x.borrowed()
+}
+
+fn owned_receiver(x: ~Foo) -> &() {
+ x.borrowed() //~ ERROR borrowed value does not live long enough
+}
+
+fn mut_owned_receiver(mut x: ~Foo) {
+ let _y = x.borrowed();
+ let _z = &mut x; //~ ERROR cannot borrow
+}
+
+fn imm_owned_receiver(mut x: ~Foo) {
+ let _y = x.borrowed();
+ let _z = &x;
+}
+
+fn main() {}
+
--- /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.
+
+trait Foo {
+ fn borrowed(&self);
+ fn borrowed_mut(&mut self);
+}
+
+fn borrowed_receiver(x: &Foo) {
+ x.borrowed();
+ x.borrowed_mut(); //~ ERROR cannot borrow
+}
+
+fn borrowed_mut_receiver(x: &mut Foo) {
+ x.borrowed();
+ x.borrowed_mut();
+}
+
+fn managed_receiver(x: @Foo) {
+ x.borrowed();
+ x.borrowed_mut(); //~ ERROR cannot borrow
+}
+
+fn managed_mut_receiver(x: @mut Foo) {
+ x.borrowed();
+ x.borrowed_mut();
+}
+
+fn owned_receiver(x: ~Foo) {
+ x.borrowed();
+ x.borrowed_mut(); //~ ERROR cannot borrow
+}
+
+fn mut_owned_receiver(mut x: ~Foo) {
+ x.borrowed();
+ x.borrowed_mut();
+}
+
+fn main() {}
+
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 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() {}
//~^ ERROR dereference of reference outside its lifetime
//~^^ ERROR automatically borrowed pointer is not valid at the time of borrow
//~^^^ ERROR lifetime of return value does not outlive the function call
- //~^^^^ ERROR cannot infer an appropriate lifetime
}
--- /dev/null
+macro_rules! test ( ($nm:ident,
+ $a:attr,
+ $i:item) => (mod $nm { $a; $i }); )
+
+test!(a,
+ #[cfg(qux)],
+ pub fn bar() { })
+
+test!(b,
+ #[cfg(not(qux))],
+ pub fn bar() { })
+
+#[qux]
+fn main() {
+ a::bar();
+ //~^ ERROR use of undeclared module `a`
+ //~^^ ERROR unresolved name
+ //~^^^ ERROR unresolved name `a::bar`
+ b::bar();
+}
+
--- /dev/null
+macro_rules! test ( ($nm:ident,
+ $a:attr,
+ $i:item) => (mod $nm { $a $i }); )
+
+test!(a,
+ #[cfg(qux)],
+ pub fn bar() { })
+
+test!(b,
+ #[cfg(not(qux))],
+ pub fn bar() { })
+
+// test1!(#[bar])
+#[qux]
+fn main() {
+ a::bar(); //~ ERROR unresolved name `a::bar`
+ b::bar();
+}
+
--- /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 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.
+
+trait Foo {
+ fn borrowed(&self);
+ fn borrowed_mut(&mut self);
+
+ fn managed(@self);
+ fn managed_mut(@mut self);
+
+ fn owned(~self);
+}
+
+fn borrowed_receiver(x: &Foo) {
+ x.borrowed();
+ x.borrowed_mut(); // See [1]
+ x.managed(); //~ ERROR does not implement any method
+ x.managed_mut(); //~ ERROR does not implement any method
+ x.owned(); //~ ERROR does not implement any method
+}
+
+fn borrowed_mut_receiver(x: &mut Foo) {
+ x.borrowed();
+ x.borrowed_mut();
+ x.managed(); //~ ERROR does not implement any method
+ x.managed_mut(); //~ ERROR does not implement any method
+ x.owned(); //~ ERROR does not implement any method
+}
+
+fn managed_receiver(x: @Foo) {
+ x.borrowed();
+ x.borrowed_mut(); // See [1]
+ x.managed();
+ x.managed_mut(); //~ ERROR does not implement any method
+ x.owned(); //~ ERROR does not implement any method
+}
+
+fn managed_mut_receiver(x: @mut Foo) {
+ x.borrowed();
+ x.borrowed_mut();
+ x.managed(); //~ ERROR does not implement any method
+ x.managed_mut();
+ x.owned(); //~ ERROR does not implement any method
+}
+
+fn owned_receiver(x: ~Foo) {
+ x.borrowed();
+ x.borrowed_mut(); // See [1]
+ x.managed(); //~ ERROR does not implement any method
+ x.managed_mut(); //~ ERROR does not implement any method
+ x.owned();
+}
+
+fn main() {}
+
+// [1]: These cases are illegal, but the error is not detected
+// until borrowck, so see the test borrowck-object-mutability.rs
}
fn do_add(x: @add, y: @add) -> @add {
- x.plus(y) //~ ERROR cannot call a method whose type contains a self-type through a boxed trait
+ x.plus(y) //~ ERROR cannot call a method whose type contains a self-type through an object
}
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 _ = (~"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`
-}
--- /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.
+
+// error-pattern: Unit-like struct construction is written with no trailing `{ }`
+struct Foo;
+
+fn f2() {
+ let _end_stmt = Foo { };
+}
+
+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.
+
+// error-pattern: Unit-like struct construction is written with no trailing `{ }`
+struct Foo;
+
+fn g3() {
+ let _mid_tuple = (Foo { }, 2);
+}
+
+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.
+
+// error-pattern: Unit-like struct construction is written with no trailing `{ }`
+struct Foo;
+
+fn h4() {
+ let _end_of_tuple = (3, Foo { });
+}
+
+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.
+
+// error-pattern: Unit-like struct construction is written with no trailing `{ }`
+struct Foo;
+
+fn i5() {
+ let _end_of_block = { Foo { } };
+}
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: Unit-like struct should be written as `struct Foo;`
+// error-pattern: Unit-like struct definition should be written as `struct Foo;`
struct Foo {}
fn main() {}
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
}
--- /dev/null
+// error-pattern:borrowed
+
+trait Foo {
+ fn foo(&self, @mut int);
+}
+
+impl Foo for int {
+ fn foo(&self, x: @mut int) {
+ *x += *self;
+ }
+}
+
+fn main() {
+ let x = @mut 3_i;
+ let y = x as @mut Foo;
+
+ // The call to `y.foo(...)` should freeze `y` (and thus also `x`,
+ // since `x === y`). It is thus an error when `foo` tries to
+ // mutate `x`.
+ y.foo(x);
+}
}
}
-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() {
pub fn main() {
- let mut nyan: @noisy = @cat(0u, 2, ~"nyan") as @noisy;
+ let nyan: @mut noisy = @mut cat(0u, 2, ~"nyan") as @mut noisy;
nyan.speak();
}
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() {}
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.
-// xfail-test
enum side { mayo, catsup, vinegar }
enum order { hamburger, fries(side), shake }
enum meal { to_go(order), for_here(order) }
// 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");
#[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.
+
+// Test invoked `&self` methods on owned objects where the values
+// closed over contain managed values. This implies that the ~ boxes
+// will have headers that must be skipped over.
+
+trait FooTrait {
+ fn foo(&self) -> uint;
+}
+
+struct BarStruct {
+ x: @uint
+}
+
+impl FooTrait for BarStruct {
+ fn foo(&self) -> uint {
+ *self.x
+ }
+}
+
+pub fn main() {
+ let foos: ~[ ~FooTrait: ] = ~[
+ ~BarStruct{ x: @0 } as ~FooTrait:,
+ ~BarStruct{ x: @1 } as ~FooTrait:,
+ ~BarStruct{ x: @2 } as ~FooTrait:
+ ];
+
+ for i in range(0u, foos.len()) {
+ assert_eq!(i, foos[i].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.
+
+// Test invoked `&self` methods on owned objects where the values
+// closed over do not contain managed values, and thus the ~ boxes do
+// not have headers.
+
+trait FooTrait {
+ fn foo(&self) -> uint;
+}
+
+struct BarStruct {
+ x: uint
+}
+
+impl FooTrait for BarStruct {
+ fn foo(&self) -> uint {
+ self.x
+ }
+}
+
+pub fn main() {
+ let foos: ~[ ~FooTrait ] = ~[
+ ~BarStruct{ x: 0 } as ~FooTrait,
+ ~BarStruct{ x: 1 } as ~FooTrait,
+ ~BarStruct{ x: 2 } as ~FooTrait
+ ];
+
+ for i in range(0u, foos.len()) {
+ assert_eq!(i, foos[i].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.
+
+// Test invoked `&self` methods on owned objects where the values
+// closed over contain managed values. This implies that the ~ boxes
+// will have headers that must be skipped over.
+
+trait FooTrait {
+ fn foo(~self) -> uint;
+}
+
+struct BarStruct {
+ x: uint
+}
+
+impl FooTrait for BarStruct {
+ fn foo(~self) -> uint {
+ self.x
+ }
+}
+
+pub fn main() {
+ let foo = ~BarStruct{ x: 22 } as ~FooTrait;
+ assert_eq!(22, foo.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.
-
-trait FooTrait {
- fn foo(&self) -> uint;
-}
-
-struct BarStruct {
- x: uint
-}
-
-impl FooTrait for BarStruct {
- fn foo(&self) -> uint {
- self.x
- }
-}
-
-pub fn main() {
- let foos: ~[ ~FooTrait ] = ~[
- ~BarStruct{ x: 0 } as ~FooTrait,
- ~BarStruct{ x: 1 } as ~FooTrait,
- ~BarStruct{ x: 2 } as ~FooTrait
- ];
-
- for i in range(0u, foos.len()) {
- assert_eq!(i, foos[i].foo());
- }
-}
unsafe {
let u = my_visitor(**self);
let v = ptr_visit_adaptor::<my_visitor>(Inner {inner: u});
- visit_tydesc(inner, @v as @TyVisitor);
+ visit_tydesc(inner, &v as &TyVisitor);
true
}
}
let td = get_tydesc_for(r);
error!("tydesc sz: %u, align: %u",
(*td).size, (*td).align);
- let v = @v as @TyVisitor;
+ let v = &v as &TyVisitor;
visit_tydesc(td, v);
let r = u.vals.clone();
fn visit_evec_uniq(&self, _mtbl: uint, inner: *TyDesc) -> bool {
self.types.push(~"[");
unsafe {
- visit_tydesc(inner, (@*self) as @TyVisitor);
+ visit_tydesc(inner, (&*self) as &TyVisitor);
}
self.types.push(~"]");
true
fn visit_evec_uniq_managed(&self, _mtbl: uint, inner: *TyDesc) -> bool {
self.types.push(~"[");
unsafe {
- visit_tydesc(inner, (@*self) as @TyVisitor);
+ visit_tydesc(inner, (&*self) as &TyVisitor);
}
self.types.push(~"]");
true
fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
}
-fn visit_ty<T>(v: @TyVisitor) {
+fn visit_ty<T>(v: &TyVisitor) {
unsafe {
visit_tydesc(get_tydesc::<T>(), v);
}
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
-// 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.
-
-trait Foo {
- fn f(&self) -> int;
-}
-
-struct Bar {
- x: int
-}
-
-impl Foo for Bar {
- fn f(&self) -> int {
- self.x
- }
-}
-
-pub fn main() {
- let x = ~Bar { x: 10 };
- let y = x as ~Foo;
- assert_eq!(y.f(), 10);
-}
pub fn main() {
let x = @[1, 2, 3];
match x {
- [2, .._] => ::std::util::unreachable(),
+ [2, .._] => fail!(),
[1, ..tail] => {
assert_eq!(tail, [2, 3]);
}
- [_] => ::std::util::unreachable(),
- [] => ::std::util::unreachable()
+ [_] => fail!(),
+ [] => fail!()
}
let y = (~[(1, true), (2, false)], 0.5);
match y {
- ([_, _, _], 0.5) => ::std::util::unreachable(),
+ ([_, _, _], 0.5) => fail!(),
([(1, a), (b, false), ..tail], _) => {
assert_eq!(a, true);
assert_eq!(b, 2);
assert!(tail.is_empty());
}
- ([..tail], _) => ::std::util::unreachable()
+ ([..tail], _) => fail!()
}
}
--- /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(),
- [_, .._, _, _] => ::std::util::unreachable(),
- [_, _] => ::std::util::unreachable(),
+ [_, _, _, _, _, .._] => fail!(),
+ [.._, _, _, _, _] => fail!(),
+ [_, .._, _, _] => fail!(),
+ [_, _] => fail!(),
[a] => {
assert_eq!(a, 1);
}
- [] => ::std::util::unreachable()
+ [] => fail!()
}
}
fn b() {
- let x = [1, 2, 3];
+ let x = ~[1, 2, 3];
match x {
[a, b, ..c] => {
assert_eq!(a, 1);
}
}
+fn c() {
+ let x = [1];
+ match x {
+ [2, .. _] => fail!(),
+ [.. _] => ()
+ }
+}
+
+fn d() {
+ let x = [1, 2, 3];
+ let branch = match x {
+ [1, 1, .. _] => 0,
+ [1, 2, 3, .. _] => 1,
+ [1, 2, .. _] => 2,
+ _ => 3
+ };
+ assert_eq!(branch, 1);
+}
+
pub fn main() {
a();
b();
+ c();
+ d();
}
}
pub fn main() {
- let x = [
+ let x = ~[
Foo { string: ~"foo" },
Foo { string: ~"bar" },
Foo { string: ~"baz" }