Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Ziad Hatahet 2013-10-23 10:09:06 -07:00
commit 7d69837bd2
110 changed files with 1956 additions and 720 deletions

View file

@ -3168,7 +3168,7 @@ Raw pointers (`*`)
: Raw pointers are pointers without safety or liveness guarantees.
Raw pointers are written `*content`,
for example `*int` means a raw pointer to an integer.
Copying or dropping a raw pointer is has no effect on the lifecycle of any other value.
Copying or dropping a raw pointer has no effect on the lifecycle of any other value.
Dereferencing a raw pointer or converting it to any other pointer type is an [`unsafe` operation](#unsafe-functions).
Raw pointers are generally discouraged in Rust code;
they exist to support interoperability with foreign code,
@ -3395,16 +3395,23 @@ a [temporary](#lvalues-rvalues-and-temporaries), or a local variable.
A _local variable_ (or *stack-local* allocation) holds a value directly,
allocated within the stack's memory. The value is a part of the stack frame.
Local variables are immutable unless declared with `let mut`. The
`mut` keyword applies to all local variables declared within that
declaration (so `let mut (x, y) = ...` declares two mutable variables, `x` and
`y`).
Local variables are immutable unless declared otherwise like: `let mut x = ...`.
Function parameters are immutable unless declared with `mut`. The
`mut` keyword applies only to the following parameter (so `|mut x, y|`
and `fn f(mut x: ~int, y: ~int)` declare one mutable variable `x` and
one immutable variable `y`).
Methods that take either `self` or `~self` can optionally place them in a
mutable slot by prefixing them with `mut` (similar to regular arguments):
~~~
trait Changer {
fn change(mut self) -> Self;
fn modify(mut ~self) -> ~Self;
}
~~~
Local variables are not initialized when allocated; the entire frame worth of
local variables are allocated at once, on frame-entry, in an uninitialized
state. Subsequent statements within a function may or may not initialize the

View file

@ -151,22 +151,6 @@ declaration to appear at the top level of the file: all statements must
live inside a function. Rust programs can also be compiled as
libraries, and included in other programs.
## Using the rust tool
While using `rustc` directly to generate your executables, and then
running them manually is a perfectly valid way to test your code,
for smaller projects, prototypes, or if you're a beginner, it might be
more convenient to use the `rust` tool.
The `rust` tool provides central access to the other rust tools,
as well as handy shortcuts for directly running source files.
For example, if you have a file `foo.rs` in your current directory,
`rust run foo.rs` would attempt to compile it and, if successful,
directly run the resulting binary.
To get a list of all available commands, simply call `rust` without any
argument.
## Editing Rust code
There are vim highlighting and indentation scripts in the Rust source

View file

@ -370,6 +370,7 @@ $(3)/stage$(1)/test/rustpkgtest-$(2)$$(X_$(2)): \
$$(SREQ$(1)_T_$(2)_H_$(3)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) \
$$(HBIN$(1)_H_$(3))/rustpkg$$(X_$(2)) \
$$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$$(X_$(2)) \
$$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(2))
@$$(call E, compile_and_link: $$@)

View file

@ -521,15 +521,15 @@ fn borrow_rwlock<T:Freeze + Send>(state: *mut RWArcInner<T>) -> *RWLock {
/// The "write permission" token used for RWArc.write_downgrade().
pub struct RWWriteMode<'self, T> {
data: &'self mut T,
token: sync::RWLockWriteMode<'self>,
poison: PoisonOnFail,
priv data: &'self mut T,
priv token: sync::RWLockWriteMode<'self>,
priv poison: PoisonOnFail,
}
/// The "read permission" token used for RWArc.write_downgrade().
pub struct RWReadMode<'self, T> {
data: &'self T,
token: sync::RWLockReadMode<'self>,
priv data: &'self T,
priv token: sync::RWLockReadMode<'self>,
}
impl<'self, T:Freeze + Send> RWWriteMode<'self, T> {

View file

@ -22,11 +22,11 @@ pub enum CharacterSet {
/// Contains configuration parameters for `to_base64`.
pub struct Config {
/// Character set to use
char_set: CharacterSet,
priv char_set: CharacterSet,
/// True to pad output with `=` characters
pad: bool,
priv pad: bool,
/// `Some(len)` to wrap lines at `len`, `None` to disable line wrapping
line_length: Option<uint>
priv line_length: Option<uint>
}
/// Configuration for RFC 4648 standard base64 encoding
@ -318,7 +318,7 @@ mod test {
use std::vec;
do 1000.times {
let times = task_rng().gen_integer_range(1u, 100);
let times = task_rng().gen_range(1u, 100);
let v = vec::from_fn(times, |_| random::<u8>());
assert_eq!(v.to_base64(STANDARD).from_base64().unwrap(), v);
}

View file

@ -226,9 +226,9 @@ enum Op {Union, Intersect, Assign, Difference}
#[deriving(Clone)]
pub struct Bitv {
/// Internal representation of the bit vector (small or large)
rep: BitvVariant,
priv rep: BitvVariant,
/// The number of valid bits in the internal representation
nbits: uint
priv nbits: uint
}
fn die() -> ! {

View file

@ -365,7 +365,7 @@ pub mod test {
digest.reset();
while count < total_size {
let next: uint = rng.gen_integer_range(0, 2 * blocksize + 1);
let next: uint = rng.gen_range(0, 2 * blocksize + 1);
let remaining = total_size - count;
let size = if next > remaining { remaining } else { next };
digest.input(buffer.slice_to(size));

View file

@ -50,7 +50,7 @@ impl Doc {
}
pub struct TaggedDoc {
tag: uint,
priv tag: uint,
doc: Doc,
}

View file

@ -155,7 +155,7 @@ struct FileInput_ {
// "self.fi" -> "self." and renaming FileInput_. Documentation above
// will likely have to be updated to use `let mut in = ...`.
pub struct FileInput {
fi: @mut FileInput_
priv fi: @mut FileInput_
}
impl FileInput {

View file

@ -113,7 +113,7 @@ mod tests {
let mut r = rand::rng();
let mut words = ~[];
do 20.times {
let range = r.gen_integer_range(1u, 10);
let range = r.gen_range(1u, 10);
words.push(r.gen_vec::<u8>(range));
}
do 20.times {

View file

@ -119,7 +119,7 @@ pub struct Opt {
/// How often it can occur
occur: Occur,
/// Which options it aliases
aliases: ~[Opt],
priv aliases: ~[Opt],
}
/// Describes wether an option is given at all or has a value.
@ -134,9 +134,9 @@ enum Optval {
#[deriving(Clone, Eq)]
pub struct Matches {
/// Options that matched
opts: ~[Opt],
priv opts: ~[Opt],
/// Values of the Options that matched
vals: ~[~[Optval]],
priv vals: ~[~[Optval]],
/// Free string fragments
free: ~[~str]
}

View file

@ -480,13 +480,13 @@ pub struct MatchOptions {
* currently only considers upper/lower case relationships between ASCII characters,
* but in future this might be extended to work with Unicode.
*/
case_sensitive: bool,
priv case_sensitive: bool,
/**
* If this is true then path-component separator characters (e.g. `/` on Posix)
* must be matched by a literal `/`, rather than by `*` or `?` or `[...]`
*/
require_literal_separator: bool,
priv require_literal_separator: bool,
/**
* If this is true then paths that contain components that start with a `.` will
@ -494,7 +494,7 @@ pub struct MatchOptions {
* will not match. This is useful because such files are conventionally considered
* hidden on Unix systems and it might be desirable to skip them when listing files.
*/
require_literal_leading_dot: bool
priv require_literal_leading_dot: bool
}
impl MatchOptions {

View file

@ -17,9 +17,9 @@ use std::cast;
/// An implementation of the io::Reader interface which reads a buffer of bytes
pub struct BufReader {
/// The buffer of bytes to read
buf: ~[u8],
priv buf: ~[u8],
/// The current position in the buffer of bytes
pos: @mut uint
priv pos: @mut uint
}
impl BufReader {

View file

@ -49,11 +49,11 @@ pub type Object = TreeMap<~str, Json>;
/// returned
pub struct Error {
/// The line number at which the error occurred
line: uint,
priv line: uint,
/// The column number at which the error occurred
col: uint,
priv col: uint,
/// A message describing the type of the error
msg: @~str,
priv msg: @~str,
}
fn escape_str(s: &str) -> ~str {

View file

@ -20,8 +20,8 @@ use super::bigint::BigInt;
#[deriving(Clone)]
#[allow(missing_doc)]
pub struct Ratio<T> {
numer: T,
denom: T
priv numer: T,
priv denom: T
}
/// Alias for a `Ratio` of machine-sized integers.

View file

@ -71,17 +71,17 @@ impl ToStr for Identifier {
#[deriving(Clone, Eq)]
pub struct Version {
/// The major version, to be incremented on incompatible changes.
major: uint,
priv major: uint,
/// The minor version, to be incremented when functionality is added in a
/// backwards-compatible manner.
minor: uint,
priv minor: uint,
/// The patch version, to be incremented when backwards-compatible bug
/// fixes are made.
patch: uint,
priv patch: uint,
/// The pre-release version identifier, if one exists.
pre: ~[Identifier],
priv pre: ~[Identifier],
/// The build metadata, ignored when determining version precedence.
build: ~[Identifier],
priv build: ~[Identifier],
}
impl ToStr for Version {

View file

@ -1069,8 +1069,8 @@ mod big_tests {
isSorted(arr);
do 3.times {
let i1 = rng.gen_integer_range(0u, n);
let i2 = rng.gen_integer_range(0u, n);
let i1 = rng.gen_range(0u, n);
let i2 = rng.gen_range(0u, n);
arr.swap(i1, i2);
}
tim_sort(arr); // 3sort
@ -1088,7 +1088,7 @@ mod big_tests {
isSorted(arr);
do (n/100).times {
let idx = rng.gen_integer_range(0u, n);
let idx = rng.gen_range(0u, n);
arr[idx] = rng.gen();
}
tim_sort(arr);
@ -1141,8 +1141,8 @@ mod big_tests {
isSorted(arr);
do 3.times {
let i1 = rng.gen_integer_range(0u, n);
let i2 = rng.gen_integer_range(0u, n);
let i1 = rng.gen_range(0u, n);
let i2 = rng.gen_range(0u, n);
arr.swap(i1, i2);
}
tim_sort(arr); // 3sort
@ -1160,7 +1160,7 @@ mod big_tests {
isSorted(arr);
do (n/100).times {
let idx = rng.gen_integer_range(0u, n);
let idx = rng.gen_range(0u, n);
arr[idx] = @rng.gen();
}
tim_sort(arr);

View file

@ -105,18 +105,23 @@ pub trait Stats {
#[deriving(Clone, Eq)]
#[allow(missing_doc)]
pub struct Summary {
sum: f64,
priv sum: f64,
// public
min: f64,
// public
max: f64,
mean: f64,
priv mean: f64,
// public
median: f64,
var: f64,
std_dev: f64,
std_dev_pct: f64,
priv var: f64,
priv std_dev: f64,
priv std_dev_pct: f64,
// public
median_abs_dev: f64,
// public
median_abs_dev_pct: f64,
quartiles: (f64,f64,f64),
iqr: f64,
priv quartiles: (f64,f64,f64),
priv iqr: f64,
}
impl Summary {

View file

@ -376,8 +376,8 @@ impl Semaphore {
* A task which fails while holding a mutex will unlock the mutex as it
* unwinds.
*/
pub struct Mutex { priv sem: Sem<~[WaitQueue]> }
pub struct Mutex { priv sem: Sem<~[WaitQueue]> }
impl Clone for Mutex {
/// Create a new handle to the mutex.
fn clone(&self) -> Mutex { Mutex { sem: Sem((*self.sem).clone()) } }
@ -663,8 +663,8 @@ impl RWLock {
}
/// The "write permission" token used for rwlock.write_downgrade().
pub struct RWLockWriteMode<'self> { priv lock: &'self RWLock, priv token: NonCopyable }
pub struct RWLockWriteMode<'self> { priv lock: &'self RWLock, priv token: NonCopyable }
/// The "read permission" token used for rwlock.write_downgrade().
pub struct RWLockReadMode<'self> { priv lock: &'self RWLock,
priv token: NonCopyable }

View file

@ -28,8 +28,8 @@ enum Msg<T> {
}
pub struct TaskPool<T> {
channels: ~[Chan<Msg<T>>],
next_index: uint,
priv channels: ~[Chan<Msg<T>>],
priv next_index: uint,
}
#[unsafe_destructor]

View file

@ -95,14 +95,14 @@ fn cap_for_attr(attr: attr::Attr) -> &'static str {
#[cfg(not(target_os = "win32"))]
pub struct Terminal {
num_colors: u16,
priv num_colors: u16,
priv out: @io::Writer,
priv ti: ~TermInfo
}
#[cfg(target_os = "win32")]
pub struct Terminal {
num_colors: u16,
priv num_colors: u16,
priv out: @io::Writer,
}

View file

@ -48,9 +48,9 @@ pub enum Param {
/// Container for static and dynamic variable arrays
pub struct Variables {
/// Static variables A-Z
sta: [Param, ..26],
priv sta: [Param, ..26],
/// Dynamic variables a-z
dyn: [Param, ..26]
priv dyn: [Param, ..26]
}
impl Variables {

View file

@ -15,9 +15,9 @@ use std::hashmap::HashMap;
/// A parsed terminfo entry.
pub struct TermInfo {
/// Names for the terminal
names: ~[~str],
priv names: ~[~str],
/// Map of capability name to boolean value
bools: HashMap<~str, bool>,
priv bools: HashMap<~str, bool>,
/// Map of capability name to numeric value
numbers: HashMap<~str, u16>,
/// Map of capability name to raw (unexpanded) string

View file

@ -102,9 +102,9 @@ impl TestFn {
// Structure passed to BenchFns
pub struct BenchHarness {
iterations: u64,
ns_start: u64,
ns_end: u64,
priv iterations: u64,
priv ns_start: u64,
priv ns_end: u64,
bytes: u64
}
@ -124,8 +124,8 @@ pub struct TestDescAndFn {
#[deriving(Clone, Encodable, Decodable, Eq)]
pub struct Metric {
value: f64,
noise: f64
priv value: f64,
priv noise: f64
}
#[deriving(Eq)]
@ -322,8 +322,8 @@ pub fn opt_shard(maybestr: Option<~str>) -> Option<(uint,uint)> {
#[deriving(Clone, Eq)]
pub struct BenchSamples {
ns_iter_summ: stats::Summary,
mb_s: uint
priv ns_iter_summ: stats::Summary,
priv mb_s: uint
}
#[deriving(Clone, Eq)]

View file

@ -31,9 +31,10 @@ pub mod rustrt {
}
/// A record specifying a time value in seconds and nanoseconds.
#[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
pub struct Timespec { sec: i64, nsec: i32 }
#[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
pub struct Timespec { priv sec: i64, priv nsec: i32 }
/*
* Timespec assumes that pre-epoch Timespecs have negative sec and positive
* nsec fields. Darwin's and Linux's struct timespec functions handle pre-
@ -105,18 +106,18 @@ pub fn tzset() {
#[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
pub struct Tm {
tm_sec: i32, // seconds after the minute ~[0-60]
tm_min: i32, // minutes after the hour ~[0-59]
tm_hour: i32, // hours after midnight ~[0-23]
tm_mday: i32, // days of the month ~[1-31]
tm_mon: i32, // months since January ~[0-11]
tm_year: i32, // years since 1900
tm_wday: i32, // days since Sunday ~[0-6]
tm_yday: i32, // days since January 1 ~[0-365]
tm_isdst: i32, // Daylight Savings Time flag
tm_gmtoff: i32, // offset from UTC in seconds
tm_zone: ~str, // timezone abbreviation
tm_nsec: i32, // nanoseconds
priv tm_sec: i32, // seconds after the minute ~[0-60]
priv tm_min: i32, // minutes after the hour ~[0-59]
priv tm_hour: i32, // hours after midnight ~[0-23]
priv tm_mday: i32, // days of the month ~[1-31]
priv tm_mon: i32, // months since January ~[0-11]
priv tm_year: i32, // years since 1900
priv tm_wday: i32, // days since Sunday ~[0-6]
priv tm_yday: i32, // days since January 1 ~[0-365]
priv tm_isdst: i32, // Daylight Savings Time flag
priv tm_gmtoff: i32, // offset from UTC in seconds
priv tm_zone: ~str, // timezone abbreviation
priv tm_nsec: i32, // nanoseconds
}
pub fn empty_tm() -> Tm {

View file

@ -1028,7 +1028,7 @@ mod test_treemap {
}
do 30.times {
let r = rng.gen_integer_range(0, ctrl.len());
let r = rng.gen_range(0, ctrl.len());
let (key, _) = ctrl.remove(r);
assert!(map.remove(&key));
check_structure(&map);

View file

@ -128,8 +128,8 @@ impl WorkMap {
}
pub struct Database {
db_filename: Path,
db_cache: TreeMap<~str, ~str>,
priv db_filename: Path,
priv db_cache: TreeMap<~str, ~str>,
db_dirty: bool
}
@ -209,7 +209,7 @@ impl Drop for Database {
pub struct Logger {
// FIXME #4432: Fill in
a: ()
priv a: ()
}
impl Logger {
@ -228,26 +228,26 @@ pub type FreshnessMap = TreeMap<~str,extern fn(&str,&str)->bool>;
#[deriving(Clone)]
pub struct Context {
db: RWArc<Database>,
logger: RWArc<Logger>,
cfg: Arc<json::Object>,
priv logger: RWArc<Logger>,
priv cfg: Arc<json::Object>,
/// Map from kinds (source, exe, url, etc.) to a freshness function.
/// The freshness function takes a name (e.g. file path) and value
/// (e.g. hash of file contents) and determines whether it's up-to-date.
/// For example, in the file case, this would read the file off disk,
/// hash it, and return the result of comparing the given hash and the
/// read hash for equality.
freshness: Arc<FreshnessMap>
priv freshness: Arc<FreshnessMap>
}
pub struct Prep<'self> {
ctxt: &'self Context,
fn_name: &'self str,
declared_inputs: WorkMap,
priv ctxt: &'self Context,
priv fn_name: &'self str,
priv declared_inputs: WorkMap,
}
pub struct Exec {
discovered_inputs: WorkMap,
discovered_outputs: WorkMap
priv discovered_inputs: WorkMap,
priv discovered_outputs: WorkMap
}
enum Work<'self, T> {

View file

@ -975,9 +975,9 @@ fn get_explicit_self(item: ebml::Doc) -> ast::explicit_self_ {
let explicit_self_kind = string[0];
match explicit_self_kind as char {
's' => { return ast::sty_static; }
'v' => { return ast::sty_value; }
'v' => { return ast::sty_value(get_mutability(string[1])); }
'@' => { return ast::sty_box(get_mutability(string[1])); }
'~' => { return ast::sty_uniq; }
'~' => { return ast::sty_uniq(get_mutability(string[1])); }
'&' => {
// FIXME(#4846) expl. region
return ast::sty_region(None, get_mutability(string[1]));

View file

@ -662,8 +662,9 @@ fn encode_explicit_self(ebml_w: &mut writer::Encoder, explicit_self: ast::explic
sty_static => {
ebml_w.writer.write(&[ 's' as u8 ]);
}
sty_value => {
sty_value(m) => {
ebml_w.writer.write(&[ 'v' as u8 ]);
encode_mutability(ebml_w, m);
}
sty_region(_, m) => {
// FIXME(#4846) encode custom lifetime
@ -674,8 +675,9 @@ fn encode_explicit_self(ebml_w: &mut writer::Encoder, explicit_self: ast::explic
ebml_w.writer.write(&[ '@' as u8 ]);
encode_mutability(ebml_w, m);
}
sty_uniq => {
sty_uniq(m) => {
ebml_w.writer.write(&[ '~' as u8 ]);
encode_mutability(ebml_w, m);
}
}

View file

@ -410,7 +410,7 @@ impl tr for ast::Def {
ast::DefMethod(did0.tr(xcx), did1.map(|did1| did1.tr(xcx)))
}
ast::DefSelfTy(nid) => { ast::DefSelfTy(xcx.tr_id(nid)) }
ast::DefSelf(nid) => { ast::DefSelf(xcx.tr_id(nid)) }
ast::DefSelf(nid, m) => { ast::DefSelf(xcx.tr_id(nid), m) }
ast::DefMod(did) => { ast::DefMod(did.tr(xcx)) }
ast::DefForeignMod(did) => { ast::DefForeignMod(did.tr(xcx)) }
ast::DefStatic(did, m) => { ast::DefStatic(did.tr(xcx), m) }

View file

@ -392,7 +392,7 @@ fn visit_fn(v: &mut LivenessVisitor,
match *fk {
visit::fk_method(_, _, method) => {
match method.explicit_self.node {
sty_value | sty_region(*) | sty_box(_) | sty_uniq => {
sty_value(_) | sty_region(*) | sty_box(_) | sty_uniq(_) => {
fn_maps.add_variable(Arg(method.self_id,
special_idents::self_));
}

View file

@ -488,12 +488,12 @@ impl mem_categorization_ctxt {
}
}
ast::DefSelf(self_id) => {
ast::DefSelf(self_id, mutbl) => {
@cmt_ {
id:id,
span:span,
cat:cat_self(self_id),
mutbl: McImmutable,
mutbl: if mutbl { McDeclared } else { McImmutable },
ty:expr_ty
}
}

View file

@ -227,7 +227,7 @@ pub fn moved_variable_node_id_from_def(def: Def) -> Option<NodeId> {
DefBinding(nid, _) |
DefArg(nid, _) |
DefLocal(nid, _) |
DefSelf(nid) => Some(nid),
DefSelf(nid, _) => Some(nid),
_ => None
}

View file

@ -150,7 +150,7 @@ enum Mutability {
enum SelfBinding {
NoSelfBinding,
HasSelfBinding(NodeId)
HasSelfBinding(NodeId, explicit_self)
}
impl Visitor<()> for Resolver {
@ -3799,8 +3799,12 @@ impl Resolver {
NoSelfBinding => {
// Nothing to do.
}
HasSelfBinding(self_node_id) => {
let def_like = DlDef(DefSelf(self_node_id));
HasSelfBinding(self_node_id, explicit_self) => {
let mutable = match explicit_self.node {
sty_uniq(m) | sty_value(m) if m == MutMutable => true,
_ => false
};
let def_like = DlDef(DefSelf(self_node_id, mutable));
*function_value_rib.self_binding = Some(def_like);
}
}
@ -3937,7 +3941,7 @@ impl Resolver {
// we only have self ty if it is a non static method
let self_binding = match method.explicit_self.node {
sty_static => { NoSelfBinding }
_ => { HasSelfBinding(method.self_id) }
_ => { HasSelfBinding(method.self_id, method.explicit_self) }
};
self.resolve_function(rib_kind,

View file

@ -1099,7 +1099,7 @@ pub fn trans_local_var(bcx: @mut Block, def: ast::Def) -> Datum {
ast::DefLocal(nid, _) | ast::DefBinding(nid, _) => {
take_local(bcx, bcx.fcx.lllocals, nid)
}
ast::DefSelf(nid) => {
ast::DefSelf(nid, _) => {
let self_info: ValSelfData = match bcx.fcx.llself {
Some(ref self_info) => *self_info,
None => {

View file

@ -144,7 +144,7 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId)
debug!("calling inline trans_fn with self_ty {}",
ty_to_str(ccx.tcx, self_ty));
match mth.explicit_self.node {
ast::sty_value => impl_self(self_ty, ty::ByRef),
ast::sty_value(_) => impl_self(self_ty, ty::ByRef),
_ => impl_self(self_ty, ty::ByCopy),
}
}

View file

@ -120,7 +120,7 @@ pub fn trans_method(ccx: @mut CrateContext,
debug!("calling trans_fn with self_ty {}",
self_ty.repr(ccx.tcx));
match method.explicit_self.node {
ast::sty_value => impl_self(self_ty, ty::ByRef),
ast::sty_value(_) => impl_self(self_ty, ty::ByRef),
_ => impl_self(self_ty, ty::ByCopy),
}
}

View file

@ -672,7 +672,7 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>(
{
match self_info.explicit_self.node {
ast::sty_static => None,
ast::sty_value => {
ast::sty_value(_) => {
Some(self_info.untransformed_self_ty)
}
ast::sty_region(ref lifetime, mutability) => {
@ -689,7 +689,7 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>(
ty::mt {ty: self_info.untransformed_self_ty,
mutbl: mutability}))
}
ast::sty_uniq => {
ast::sty_uniq(_) => {
Some(ty::mk_uniq(this.tcx(),
ty::mt {ty: self_info.untransformed_self_ty,
mutbl: ast::MutImmutable}))

View file

@ -1082,7 +1082,7 @@ impl<'self> LookupContext<'self> {
ast::sty_static => {
self.bug(~"static method for object type receiver");
}
ast::sty_value => {
ast::sty_value(_) => {
ty::mk_err() // error reported in `enforce_object_limitations()`
}
ast::sty_region(*) | ast::sty_box(*) | ast::sty_uniq(*) => {
@ -1141,7 +1141,7 @@ impl<'self> LookupContext<'self> {
through an object");
}
ast::sty_value => { // reason (a) above
ast::sty_value(_) => { // reason (a) above
self.tcx().sess.span_err(
self.expr.span,
"cannot call a method with a by-value receiver \
@ -1198,7 +1198,7 @@ impl<'self> LookupContext<'self> {
false
}
sty_value => {
sty_value(_) => {
rcvr_matches_ty(self.fcx, rcvr_ty, candidate)
}
@ -1236,7 +1236,7 @@ impl<'self> LookupContext<'self> {
}
}
sty_uniq => {
sty_uniq(_) => {
debug!("(is relevant?) explicit self is a unique pointer");
match ty::get(rcvr_ty).sty {
ty::ty_uniq(mt) => {
@ -1369,7 +1369,7 @@ impl<'self> LookupContext<'self> {
pub fn get_mode_from_explicit_self(explicit_self: ast::explicit_self_) -> SelfMode {
match explicit_self {
sty_value => ty::ByRef,
sty_value(_) => ty::ByRef,
_ => ty::ByCopy,
}
}

View file

@ -3254,7 +3254,7 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt,
defn: ast::Def)
-> ty_param_bounds_and_ty {
match defn {
ast::DefArg(nid, _) | ast::DefLocal(nid, _) | ast::DefSelf(nid) |
ast::DefArg(nid, _) | ast::DefLocal(nid, _) | ast::DefSelf(nid, _) |
ast::DefBinding(nid, _) => {
let typ = fcx.local_ty(sp, nid);
return no_params(typ);

View file

@ -58,7 +58,7 @@ fn encl_region_of_def(fcx: @mut FnCtxt, def: ast::Def) -> ty::Region {
let tcx = fcx.tcx();
match def {
DefLocal(node_id, _) | DefArg(node_id, _) |
DefSelf(node_id) | DefBinding(node_id, _) => {
DefSelf(node_id, _) | DefBinding(node_id, _) => {
tcx.region_maps.encl_region(node_id)
}
DefUpvar(_, subdef, closure_id, body_id) => {

View file

@ -388,8 +388,8 @@ impl Clean<SelfTy> for ast::explicit_self {
fn clean(&self) -> SelfTy {
match self.node {
ast::sty_static => SelfStatic,
ast::sty_value => SelfValue,
ast::sty_uniq => SelfOwned,
ast::sty_value(_) => SelfValue,
ast::sty_uniq(_) => SelfOwned,
ast::sty_region(lt, mt) => SelfBorrowed(lt.clean(), mt.clean()),
ast::sty_box(mt) => SelfManaged(mt.clean()),
}
@ -1171,7 +1171,7 @@ fn resolve_type(path: Path, tpbs: Option<~[TyParamBound]>,
let (def_id, kind) = match *d {
ast::DefFn(i, _) => (i, TypeFunction),
ast::DefSelf(i) | ast::DefSelfTy(i) => return Self(i),
ast::DefSelf(i, _) | ast::DefSelfTy(i) => return Self(i),
ast::DefTy(i) => (i, TypeEnum),
ast::DefTrait(i) => {
debug!("saw DefTrait in def_to_id");

View file

@ -12,22 +12,35 @@ use context::*;
use crate::*;
use package_id::*;
use package_source::*;
use path_util::{platform_library_name, target_build_dir};
use target::*;
use version::Version;
use workspace::pkg_parent_workspaces;
use workcache_support::*;
pub use path_util::default_workspace;
pub use source_control::{safe_git_clone, git_clone_url};
use std::os;
use std::{os, run};
use extra::arc::{Arc,RWArc};
use extra::workcache;
use extra::workcache::{Database, Logger, FreshnessMap};
use extra::treemap::TreeMap;
// A little sad -- duplicated from rustc::back::*
#[cfg(target_arch = "arm")]
fn cc_args() -> ~[~str] { ~[~"-marm"] }
#[cfg(target_arch = "mips")]
fn cc_args() -> ~[~str] { ~[] }
#[cfg(target_arch = "x86")]
fn cc_args() -> ~[~str] { ~[~"-m32"] }
#[cfg(target_arch = "x86_64")]
fn cc_args() -> ~[~str] { ~[~"-m64"] }
/// Convenience functions intended for calling from pkg.rs
/// p is where to put the cache file for dependencies
pub fn default_context(p: Path) -> BuildContext {
new_default_context(new_workcache_context(&p), p)
pub fn default_context(sysroot: Path, p: Path) -> BuildContext {
new_default_context(new_workcache_context(&p), sysroot)
}
pub fn new_default_context(c: workcache::Context, p: Path) -> BuildContext {
@ -68,7 +81,7 @@ pub fn new_workcache_context(p: &Path) -> workcache::Context {
pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
lib: Path) {
let cx = default_context(sysroot);
let cx = default_context(sysroot, root.clone());
let pkg_src = PkgSrc {
source_workspace: root.clone(),
build_in_destination: false,
@ -81,12 +94,12 @@ pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
tests: ~[],
benchs: ~[]
};
pkg_src.build(&cx, ~[]);
pkg_src.build(&cx, ~[], []);
}
pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
main: Path) {
let cx = default_context(sysroot);
let cx = default_context(sysroot, root.clone());
let pkg_src = PkgSrc {
source_workspace: root.clone(),
build_in_destination: false,
@ -100,13 +113,76 @@ pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
benchs: ~[]
};
pkg_src.build(&cx, ~[]);
pkg_src.build(&cx, ~[], []);
}
pub fn install_pkg(sysroot: Path, workspace: Path, name: ~str, version: Version) {
let cx = default_context(sysroot);
pub fn install_pkg(cx: &BuildContext,
workspace: Path,
name: ~str,
version: Version,
// For now, these inputs are assumed to be inputs to each of the crates
more_inputs: ~[(~str, Path)]) { // pairs of Kind and Path
let pkgid = PkgId{ version: version, ..PkgId::new(name)};
cx.install(PkgSrc::new(workspace.clone(), workspace, false, pkgid), &Everything);
cx.install(PkgSrc::new(workspace.clone(), workspace, false, pkgid),
&WhatToBuild{ build_type: Inferred,
inputs_to_discover: more_inputs,
sources: Everything });
}
/// Builds an arbitrary library whose short name is `output`,
/// by invoking `tool` with arguments `args` plus "-o %s", where %s
/// is the platform-specific library name for `output`.
/// Returns that platform-specific name.
pub fn build_library_in_workspace(exec: &mut workcache::Exec,
context: &mut Context,
package_name: &str,
tool: &str,
flags: &[~str],
paths: &[~str],
output: &str) -> ~str {
use command_failed = conditions::command_failed::cond;
let workspace = my_workspace(context, package_name);
let workspace_build_dir = target_build_dir(&workspace);
let out_name = workspace_build_dir.join_many([package_name.to_str(),
platform_library_name(output)]);
// make paths absolute
let pkgid = PkgId::new(package_name);
let absolute_paths = paths.map(|s| {
let whatever = workspace.join_many([~"src",
pkgid.to_str(),
s.to_owned()]);
whatever.as_str().unwrap().to_owned()
});
let cc_args = cc_args();
let all_args = flags + absolute_paths + cc_args +
~[~"-o", out_name.as_str().unwrap().to_owned()];
let exit_code = run::process_status(tool, all_args);
if exit_code != 0 {
command_failed.raise((tool.to_owned(), all_args, exit_code))
}
else {
let out_name_str = out_name.as_str().unwrap().to_owned();
exec.discover_output("binary",
out_name_str,
digest_only_date(&out_name));
context.add_library_path(out_name.dir_path());
out_name_str
}
}
pub fn my_workspace(context: &Context, package_name: &str) -> Path {
use bad_pkg_id = conditions::bad_pkg_id::cond;
// (this assumes no particular version is requested)
let pkgid = PkgId::new(package_name);
let workspaces = pkg_parent_workspaces(context, &pkgid);
if workspaces.is_empty() {
bad_pkg_id.raise((Path::new(package_name), package_name.to_owned()));
}
workspaces[0]
}
fn mk_crate(p: Path) -> Crate {

View file

@ -53,3 +53,9 @@ condition! {
condition! {
pub git_checkout_failed: (~str, Path) -> ();
}
condition! {
// str is output of applying the command (first component)
// to the args (second component)
pub command_failed: (~str, ~[~str], int) -> ~str;
}

View file

@ -54,6 +54,15 @@ impl BuildContext {
pub fn compile_upto(&self) -> StopBefore {
self.context.compile_upto()
}
pub fn add_library_path(&mut self, p: Path) {
debug!("Adding library path: {}", p.display());
self.context.add_library_path(p);
}
pub fn additional_library_paths(&self) -> ~[Path] {
self.context.rustc_flags.additional_library_paths.clone()
}
}
/*
@ -85,6 +94,9 @@ pub struct RustcFlags {
target: Option<~str>,
// Target CPU (defaults to rustc's default target CPU)
target_cpu: Option<~str>,
// Additional library directories, which get passed with the -L flag
// This can't be set with a rustpkg flag, only from package scripts
additional_library_paths: ~[Path],
// Any -Z features
experimental_features: Option<~[~str]>
}
@ -99,6 +111,7 @@ impl Clone for RustcFlags {
save_temps: self.save_temps,
target: self.target.clone(),
target_cpu: self.target_cpu.clone(),
additional_library_paths: self.additional_library_paths.clone(),
experimental_features: self.experimental_features.clone()
}
}
@ -148,6 +161,10 @@ impl Context {
pub fn compile_upto(&self) -> StopBefore {
self.rustc_flags.compile_upto
}
pub fn add_library_path(&mut self, p: Path) {
self.rustc_flags.additional_library_paths.push(p);
}
}
/// We assume that if ../../rustc exists, then we're running
@ -210,6 +227,7 @@ impl RustcFlags {
save_temps: false,
target: None,
target_cpu: None,
additional_library_paths: ~[],
experimental_features: None
}
}

View file

@ -23,7 +23,7 @@ use path_util::{find_dir_using_rust_path_hack, make_dir_rwx_recursive, default_w
use path_util::{target_build_dir, versionize, dir_has_crate_file};
use util::{compile_crate, DepMap};
use workcache_support;
use workcache_support::crate_tag;
use workcache_support::{digest_only_date, digest_file_with_date, crate_tag};
use extra::workcache;
use extra::treemap::TreeMap;
@ -390,7 +390,8 @@ impl PkgSrc {
deps: &mut DepMap,
crates: &[Crate],
cfgs: &[~str],
what: OutputType) {
what: OutputType,
inputs_to_discover: &[(~str, Path)]) {
for crate in crates.iter() {
let path = self.start_dir.join(&crate.file);
debug!("build_crates: compiling {}", path.display());
@ -408,7 +409,19 @@ impl PkgSrc {
let sub_dir = self.build_workspace().clone();
let sub_flags = crate.flags.clone();
let sub_deps = deps.clone();
let inputs = inputs_to_discover.map(|&(ref k, ref p)|
(k.clone(), p.as_str().unwrap().to_owned()));
do prep.exec |exec| {
for &(ref kind, ref p) in inputs.iter() {
let pth = Path::new(p.clone());
exec.discover_input(*kind, *p, if *kind == ~"file" {
digest_file_with_date(&pth)
} else if *kind == ~"binary" {
digest_only_date(&Path::new(p.clone()))
} else {
fail!("Bad kind in build_crates")
});
}
let result = compile_crate(&subcx,
exec,
&id,
@ -452,22 +465,43 @@ impl PkgSrc {
build_context: &BuildContext,
// DepMap is a map from str (crate name) to (kind, name) --
// it tracks discovered dependencies per-crate
cfgs: ~[~str]) -> DepMap {
cfgs: ~[~str],
inputs_to_discover: &[(~str, Path)]) -> DepMap {
let mut deps = TreeMap::new();
let libs = self.libs.clone();
let mains = self.mains.clone();
let tests = self.tests.clone();
let benchs = self.benchs.clone();
debug!("Building libs in {}, destination = {}",
self.source_workspace.display(), self.build_workspace().display());
self.build_crates(build_context, &mut deps, libs, cfgs, Lib);
self.destination_workspace.display(),
self.destination_workspace.display());
self.build_crates(build_context,
&mut deps,
libs,
cfgs,
Lib,
inputs_to_discover);
debug!("Building mains");
self.build_crates(build_context, &mut deps, mains, cfgs, Main);
self.build_crates(build_context,
&mut deps,
mains,
cfgs,
Main,
inputs_to_discover);
debug!("Building tests");
self.build_crates(build_context, &mut deps, tests, cfgs, Test);
self.build_crates(build_context,
&mut deps,
tests,
cfgs,
Test,
inputs_to_discover);
debug!("Building benches");
self.build_crates(build_context, &mut deps, benchs, cfgs, Bench);
self.build_crates(build_context,
&mut deps,
benchs,
cfgs,
Bench,
inputs_to_discover);
deps
}

View file

@ -461,7 +461,6 @@ pub fn versionize(p: &Path, v: &Version) -> Path {
p.with_filename(q)
}
#[cfg(target_os = "win32")]
pub fn chmod_read_only(p: &Path) -> bool {
#[fixed_stack_segment];
@ -483,3 +482,6 @@ pub fn chmod_read_only(p: &Path) -> bool {
}
}
pub fn platform_library_name(s: &str) -> ~str {
format!("{}{}{}", os::consts::DLL_PREFIX, s, os::consts::DLL_SUFFIX)
}

View file

@ -33,7 +33,6 @@ use rustc::metadata::filesearch;
use rustc::metadata::filesearch::rust_path;
use extra::{getopts};
use syntax::{ast, diagnostic};
use util::*;
use messages::{error, warn, note};
use path_util::{build_pkg_id_in_workspace, built_test_in_workspace};
use path_util::{U_RWX, in_rust_path};
@ -47,15 +46,16 @@ use context::{Context, BuildContext,
LLVMAssemble, LLVMCompileBitcode};
use package_id::PkgId;
use package_source::PkgSrc;
use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench, Tests};
use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench};
use target::{Tests, MaybeCustom, Inferred, JustOne};
use workcache_support::digest_only_date;
use exit_codes::{COPY_FAILED_CODE, BAD_FLAG_CODE};
pub mod api;
mod conditions;
mod context;
pub mod context;
mod crate;
mod exit_codes;
pub mod exit_codes;
mod installed_packages;
mod messages;
mod package_id;
@ -67,7 +67,7 @@ mod target;
#[cfg(test)]
mod tests;
mod util;
mod version;
pub mod version;
pub mod workcache_support;
mod workspace;
@ -96,7 +96,7 @@ impl<'self> PkgScript<'self> {
/// Given the path name for a package script
/// and a package ID, parse the package script into
/// a PkgScript that we can then execute
fn parse<'a>(sysroot: @Path,
fn parse<'a>(sysroot: Path,
script: Path,
workspace: &Path,
id: &'a PkgId) -> PkgScript<'a> {
@ -107,7 +107,7 @@ impl<'self> PkgScript<'self> {
debug!("pkgscript parse: {}", sysroot.display());
let options = @session::options {
binary: binary,
maybe_sysroot: Some(sysroot),
maybe_sysroot: Some(@sysroot),
crate_type: session::bin_crate,
.. (*session::basic_options()).clone()
};
@ -132,12 +132,7 @@ impl<'self> PkgScript<'self> {
}
}
/// Run the contents of this package script, where <what>
/// is the command to pass to it (e.g., "build", "clean", "install")
/// Returns a pair of an exit code and list of configs (obtained by
/// calling the package script's configs() function if it exists
fn run_custom(&mut self, exec: &mut workcache::Exec,
sysroot: &Path) -> (~[~str], ExitCode) {
fn build_custom(&mut self, exec: &mut workcache::Exec) -> ~str {
let sess = self.sess;
debug!("Working directory = {}", self.build_dir.display());
@ -152,17 +147,28 @@ impl<'self> PkgScript<'self> {
&self.build_dir,
sess,
crate);
debug!("Running program: {} {} {}", exe.display(),
sysroot.display(), "install");
// Discover the output
// FIXME (#9639): This needs to handle non-utf8 paths
exec.discover_output("binary", exe.as_str().unwrap(), digest_only_date(&exe));
// Discover the output
exec.discover_output("binary", exe.as_str().unwrap().to_owned(), digest_only_date(&exe));
exe.as_str().unwrap().to_owned()
}
/// Run the contents of this package script, where <what>
/// is the command to pass to it (e.g., "build", "clean", "install")
/// Returns a pair of an exit code and list of configs (obtained by
/// calling the package script's configs() function if it exists
fn run_custom(exe: &Path, sysroot: &Path) -> (~[~str], int) {
debug!("Running program: {} {} {}", exe.as_str().unwrap().to_owned(),
sysroot.display(), "install");
// FIXME #7401 should support commands besides `install`
// FIXME (#9639): This needs to handle non-utf8 paths
let status = run::process_status(exe.as_str().unwrap(),
[sysroot.as_str().unwrap().to_owned(), ~"install"]);
if status != 0 {
return (~[], status);
debug!("run_custom: first pkg command failed with {:?}", status);
(~[], status)
}
else {
debug!("Running program (configs): {} {} {}",
@ -170,6 +176,7 @@ impl<'self> PkgScript<'self> {
// FIXME (#9639): This needs to handle non-utf8 paths
let output = run::process_output(exe.as_str().unwrap(),
[sysroot.as_str().unwrap().to_owned(), ~"configs"]);
debug!("run_custom: second pkg command did {:?}", output.status);
// Run the configs() function to get the configs
let cfgs = str::from_utf8_slice(output.output).word_iter()
.map(|w| w.to_owned()).collect();
@ -263,7 +270,7 @@ impl CtxMethods for BuildContext {
let cwd = os::getcwd();
match cmd {
"build" => {
self.build_args(args, &Everything);
self.build_args(args, &WhatToBuild::new(MaybeCustom, Everything));
}
"clean" => {
if args.len() < 1 {
@ -301,12 +308,14 @@ impl CtxMethods for BuildContext {
let inferred_pkgid =
PkgId::new(cwd.filename_str().unwrap());
self.install(PkgSrc::new(cwd, default_workspace(),
true, inferred_pkgid), &Everything);
true, inferred_pkgid),
&WhatToBuild::new(MaybeCustom, Everything));
}
None => { usage::install(); return; }
Some((ws, pkgid)) => {
let pkg_src = PkgSrc::new(ws.clone(), ws.clone(), false, pkgid);
self.install(pkg_src, &Everything);
self.install(pkg_src, &WhatToBuild::new(MaybeCustom,
Everything));
}
}
}
@ -320,7 +329,7 @@ impl CtxMethods for BuildContext {
if workspaces.is_empty() {
let d = default_workspace();
let src = PkgSrc::new(d.clone(), d, false, pkgid.clone());
self.install(src, &Everything);
self.install(src, &WhatToBuild::new(MaybeCustom, Everything));
}
else {
for workspace in workspaces.iter() {
@ -331,7 +340,7 @@ impl CtxMethods for BuildContext {
dest,
self.context.use_rust_path_hack,
pkgid.clone());
self.install(src, &Everything);
self.install(src, &WhatToBuild::new(MaybeCustom, Everything));
};
}
}
@ -354,7 +363,8 @@ impl CtxMethods for BuildContext {
}
"test" => {
// Build the test executable
let maybe_id_and_workspace = self.build_args(args, &Tests);
let maybe_id_and_workspace = self.build_args(args,
&WhatToBuild::new(MaybeCustom, Tests));
match maybe_id_and_workspace {
Some((pkg_id, workspace)) => {
// Assuming it's built, run the tests
@ -420,6 +430,7 @@ impl CtxMethods for BuildContext {
pkgid = {} pkgsrc start_dir = {}", workspace.display(),
in_rust_path(&workspace), is_git_dir(&workspace.join(&pkgid.path)),
pkgid.to_str(), pkg_src.start_dir.display());
debug!("build: what to build = {:?}", what_to_build);
// If workspace isn't in the RUST_PATH, and it's a git repo,
// then clone it into the first entry in RUST_PATH, and repeat
@ -448,27 +459,27 @@ impl CtxMethods for BuildContext {
debug!("Package source directory = {}", pkg_src.to_str());
let opt = pkg_src.package_script_option();
debug!("Calling pkg_script_option on {:?}", opt);
let cfgs = match pkg_src.package_script_option() {
Some(package_script_path) => {
let cfgs = match (pkg_src.package_script_option(), what_to_build.build_type) {
(Some(package_script_path), MaybeCustom) => {
let sysroot = self.sysroot_to_use();
// FIXME (#9639): This needs to handle non-utf8 paths
let pkg_script_path_str = package_script_path.as_str().unwrap();
let (cfgs, hook_result) =
do self.workcache_context.with_prep(pkg_script_path_str) |prep| {
let sub_sysroot = sysroot.clone();
let package_script_path_clone = package_script_path.clone();
let sub_ws = workspace.clone();
let sub_id = pkgid.clone();
declare_package_script_dependency(prep, &*pkg_src);
// Build the package script if needed
let script_build = format!("build_package_script({})",
package_script_path.display());
let pkg_exe = do self.workcache_context.with_prep(script_build) |prep| {
let subsysroot = sysroot.clone();
let psp = package_script_path.clone();
let ws = workspace.clone();
let pid = pkgid.clone();
do prep.exec |exec| {
let mut pscript = PkgScript::parse(@sub_sysroot.clone(),
package_script_path_clone.clone(),
&sub_ws,
&sub_id);
pscript.run_custom(exec, &sub_sysroot)
let mut pscript = PkgScript::parse(subsysroot.clone(),
psp.clone(),
&ws,
&pid);
pscript.build_custom(exec)
}
};
// We always *run* the package script
let (cfgs, hook_result) = PkgScript::run_custom(&Path::new(pkg_exe), &sysroot);
debug!("Command return code = {:?}", hook_result);
if hook_result != 0 {
fail!("Error running custom build command")
@ -477,7 +488,11 @@ impl CtxMethods for BuildContext {
// otherwise, the package script succeeded
cfgs
}
None => {
(Some(_), Inferred) => {
debug!("There is a package script, but we're ignoring it");
~[]
}
(None, _) => {
debug!("No package script, continuing");
~[]
}
@ -486,13 +501,13 @@ impl CtxMethods for BuildContext {
// If there was a package script, it should have finished
// the build already. Otherwise...
if !custom {
match what_to_build {
match what_to_build.sources {
// Find crates inside the workspace
&Everything => pkg_src.find_crates(),
Everything => pkg_src.find_crates(),
// Find only tests
&Tests => pkg_src.find_crates_with_filter(|s| { is_test(&Path::new(s)) }),
Tests => pkg_src.find_crates_with_filter(|s| { is_test(&Path::new(s)) }),
// Don't infer any crates -- just build the one that was requested
&JustOne(ref p) => {
JustOne(ref p) => {
// We expect that p is relative to the package source's start directory,
// so check that assumption
debug!("JustOne: p = {}", p.display());
@ -512,7 +527,7 @@ impl CtxMethods for BuildContext {
}
}
// Build it!
pkg_src.build(self, cfgs);
pkg_src.build(self, cfgs, []);
}
}
@ -551,6 +566,8 @@ impl CtxMethods for BuildContext {
// just means inferring all the crates in it, then building each one.
self.build(&mut pkg_src, what);
debug!("Done building package source {}", pkg_src.to_str());
let to_do = ~[pkg_src.libs.clone(), pkg_src.mains.clone(),
pkg_src.tests.clone(), pkg_src.benchs.clone()];
debug!("In declare inputs for {}", id.to_str());
@ -823,6 +840,7 @@ pub fn main_args(args: &[~str]) -> int {
save_temps: save_temps,
target: target,
target_cpu: target_cpu,
additional_library_paths: ~[], // No way to set this from the rustpkg command line
experimental_features: experimental_features
};
@ -895,7 +913,8 @@ pub fn main_args(args: &[~str]) -> int {
use_rust_path_hack: use_rust_path_hack,
sysroot: sroot.clone(), // Currently, only tests override this
},
workcache_context: api::default_context(default_workspace()).workcache_context
workcache_context: api::default_context(sroot.clone(),
default_workspace()).workcache_context
}.run(sub_cmd, rm_args.clone())
};
// FIXME #9262: This is using the same error code for all errors,

View file

@ -23,7 +23,31 @@ pub enum Target {
}
#[deriving(Eq, Clone)]
pub enum WhatToBuild {
pub struct WhatToBuild {
build_type: BuildType, // Whether or not to ignore the pkg.rs file
sources: SourceType, // Which crates to build
inputs_to_discover: ~[(~str, Path)] // Inputs to these crates to be discovered
// (For now all of these inputs will be taken as discovered inputs
// for all of the crates)
// (Paired with their kinds)
}
impl WhatToBuild {
pub fn new(build_type: BuildType, sources: SourceType) -> WhatToBuild {
WhatToBuild { build_type: build_type,
sources: sources,
inputs_to_discover: ~[] }
}
}
#[deriving(Eq, Clone)]
pub enum BuildType {
Inferred, // Ignore the pkg.rs file even if one exists
MaybeCustom // Use the pkg.rs file if it exists
}
#[deriving(Eq, Clone)]
pub enum SourceType {
/// Build just one lib.rs file in `path`, which is relative to the active workspace's src/ dir
JustOne(Path),
/// Build any test.rs files that can be recursively found in the active workspace

View file

@ -28,7 +28,7 @@ use path_util::{target_executable_in_workspace, target_test_in_workspace,
library_in_workspace, installed_library_in_workspace,
built_bench_in_workspace, built_test_in_workspace,
built_library_in_workspace, built_executable_in_workspace, target_build_dir,
chmod_read_only};
chmod_read_only, platform_library_name};
use rustc::back::link::get_cc_prog;
use rustc::metadata::filesearch::rust_path;
use rustc::driver::driver::{build_session, build_session_options, host_triple, optgroups};
@ -299,12 +299,6 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s
cmd, args, str::from_utf8(output.output),
str::from_utf8(output.error),
output.status);
/*
By the way, rustpkg *won't* return a nonzero exit code if it fails --
see #4547
So tests that use this need to check the existence of a file
to make sure the command succeeded
*/
if output.status != 0 {
debug!("Command {} {:?} failed with exit code {:?}; its output was --- {} ---",
cmd, args, output.status,
@ -600,7 +594,7 @@ fn test_install_valid() {
temp_workspace.clone(),
false,
temp_pkg_id.clone());
ctxt.install(src, &Everything);
ctxt.install(src, &WhatToBuild::new(MaybeCustom, Everything));
// Check that all files exist
let exec = target_executable_in_workspace(&temp_pkg_id, temp_workspace);
debug!("exec = {}", exec.display());
@ -639,7 +633,7 @@ fn test_install_invalid() {
temp_workspace.clone(),
false,
pkgid.clone());
ctxt.install(pkg_src, &Everything);
ctxt.install(pkg_src, &WhatToBuild::new(MaybeCustom, Everything));
};
// Not the best test -- doesn't test that we failed in the right way.
// Best we can do for now.
@ -897,14 +891,14 @@ fn rustpkg_local_pkg() {
}
#[test]
#[ignore (reason = "test makes bogus assumptions about build directory layout: issue #8690")]
fn package_script_with_default_build() {
let dir = create_local_package(&PkgId::new("fancy-lib"));
let dir = dir.path();
debug!("dir = {}", dir.display());
let mut source = test_sysroot().dir_path();
source.pop(); source.pop();
source.push_many(["src", "librustpkg", "testsuite", "pass", "src", "fancy-lib", "pkg.rs"]);
let source = Path::new(file!()).dir_path().join_many(
[~"testsuite", ~"pass", ~"src", ~"fancy-lib", ~"pkg.rs"]);
debug!("package_script_with_default_build: {}", source.display());
if !os::copy_file(&source,
&dir.join_many(["src", "fancy-lib-0.1", "pkg.rs"])) {
@ -912,7 +906,10 @@ fn package_script_with_default_build() {
}
command_line_test([~"install", ~"fancy-lib"], dir);
assert_lib_exists(dir, &Path::new("fancy-lib"), NoVersion);
assert!(os::path_exists(&target_build_dir(dir).join_many(["fancy-lib", "generated.rs"])));
assert!(os::path_exists(&target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"])));
let generated_path = target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"]);
debug!("generated path = {}", generated_path.display());
assert!(os::path_exists(&generated_path));
}
#[test]
@ -2251,6 +2248,106 @@ fn find_sources_in_cwd() {
assert_executable_exists(&source_dir.join(".rust"), "foo");
}
#[test]
fn test_c_dependency_ok() {
// Pkg has a custom build script that adds a single C file as a dependency, and
// registers a hook to build it if it's not fresh
// After running `build`, test that the C library built
let dir = create_local_package(&PkgId::new("cdep"));
let dir = dir.path();
writeFile(&dir.join_many(["src", "cdep-0.1", "main.rs"]),
"#[link_args = \"-lfoo\"]\nextern { fn f(); } \
\n#[fixed_stack_segment]\nfn main() { unsafe { f(); } }");
writeFile(&dir.join_many(["src", "cdep-0.1", "foo.c"]), "void f() {}");
debug!("dir = {}", dir.display());
let source = Path::new(file!()).dir_path().join_many(
[~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]);
if !os::copy_file(&source,
&dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])) {
fail!("Couldn't copy file");
}
command_line_test([~"build", ~"cdep"], dir);
assert_executable_exists(dir, "cdep");
let out_dir = target_build_dir(dir).join("cdep");
let c_library_path = out_dir.join(platform_library_name("foo"));
debug!("c library path: {}", c_library_path.display());
assert!(os::path_exists(&c_library_path));
}
#[test]
fn test_c_dependency_no_rebuilding() {
let dir = create_local_package(&PkgId::new("cdep"));
let dir = dir.path();
writeFile(&dir.join_many(["src", "cdep-0.1", "main.rs"]),
"#[link_args = \"-lfoo\"]\nextern { fn f(); } \
\n#[fixed_stack_segment]\nfn main() { unsafe { f(); } }");
writeFile(&dir.join_many(["src", "cdep-0.1", "foo.c"]), "void f() {}");
debug!("dir = {}", dir.display());
let source = Path::new(file!()).dir_path().join_many(
[~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]);
if !os::copy_file(&source,
&dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])) {
fail!("Couldn't copy file");
}
command_line_test([~"build", ~"cdep"], dir);
assert_executable_exists(dir, "cdep");
let out_dir = target_build_dir(dir).join("cdep");
let c_library_path = out_dir.join(platform_library_name("foo"));
debug!("c library path: {}", c_library_path.display());
assert!(os::path_exists(&c_library_path));
// Now, make it read-only so rebuilding will fail
assert!(chmod_read_only(&c_library_path));
match command_line_test_partial([~"build", ~"cdep"], dir) {
Success(*) => (), // ok
Fail(status) if status == 65 => fail!("test_c_dependency_no_rebuilding failed: \
it tried to rebuild foo.c"),
Fail(_) => fail!("test_c_dependency_no_rebuilding failed for some other reason")
}
}
#[test]
fn test_c_dependency_yes_rebuilding() {
let dir = create_local_package(&PkgId::new("cdep"));
let dir = dir.path();
writeFile(&dir.join_many(["src", "cdep-0.1", "main.rs"]),
"#[link_args = \"-lfoo\"]\nextern { fn f(); } \
\n#[fixed_stack_segment]\nfn main() { unsafe { f(); } }");
let c_file_name = dir.join_many(["src", "cdep-0.1", "foo.c"]);
writeFile(&c_file_name, "void f() {}");
let source = Path::new(file!()).dir_path().join_many(
[~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]);
let target = dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"]);
debug!("Copying {} -> {}", source.display(), target.display());
if !os::copy_file(&source, &target) {
fail!("Couldn't copy file");
}
command_line_test([~"build", ~"cdep"], dir);
assert_executable_exists(dir, "cdep");
let out_dir = target_build_dir(dir).join("cdep");
let c_library_path = out_dir.join(platform_library_name("foo"));
debug!("c library path: {}", c_library_path.display());
assert!(os::path_exists(&c_library_path));
// Now, make the Rust library read-only so rebuilding will fail
match built_library_in_workspace(&PkgId::new("cdep"), dir) {
Some(ref pth) => assert!(chmod_read_only(pth)),
None => assert_built_library_exists(dir, "cdep")
}
match command_line_test_partial([~"build", ~"cdep"], dir) {
Success(*) => fail!("test_c_dependency_yes_rebuilding failed: \
it didn't rebuild and should have"),
Fail(status) if status == 65 => (),
Fail(_) => fail!("test_c_dependency_yes_rebuilding failed for some other reason")
}
}
/// Returns true if p exists and is executable
fn is_executable(p: &Path) -> bool {
use std::libc::consts::os::posix88::{S_IXUSR};

View file

@ -0,0 +1,13 @@
// 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.
pub fn assert_true() {
assert!(true);
}

View file

@ -0,0 +1,12 @@
// 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.
pub fn do_nothing() {
}

View file

@ -0,0 +1,14 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern mod std;
pub mod foo;
pub mod bar;

View file

@ -0,0 +1,83 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern mod rustpkg;
extern mod rustc;
use std::{io, os, task};
use rustpkg::api;
use rustpkg::version::NoVersion;
use rustpkg::workcache_support::digest_file_with_date;
use rustpkg::exit_codes::COPY_FAILED_CODE;
pub fn main() {
let args = os::args();
// by convention, first arg is sysroot
if args.len() < 2 {
fail!("Package script requires a directory where rustc libraries live as the first \
argument");
}
let path_for_db = api::default_workspace();
debug!("path_for_db = {}", path_for_db.display());
let sysroot_arg = args[1].clone();
let sysroot = Path::new(sysroot_arg);
if !os::path_exists(&sysroot) {
fail!("Package script requires a sysroot that exists; {} doesn't", sysroot.display());
}
if args[2] != ~"install" {
io::println(format!("Warning: I don't know how to {}", args[2]));
return;
}
let mut context = api::default_context(sysroot, path_for_db);
let my_workspace = api::my_workspace(&context.context, "cdep");
let foo_c_name = my_workspace.join_many(["src", "cdep-0.1", "foo.c"]);
let out_lib_path = do context.workcache_context.with_prep("foo.c") |prep| {
let sub_cx = context.context.clone();
debug!("foo_c_name = {}", foo_c_name.display());
prep.declare_input("file",
foo_c_name.as_str().unwrap().to_owned(),
digest_file_with_date(&foo_c_name));
let out_path = do prep.exec |exec| {
let out_path = api::build_library_in_workspace(exec,
&mut sub_cx.clone(),
"cdep",
"gcc",
[~"-c"],
[~"foo.c"],
"foo");
let out_p = Path::new(out_path);
out_p.as_str().unwrap().to_owned()
};
out_path
};
let out_lib_path = Path::new(out_lib_path);
debug!("out_lib_path = {}", out_lib_path.display());
context.add_library_path(out_lib_path.dir_path());
let context_clone = context.clone();
let task_res = do task::try {
let mut cc = context_clone.clone();
api::install_pkg(&mut cc,
os::getcwd(),
~"cdep",
NoVersion,
~[(~"binary", out_lib_path.clone()), (~"file", foo_c_name.clone())]);
};
if task_res.is_err() {
os::set_exit_status(COPY_FAILED_CODE);
}
}

View file

@ -21,4 +21,4 @@ extern mod std;
pub mod foo;
pub mod bar;
#[path = "../../build/fancy_lib/generated.rs"] pub mod generated;
#[path = "../../build/fancy-lib/generated.rs"] pub mod generated;

View file

@ -15,42 +15,37 @@ use std::{io, os};
use rustpkg::api;
use rustpkg::version::NoVersion;
use rustc::metadata::filesearch;
pub fn main() {
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
let args = os::args();
// by convention, first arg is sysroot
if args.len() < 2 {
debug!("Failing, arg len");
fail!("Package script requires a directory where rustc libraries live as the first \
argument");
}
let sysroot_arg = args[1].clone();
let sysroot = Path(sysroot_arg);
let sysroot = Path::new(sysroot_arg);
if !os::path_exists(&sysroot) {
fail!("Package script requires a sysroot that exists; %s doesn't", sysroot.to_str());
debug!("Failing, sysroot");
fail!("Package script requires a sysroot that exists;{} doesn't", sysroot.display());
}
if args[2] != ~"install" {
debug!("Failing, weird command");
println!("Warning: I don't know how to {}", args[2]);
return;
}
let out_path = Path("build/fancy-lib");
if !os::path_exists(&out_path) {
assert!(os::make_dir(&out_path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
}
debug!("Checking self_exe_path");
let out_path = os::self_exe_path().expect("Couldn't get self_exe path");
let file = io::file_writer(&out_path.push("generated.rs"),
[io::Create]).unwrap();
file.write_str("pub fn wheeeee() { for [1, 2, 3].each() |_| { assert!(true); } }");
debug!("Writing file");
let file = io::file_writer(&out_path.join("generated.rs"), [io::Create]).unwrap();
file.write_str("pub fn wheeeee() { let xs = [1, 2, 3]; \
for _ in xs.iter() { assert!(true); } }");
debug!("api_____install_____lib, my sysroot:");
debug!(sysroot.to_str());
api::install_lib(@sysroot, os::getcwd(), ~"fancy-lib", Path("lib.rs"),
NoVersion);
let context = api::default_context(sysroot, api::default_workspace());
api::install_pkg(&context, os::getcwd(), ~"fancy-lib", NoVersion, ~[]);
}

View file

@ -27,11 +27,13 @@ use context::{in_target, StopBefore, Link, Assemble, BuildContext};
use package_id::PkgId;
use package_source::PkgSrc;
use workspace::pkg_parent_workspaces;
use path_util::{U_RWX, system_library, target_build_dir};
use path_util::{system_library, target_build_dir};
use path_util::{default_workspace, built_library_in_workspace};
pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
pub use target::{Target, Build, Install};
use extra::treemap::TreeMap;
use path_util::U_RWX;
pub use target::{lib_name_of, lib_crate_filename, WhatToBuild, MaybeCustom, Inferred};
use workcache_support::{digest_file_with_date, digest_only_date};
// It would be nice to have the list of commands in just one place -- for example,
@ -233,12 +235,14 @@ pub fn compile_input(context: &BuildContext,
Nothing => link::output_type_exe
};
debug!("Output type = {:?}", output_type);
let options = @session::options {
crate_type: crate_type,
optimize: if opt { session::Aggressive } else { session::No },
test: what == Test || what == Bench,
maybe_sysroot: Some(sysroot_to_use),
addl_lib_search_paths: @mut (~[]),
addl_lib_search_paths: @mut context.additional_library_paths(),
output_type: output_type,
.. (*driver::build_session_options(binary,
&matches,
@ -246,6 +250,8 @@ pub fn compile_input(context: &BuildContext,
@diagnostic::Emitter)).clone()
};
debug!("Created options...");
let addl_lib_search_paths = @mut options.addl_lib_search_paths;
// Make sure all the library directories actually exist, since the linker will complain
// otherwise
@ -258,16 +264,22 @@ pub fn compile_input(context: &BuildContext,
}
}
debug!("About to build session...");
let sess = driver::build_session(options,
@diagnostic::DefaultEmitter as
@diagnostic::Emitter);
debug!("About to build config...");
// Infer dependencies that rustpkg needs to build, by scanning for
// `extern mod` directives.
let cfg = driver::build_configuration(sess);
let mut crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
crate = driver::phase_2_configure_and_expand(sess, cfg.clone(), crate);
debug!("About to call find_and_install_dependencies...");
find_and_install_dependencies(context, pkg_id, in_file, sess, exec, &crate, deps,
|p| {
debug!("a dependency: {}", p.display());
@ -377,7 +389,6 @@ pub fn compile_crate_from_input(input: &Path,
debug!("Built {}, date = {:?}", outputs.out_filename.display(),
datestamp(&outputs.out_filename));
Some(outputs.out_filename)
}
@ -431,7 +442,9 @@ impl<'self> Visitor<()> for ViewItemVisitor<'self> {
};
debug!("Finding and installing... {}", lib_name);
// Check standard Rust library path first
match system_library(&self.context.sysroot(), lib_name) {
let whatever = system_library(&self.context.sysroot(), lib_name);
debug!("system library returned {:?}", whatever);
match whatever {
Some(ref installed_path) => {
debug!("It exists: {}", installed_path.display());
// Say that [path for c] has a discovered dependency on
@ -478,7 +491,10 @@ impl<'self> Visitor<()> for ViewItemVisitor<'self> {
self.context.context.use_rust_path_hack,
pkg_id.clone());
let (outputs_disc, inputs_disc) =
self.context.install(pkg_src, &JustOne(Path::new(lib_crate_filename)));
self.context.install(
pkg_src,
&WhatToBuild::new(Inferred,
JustOne(Path::new(lib_crate_filename))));
debug!("Installed {}, returned {:?} dependencies and \
{:?} transitive dependencies",
lib_name, outputs_disc.len(), inputs_disc.len());

View file

@ -490,7 +490,6 @@ pub struct Formatter<'self> {
/// Output buffer.
buf: &'self mut io::Writer,
priv curarg: vec::VecIterator<'self, Argument<'self>>,
priv args: &'self [Argument<'self>],
}

View file

@ -1009,7 +1009,7 @@ impl<R:Reader,C> Reader for Wrapper<R, C> {
}
pub struct FILERes {
f: *libc::FILE,
priv f: *libc::FILE,
}
impl FILERes {
@ -1282,7 +1282,7 @@ impl Writer for fd_t {
}
pub struct FdRes {
fd: fd_t,
priv fd: fd_t,
}
impl FdRes {
@ -1792,7 +1792,7 @@ pub mod fsync {
// Artifacts that need to fsync on destruction
pub struct Res<t> {
arg: Arg<t>,
priv arg: Arg<t>,
}
impl <t> Res<t> {
@ -1815,9 +1815,9 @@ pub mod fsync {
}
pub struct Arg<t> {
val: t,
opt_level: Option<Level>,
fsync_fn: extern "Rust" fn(f: &t, Level) -> int,
priv val: t,
priv opt_level: Option<Level>,
priv fsync_fn: extern "Rust" fn(f: &t, Level) -> int,
}
// fsync file after executing blk

View file

@ -1790,9 +1790,9 @@ impl<'self, A, St> Iterator<A> for Unfold<'self, A, St> {
#[deriving(Clone)]
pub struct Counter<A> {
/// The current state the counter is at (next value to be yielded)
state: A,
priv state: A,
/// The amount that this iterator is stepping by
step: A
priv step: A
}
/// Creates a new counter with the specified start/step

View file

@ -8,38 +8,226 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Sampling from random distributions
/*!
Sampling from random distributions.
// Some implementations use the Ziggurat method
// https://en.wikipedia.org/wiki/Ziggurat_algorithm
//
// The version used here is ZIGNOR [Doornik 2005, "An Improved
// Ziggurat Method to Generate Normal Random Samples"] which is slower
// (about double, it generates an extra random number) than the
// canonical version [Marsaglia & Tsang 2000, "The Ziggurat Method for
// Generating Random Variables"], but more robust. If one wanted, one
// could implement VIZIGNOR the ZIGNOR paper for more speed.
This is a generalization of `Rand` to allow parameters to control the
exact properties of the generated values, e.g. the mean and standard
deviation of a normal distribution. The `Sample` trait is the most
general, and allows for generating values that change some state
internally. The `IndependentSample` trait is for generating values
that do not need to record state.
*/
use iter::range;
use option::{Some, None};
use num;
use rand::{Rng,Rand};
use clone::Clone;
pub use self::range::Range;
pub mod range;
/// Types that can be used to create a random instance of `Support`.
pub trait Sample<Support> {
/// Generate a random value of `Support`, using `rng` as the
/// source of randomness.
fn sample<R: Rng>(&mut self, rng: &mut R) -> Support;
}
/// `Sample`s that do not require keeping track of state.
///
/// Since no state is recored, each sample is (statistically)
/// independent of all others, assuming the `Rng` used has this
/// property.
// XXX maybe having this separate is overkill (the only reason is to
// take &self rather than &mut self)? or maybe this should be the
// trait called `Sample` and the other should be `DependentSample`.
pub trait IndependentSample<Support>: Sample<Support> {
/// Generate a random value.
fn ind_sample<R: Rng>(&self, &mut R) -> Support;
}
/// A wrapper for generating types that implement `Rand` via the
/// `Sample` & `IndependentSample` traits.
pub struct RandSample<Sup>;
impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
}
impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
rng.gen()
}
}
/// A value with a particular weight for use with `WeightedChoice`.
pub struct Weighted<T> {
/// The numerical weight of this item
weight: uint,
/// The actual item which is being weighted
item: T,
}
/// A distribution that selects from a finite collection of weighted items.
///
/// Each item has an associated weight that influences how likely it
/// is to be chosen: higher weight is more likely.
///
/// The `Clone` restriction is a limitation of the `Sample` and
/// `IndepedentSample` traits. Note that `&T` is (cheaply) `Clone` for
/// all `T`, as is `uint`, so one can store references or indices into
/// another vector.
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::distributions::{Weighted, WeightedChoice, IndepedentSample};
///
/// fn main() {
/// let wc = WeightedChoice::new(~[Weighted { weight: 2, item: 'a' },
/// Weighted { weight: 4, item: 'b' },
/// Weighted { weight: 1, item: 'c' }]);
/// let rng = rand::task_rng();
/// for _ in range(0, 16) {
/// // on average prints 'a' 4 times, 'b' 8 and 'c' twice.
/// println!("{}", wc.ind_sample(rng));
/// }
/// }
/// ```
pub struct WeightedChoice<T> {
priv items: ~[Weighted<T>],
priv weight_range: Range<uint>
}
impl<T: Clone> WeightedChoice<T> {
/// Create a new `WeightedChoice`.
///
/// Fails if:
/// - `v` is empty
/// - the total weight is 0
/// - the total weight is larger than a `uint` can contain.
pub fn new(mut items: ~[Weighted<T>]) -> WeightedChoice<T> {
// strictly speaking, this is subsumed by the total weight == 0 case
assert!(!items.is_empty(), "WeightedChoice::new called with no items");
let mut running_total = 0u;
// we convert the list from individual weights to cumulative
// weights so we can binary search. This *could* drop elements
// with weight == 0 as an optimisation.
for item in items.mut_iter() {
running_total = running_total.checked_add(&item.weight)
.expect("WeightedChoice::new called with a total weight larger \
than a uint can contain");
item.weight = running_total;
}
assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0");
WeightedChoice {
items: items,
// we're likely to be generating numbers in this range
// relatively often, so might as well cache it
weight_range: Range::new(0, running_total)
}
}
}
impl<T: Clone> Sample<T> for WeightedChoice<T> {
fn sample<R: Rng>(&mut self, rng: &mut R) -> T { self.ind_sample(rng) }
}
impl<T: Clone> IndependentSample<T> for WeightedChoice<T> {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> T {
// we want to find the first element that has cumulative
// weight > sample_weight, which we do by binary since the
// cumulative weights of self.items are sorted.
// choose a weight in [0, total_weight)
let sample_weight = self.weight_range.ind_sample(rng);
// short circuit when it's the first item
if sample_weight < self.items[0].weight {
return self.items[0].item.clone();
}
let mut idx = 0;
let mut modifier = self.items.len();
// now we know that every possibility has an element to the
// left, so we can just search for the last element that has
// cumulative weight <= sample_weight, then the next one will
// be "it". (Note that this greatest element will never be the
// last element of the vector, since sample_weight is chosen
// in [0, total_weight) and the cumulative weight of the last
// one is exactly the total weight.)
while modifier > 1 {
let i = idx + modifier / 2;
if self.items[i].weight <= sample_weight {
// we're small, so look to the right, but allow this
// exact element still.
idx = i;
// we need the `/ 2` to round up otherwise we'll drop
// the trailing elements when `modifier` is odd.
modifier += 1;
} else {
// otherwise we're too big, so go left. (i.e. do
// nothing)
}
modifier /= 2;
}
return self.items[idx + 1].item.clone();
}
}
mod ziggurat_tables;
// inlining should mean there is no performance penalty for this
#[inline]
/// Sample a random number using the Ziggurat method (specifically the
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
/// directly from the paper:
///
/// * `rng`: source of randomness
/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
/// * `X`: the $x_i$ abscissae.
/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
/// * `pdf`: the probability density function
/// * `zero_case`: manual sampling from the tail when we chose the
/// bottom box (i.e. i == 0)
// the perf improvement (25-50%) is definitely worth the extra code
// size from force-inlining.
#[inline(always)]
fn ziggurat<R:Rng>(rng: &mut R,
center_u: bool,
symmetric: bool,
X: ziggurat_tables::ZigTable,
F: ziggurat_tables::ZigTable,
F_DIFF: ziggurat_tables::ZigTable,
pdf: &'static fn(f64) -> f64, // probability density function
pdf: &'static fn(f64) -> f64,
zero_case: &'static fn(&mut R, f64) -> f64) -> f64 {
static SCALE: f64 = (1u64 << 53) as f64;
loop {
let u = if center_u {2.0 * rng.gen() - 1.0} else {rng.gen()};
let i: uint = rng.gen::<uint>() & 0xff;
// reimplement the f64 generation as an optimisation suggested
// by the Doornik paper: we have a lot of precision-space
// (i.e. there are 11 bits of the 64 of a u64 to use after
// creating a f64), so we might as well reuse some to save
// generating a whole extra random number. (Seems to be 15%
// faster.)
let bits: u64 = rng.gen();
let i = (bits & 0xff) as uint;
let f = (bits >> 11) as f64 / SCALE;
// u is either U(-1, 1) or U(0, 1) depending on if this is a
// symmetric distribution or not.
let u = if symmetric {2.0 * f - 1.0} else {f};
let x = u * X[i];
let test_x = if center_u {num::abs(x)} else {x};
let test_x = if symmetric {num::abs(x)} else {x};
// algebraically equivalent to |u| < X[i+1]/X[i] (or u < X[i+1]/X[i])
if test_x < X[i + 1] {
@ -49,30 +237,25 @@ fn ziggurat<R:Rng>(rng: &mut R,
return zero_case(rng, u);
}
// algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
if F[i+1] + F_DIFF[i+1] * rng.gen() < pdf(x) {
if F[i + 1] + F_DIFF[i + 1] * rng.gen() < pdf(x) {
return x;
}
}
}
/// A wrapper around an `f64` to generate N(0, 1) random numbers (a.k.a. a
/// standard normal, or Gaussian). Multiplying the generated values by the
/// desired standard deviation `sigma` then adding the desired mean `mu` will
/// give N(mu, sigma^2) distributed random numbers.
/// A wrapper around an `f64` to generate N(0, 1) random numbers
/// (a.k.a. a standard normal, or Gaussian).
///
/// Note that this has to be unwrapped before use as an `f64` (using either
/// `*` or `cast::transmute` is safe).
/// See `Normal` for the general normal distribution. That this has to
/// be unwrapped before use as an `f64` (using either `*` or
/// `cast::transmute` is safe).
///
/// # Example
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method.
///
/// ```
/// use std::rand::distributions::StandardNormal;
///
/// fn main() {
/// let normal = 2.0 + (*rand::random::<StandardNormal>()) * 3.0;
/// println!("{} is from a N(2, 9) distribution", normal)
/// }
/// ```
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
/// Generate Normal Random
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
/// College, Oxford
pub struct StandardNormal(f64);
impl Rand for StandardNormal {
@ -110,23 +293,62 @@ impl Rand for StandardNormal {
}
}
/// A wrapper around an `f64` to generate Exp(1) random numbers. Dividing by
/// the desired rate `lambda` will give Exp(lambda) distributed random
/// numbers.
/// The normal distribution `N(mean, std_dev**2)`.
///
/// Note that this has to be unwrapped before use as an `f64` (using either
/// `*` or `cast::transmute` is safe).
/// This uses the ZIGNOR variant of the Ziggurat method, see
/// `StandardNormal` for more details.
///
/// # Example
///
/// ```
/// use std::rand::distributions::Exp1;
/// use std::rand;
/// use std::rand::distributions::{Normal, IndependentSample};
///
/// fn main() {
/// let exp2 = (*rand::random::<Exp1>()) * 0.5;
/// println!("{} is from a Exp(2) distribution", exp2);
/// let normal = Normal::new(2.0, 3.0);
/// let v = normal.ind_sample(rand::task_rng());
/// println!("{} is from a N(2, 9) distribution", v)
/// }
/// ```
pub struct Normal {
priv mean: f64,
priv std_dev: f64
}
impl Normal {
/// Construct a new `Normal` distribution with the given mean and
/// standard deviation. Fails if `std_dev < 0`.
pub fn new(mean: f64, std_dev: f64) -> Normal {
assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0");
Normal {
mean: mean,
std_dev: std_dev
}
}
}
impl Sample<f64> for Normal {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for Normal {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
self.mean + self.std_dev * (*rng.gen::<StandardNormal>())
}
}
/// A wrapper around an `f64` to generate Exp(1) random numbers.
///
/// See `Exp` for the general exponential distribution.Note that this
// has to be unwrapped before use as an `f64` (using either
/// `*` or `cast::transmute` is safe).
///
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The
/// exact description in the paper was adjusted to use tables for the
/// exponential distribution rather than normal.
///
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
/// Generate Normal Random
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
/// College, Oxford
pub struct Exp1(f64);
// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
@ -148,3 +370,221 @@ impl Rand for Exp1 {
pdf, zero_case))
}
}
/// The exponential distribution `Exp(lambda)`.
///
/// This distribution has density function: `f(x) = lambda *
/// exp(-lambda * x)` for `x > 0`.
///
/// # Example
///
/// ```
/// use std::rand;
/// use std::rand::distributions::{Exp, IndependentSample};
///
/// fn main() {
/// let exp = Exp::new(2.0);
/// let v = exp.ind_sample(rand::task_rng());
/// println!("{} is from a Exp(2) distribution", v);
/// }
/// ```
pub struct Exp {
/// `lambda` stored as `1/lambda`, since this is what we scale by.
priv lambda_inverse: f64
}
impl Exp {
/// Construct a new `Exp` with the given shape parameter
/// `lambda`. Fails if `lambda <= 0`.
pub fn new(lambda: f64) -> Exp {
assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0");
Exp { lambda_inverse: 1.0 / lambda }
}
}
impl Sample<f64> for Exp {
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for Exp {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
(*rng.gen::<Exp1>()) * self.lambda_inverse
}
}
#[cfg(test)]
mod tests {
use rand::*;
use super::*;
use iter::range;
use option::{Some, None};
struct ConstRand(uint);
impl Rand for ConstRand {
fn rand<R: Rng>(_: &mut R) -> ConstRand {
ConstRand(0)
}
}
// 0, 1, 2, 3, ...
struct CountingRng { i: u32 }
impl Rng for CountingRng {
fn next_u32(&mut self) -> u32 {
self.i += 1;
self.i - 1
}
fn next_u64(&mut self) -> u64 {
self.next_u32() as u64
}
}
#[test]
fn test_rand_sample() {
let mut rand_sample = RandSample::<ConstRand>;
assert_eq!(*rand_sample.sample(task_rng()), 0);
assert_eq!(*rand_sample.ind_sample(task_rng()), 0);
}
#[test]
fn test_normal() {
let mut norm = Normal::new(10.0, 10.0);
let rng = task_rng();
for _ in range(0, 1000) {
norm.sample(rng);
norm.ind_sample(rng);
}
}
#[test]
#[should_fail]
fn test_normal_invalid_sd() {
Normal::new(10.0, -1.0);
}
#[test]
fn test_exp() {
let mut exp = Exp::new(10.0);
let rng = task_rng();
for _ in range(0, 1000) {
assert!(exp.sample(rng) >= 0.0);
assert!(exp.ind_sample(rng) >= 0.0);
}
}
#[test]
#[should_fail]
fn test_exp_invalid_lambda_zero() {
Exp::new(0.0);
}
#[test]
#[should_fail]
fn test_exp_invalid_lambda_neg() {
Exp::new(-10.0);
}
#[test]
fn test_weighted_choice() {
// this makes assumptions about the internal implementation of
// WeightedChoice, specifically: it doesn't reorder the items,
// it doesn't do weird things to the RNG (so 0 maps to 0, 1 to
// 1, internally; modulo a modulo operation).
macro_rules! t (
($items:expr, $expected:expr) => {{
let wc = WeightedChoice::new($items);
let expected = $expected;
let mut rng = CountingRng { i: 0 };
for &val in expected.iter() {
assert_eq!(wc.ind_sample(&mut rng), val)
}
}}
);
t!(~[Weighted { weight: 1, item: 10}], ~[10]);
// skip some
t!(~[Weighted { weight: 0, item: 20},
Weighted { weight: 2, item: 21},
Weighted { weight: 0, item: 22},
Weighted { weight: 1, item: 23}],
~[21,21, 23]);
// different weights
t!(~[Weighted { weight: 4, item: 30},
Weighted { weight: 3, item: 31}],
~[30,30,30,30, 31,31,31]);
// check that we're binary searching
// correctly with some vectors of odd
// length.
t!(~[Weighted { weight: 1, item: 40},
Weighted { weight: 1, item: 41},
Weighted { weight: 1, item: 42},
Weighted { weight: 1, item: 43},
Weighted { weight: 1, item: 44}],
~[40, 41, 42, 43, 44]);
t!(~[Weighted { weight: 1, item: 50},
Weighted { weight: 1, item: 51},
Weighted { weight: 1, item: 52},
Weighted { weight: 1, item: 53},
Weighted { weight: 1, item: 54},
Weighted { weight: 1, item: 55},
Weighted { weight: 1, item: 56}],
~[50, 51, 52, 53, 54, 55, 56]);
}
#[test] #[should_fail]
fn test_weighted_choice_no_items() {
WeightedChoice::<int>::new(~[]);
}
#[test] #[should_fail]
fn test_weighted_choice_zero_weight() {
WeightedChoice::new(~[Weighted { weight: 0, item: 0},
Weighted { weight: 0, item: 1}]);
}
#[test] #[should_fail]
fn test_weighted_choice_weight_overflows() {
let x = (-1) as uint / 2; // x + x + 2 is the overflow
WeightedChoice::new(~[Weighted { weight: x, item: 0 },
Weighted { weight: 1, item: 1 },
Weighted { weight: x, item: 2 },
Weighted { weight: 1, item: 3 }]);
}
}
#[cfg(test)]
mod bench {
use extra::test::BenchHarness;
use rand::*;
use super::*;
use iter::range;
use option::{Some, None};
use mem::size_of;
static N: u64 = 100;
#[bench]
fn rand_normal(bh: &mut BenchHarness) {
let mut rng = XorShiftRng::new();
let mut normal = Normal::new(-2.71828, 3.14159);
do bh.iter {
for _ in range(0, N) {
normal.sample(&mut rng);
}
}
bh.bytes = size_of::<f64>() as u64 * N;
}
#[bench]
fn rand_exp(bh: &mut BenchHarness) {
let mut rng = XorShiftRng::new();
let mut exp = Exp::new(2.71828 * 3.14159);
do bh.iter {
for _ in range(0, N) {
exp.sample(&mut rng);
}
}
bh.bytes = size_of::<f64>() as u64 * N;
}
}

View file

@ -10,18 +10,24 @@
//! The ISAAC random number generator.
use cast;
use rand::{Rng, SeedableRng, OSRng};
use iter::{Iterator, range, range_step, Repeat};
use option::{None, Some};
use vec::raw;
use mem;
static RAND_SIZE_LEN: u32 = 8;
static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN;
/// A random number generator that uses the [ISAAC
/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29).
/// A random number generator that uses the ISAAC algorithm[1].
///
/// The ISAAC algorithm is suitable for cryptographic purposes.
/// The ISAAC algorithm is generally accepted as suitable for
/// cryptographic purposes, but this implementation has not be
/// verified as such. Prefer a generator like `OSRng` that defers to
/// the operating system for cases that need high security.
///
/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number
/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html)
pub struct IsaacRng {
priv cnt: u32,
priv rsl: [u32, .. RAND_SIZE],
@ -42,9 +48,12 @@ impl IsaacRng {
pub fn new() -> IsaacRng {
let mut rng = EMPTY;
{
let bytes = unsafe {cast::transmute::<&mut [u32], &mut [u8]>(rng.rsl)};
OSRng::new().fill_bytes(bytes);
unsafe {
let ptr = raw::to_mut_ptr(rng.rsl);
do raw::mut_buf_as_slice(ptr as *mut u8, mem::size_of_val(&rng.rsl)) |slice| {
OSRng::new().fill_bytes(slice);
}
}
rng.init(true);
@ -212,11 +221,16 @@ impl<'self> SeedableRng<&'self [u32]> for IsaacRng {
static RAND_SIZE_64_LEN: uint = 8;
static RAND_SIZE_64: uint = 1 << RAND_SIZE_64_LEN;
/// A random number generator that uses the 64-bit variant of the
/// [ISAAC
/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29).
/// A random number generator that uses ISAAC-64[1], the 64-bit
/// variant of the ISAAC algorithm.
///
/// The ISAAC algorithm is suitable for cryptographic purposes.
/// The ISAAC algorithm is generally accepted as suitable for
/// cryptographic purposes, but this implementation has not be
/// verified as such. Prefer a generator like `OSRng` that defers to
/// the operating system for cases that need high security.
///
/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number
/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html)
pub struct Isaac64Rng {
priv cnt: uint,
priv rsl: [u64, .. RAND_SIZE_64],
@ -238,10 +252,15 @@ impl Isaac64Rng {
/// seed.
pub fn new() -> Isaac64Rng {
let mut rng = EMPTY_64;
{
let bytes = unsafe {cast::transmute::<&mut [u64], &mut [u8]>(rng.rsl)};
OSRng::new().fill_bytes(bytes);
unsafe {
let ptr = raw::to_mut_ptr(rng.rsl);
do raw::mut_buf_as_slice(ptr as *mut u8, mem::size_of_val(&rng.rsl)) |slice| {
OSRng::new().fill_bytes(slice);
}
}
rng.init(true);
rng
}
@ -434,14 +453,14 @@ mod test {
#[test]
fn test_rng_32_seeded() {
let seed = &[2, 32, 4, 32, 51];
let seed = &[1, 23, 456, 7890, 12345];
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
}
#[test]
fn test_rng_64_seeded() {
let seed = &[2, 32, 4, 32, 51];
let seed = &[1, 23, 456, 7890, 12345];
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
@ -472,46 +491,46 @@ mod test {
#[test]
fn test_rng_32_true_values() {
let seed = &[2, 32, 4, 32, 51];
let seed = &[1, 23, 456, 7890, 12345];
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
// Regression test that isaac is actually using the above vector
let v = vec::from_fn(10, |_| ra.next_u32());
assert_eq!(v,
~[447462228, 2081944040, 3163797308, 2379916134, 2377489184,
1132373754, 536342443, 2995223415, 1265094839, 345325140]);
~[2558573138, 873787463, 263499565, 2103644246, 3595684709,
4203127393, 264982119, 2765226902, 2737944514, 3900253796]);
let seed = &[500, -4000, 123456, 9876543, 1, 1, 1, 1, 1];
let seed = &[12345, 67890, 54321, 9876];
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
// skip forward to the 10000th number
for _ in range(0, 10000) { rb.next_u32(); }
let v = vec::from_fn(10, |_| rb.next_u32());
assert_eq!(v,
~[612373032, 292987903, 1819311337, 3141271980, 422447569,
310096395, 1083172510, 867909094, 2478664230, 2073577855]);
~[3676831399, 3183332890, 2834741178, 3854698763, 2717568474,
1576568959, 3507990155, 179069555, 141456972, 2478885421]);
}
#[test]
fn test_rng_64_true_values() {
let seed = &[2, 32, 4, 32, 51];
let seed = &[1, 23, 456, 7890, 12345];
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
// Regression test that isaac is actually using the above vector
let v = vec::from_fn(10, |_| ra.next_u64());
assert_eq!(v,
~[15015576812873463115, 12461067598045625862, 14818626436142668771,
5562406406765984441, 11813289907965514161, 13443797187798420053,
6935026941854944442, 7750800609318664042, 14428747036317928637,
14028894460301215947]);
~[547121783600835980, 14377643087320773276, 17351601304698403469,
1238879483818134882, 11952566807690396487, 13970131091560099343,
4469761996653280935, 15552757044682284409, 6860251611068737823,
13722198873481261842]);
let seed = &[500, -4000, 123456, 9876543, 1, 1, 1, 1, 1];
let seed = &[12345, 67890, 54321, 9876];
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
// skip forward to the 10000th number
for _ in range(0, 10000) { rb.next_u64(); }
let v = vec::from_fn(10, |_| rb.next_u64());
assert_eq!(v,
~[13557216323596688637, 17060829581390442094, 4927582063811333743,
2699639759356482270, 4819341314392384881, 6047100822963614452,
11086255989965979163, 11901890363215659856, 5370800226050011580,
16496463556025356451]);
~[18143823860592706164, 8491801882678285927, 2699425367717515619,
17196852593171130876, 2606123525235546165, 15790932315217671084,
596345674630742204, 9947027391921273664, 11788097613744130851,
10391409374914919106]);
}
}

View file

@ -28,6 +28,23 @@ from an operating-system source of randomness, e.g. `/dev/urandom` on
Unix systems, and will automatically reseed itself from this source
after generating 32 KiB of random data.
# Cryptographic security
An application that requires random numbers for cryptographic purposes
should prefer `OSRng`, which reads randomness from one of the source
that the operating system provides (e.g. `/dev/urandom` on
Unixes). The other random number generators provided by this module
are either known to be insecure (`XorShiftRng`), or are not verified
to be secure (`IsaacRng`, `Isaac64Rng` and `StdRng`).
*Note*: on Linux, `/dev/random` is more secure than `/dev/urandom`,
but it is a blocking RNG, and will wait until it has determined that
it has collected enough entropy to fulfill a request for random
data. It can be used with the `Rng` trait provided by this module by
opening the file and passing it to `reader::ReaderRng`. Since it
blocks, `/dev/random` should only be used to retrieve small amounts of
randomness.
# Examples
```rust
@ -52,20 +69,21 @@ fn main () {
```
*/
use mem::size_of;
use unstable::raw::Slice;
use cast;
use cmp::Ord;
use container::Container;
use iter::{Iterator, range};
use local_data;
use prelude::*;
use str;
use u64;
use vec;
pub use self::isaac::{IsaacRng, Isaac64Rng};
pub use self::os::OSRng;
use self::distributions::{Range, IndependentSample};
use self::distributions::range::SampleRange;
pub mod distributions;
pub mod isaac;
pub mod os;
@ -80,14 +98,6 @@ pub trait Rand {
fn rand<R: Rng>(rng: &mut R) -> Self;
}
/// A value with a particular weight compared to other values
pub struct Weighted<T> {
/// The numerical weight of this item
weight: uint,
/// The actual item which is being weighted
item: T,
}
/// A random number generator
pub trait Rng {
/// Return the next random u32. This rarely needs to be called
@ -136,46 +146,26 @@ pub trait Rng {
/// }
/// ```
fn fill_bytes(&mut self, dest: &mut [u8]) {
let mut slice: Slice<u64> = unsafe { cast::transmute_copy(&dest) };
slice.len /= size_of::<u64>();
let as_u64: &mut [u64] = unsafe { cast::transmute(slice) };
for dest in as_u64.mut_iter() {
*dest = self.next_u64();
}
// the above will have filled up the vector as much as
// possible in multiples of 8 bytes.
let mut remaining = dest.len() % 8;
// space for a u32
if remaining >= 4 {
let mut slice: Slice<u32> = unsafe { cast::transmute_copy(&dest) };
slice.len /= size_of::<u32>();
let as_u32: &mut [u32] = unsafe { cast::transmute(slice) };
as_u32[as_u32.len() - 1] = self.next_u32();
remaining -= 4;
}
// exactly filled
if remaining == 0 { return }
// now we know we've either got 1, 2 or 3 spots to go,
// i.e. exactly one u32 is enough.
let rand = self.next_u32();
let remaining_index = dest.len() - remaining;
match dest.mut_slice_from(remaining_index) {
[ref mut a] => {
*a = rand as u8;
// this could, in theory, be done by transmuting dest to a
// [u64], but this is (1) likely to be undefined behaviour for
// LLVM, (2) has to be very careful about alignment concerns,
// (3) adds more `unsafe` that needs to be checked, (4)
// probably doesn't give much performance gain if
// optimisations are on.
let mut count = 0;
let mut num = 0;
for byte in dest.mut_iter() {
if count == 0 {
// we could micro-optimise here by generating a u32 if
// we only need a few more bytes to fill the vector
// (i.e. at most 4).
num = self.next_u64();
count = 8;
}
[ref mut a, ref mut b] => {
*a = rand as u8;
*b = (rand >> 8) as u8;
}
[ref mut a, ref mut b, ref mut c] => {
*a = rand as u8;
*b = (rand >> 8) as u8;
*c = (rand >> 16) as u8;
}
_ => fail!("Rng.fill_bytes: the impossible occurred: remaining != 1, 2 or 3")
*byte = (num & 0xff) as u8;
num >>= 8;
count -= 1;
}
}
@ -218,14 +208,14 @@ pub trait Rng {
vec::from_fn(len, |_| self.gen())
}
/// Generate a random primitive integer in the range [`low`,
/// `high`). Fails if `low >= high`.
/// Generate a random value in the range [`low`, `high`). Fails if
/// `low >= high`.
///
/// This gives a uniform distribution (assuming this RNG is itself
/// uniform), even for edge cases like `gen_integer_range(0u8,
/// 170)`, which a naive modulo operation would return numbers
/// less than 85 with double the probability to those greater than
/// 85.
/// This is a convenience wrapper around
/// `distributions::Range`. If this function will be called
/// repeatedly with the same arguments, one should use `Range`, as
/// that will amortize the computations that allow for perfect
/// uniformity, as they only happen on initialization.
///
/// # Example
///
@ -235,22 +225,15 @@ pub trait Rng {
///
/// fn main() {
/// let mut rng = rand::task_rng();
/// let n: uint = rng.gen_integer_range(0u, 10);
/// let n: uint = rng.gen_range(0u, 10);
/// println!("{}", n);
/// let m: int = rng.gen_integer_range(-40, 400);
/// let m: float = rng.gen_range(-40.0, 1.3e5);
/// println!("{}", m);
/// }
/// ```
fn gen_integer_range<T: Rand + Int>(&mut self, low: T, high: T) -> T {
assert!(low < high, "RNG.gen_integer_range called with low >= high");
let range = (high - low).to_u64().unwrap();
let accept_zone = u64::max_value - u64::max_value % range;
loop {
let rand = self.gen::<u64>();
if rand < accept_zone {
return low + NumCast::from(rand % range).unwrap();
}
}
fn gen_range<T: Ord + SampleRange>(&mut self, low: T, high: T) -> T {
assert!(low < high, "Rng.gen_range called with low >= high");
Range::new(low, high).ind_sample(self)
}
/// Return a bool with a 1 in n chance of true
@ -267,7 +250,7 @@ pub trait Rng {
/// }
/// ```
fn gen_weighted_bool(&mut self, n: uint) -> bool {
n == 0 || self.gen_integer_range(0, n) == 0
n == 0 || self.gen_range(0, n) == 0
}
/// Return a random string of the specified length composed of
@ -317,95 +300,10 @@ pub trait Rng {
if values.is_empty() {
None
} else {
Some(&values[self.gen_integer_range(0u, values.len())])
Some(&values[self.gen_range(0u, values.len())])
}
}
/// Choose an item respecting the relative weights, failing if the sum of
/// the weights is 0
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::Rng;
///
/// fn main() {
/// let mut rng = rand::rng();
/// let x = [rand::Weighted {weight: 4, item: 'a'},
/// rand::Weighted {weight: 2, item: 'b'},
/// rand::Weighted {weight: 2, item: 'c'}];
/// println!("{}", rng.choose_weighted(x));
/// }
/// ```
fn choose_weighted<T:Clone>(&mut self, v: &[Weighted<T>]) -> T {
self.choose_weighted_option(v).expect("Rng.choose_weighted: total weight is 0")
}
/// Choose Some(item) respecting the relative weights, returning none if
/// the sum of the weights is 0
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::Rng;
///
/// fn main() {
/// let mut rng = rand::rng();
/// let x = [rand::Weighted {weight: 4, item: 'a'},
/// rand::Weighted {weight: 2, item: 'b'},
/// rand::Weighted {weight: 2, item: 'c'}];
/// println!("{:?}", rng.choose_weighted_option(x));
/// }
/// ```
fn choose_weighted_option<T:Clone>(&mut self, v: &[Weighted<T>])
-> Option<T> {
let mut total = 0u;
for item in v.iter() {
total += item.weight;
}
if total == 0u {
return None;
}
let chosen = self.gen_integer_range(0u, total);
let mut so_far = 0u;
for item in v.iter() {
so_far += item.weight;
if so_far > chosen {
return Some(item.item.clone());
}
}
unreachable!();
}
/// Return a vec containing copies of the items, in order, where
/// the weight of the item determines how many copies there are
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::Rng;
///
/// fn main() {
/// let mut rng = rand::rng();
/// let x = [rand::Weighted {weight: 4, item: 'a'},
/// rand::Weighted {weight: 2, item: 'b'},
/// rand::Weighted {weight: 2, item: 'c'}];
/// println!("{}", rng.weighted_vec(x));
/// }
/// ```
fn weighted_vec<T:Clone>(&mut self, v: &[Weighted<T>]) -> ~[T] {
let mut r = ~[];
for item in v.iter() {
for _ in range(0u, item.weight) {
r.push(item.item.clone());
}
}
r
}
/// Shuffle a vec
///
/// # Example
@ -447,7 +345,7 @@ pub trait Rng {
// invariant: elements with index >= i have been locked in place.
i -= 1u;
// lock element i in place.
values.swap(i, self.gen_integer_range(0u, i + 1u));
values.swap(i, self.gen_range(0u, i + 1u));
}
}
@ -473,7 +371,7 @@ pub trait Rng {
continue
}
let k = self.gen_integer_range(0, i + 1);
let k = self.gen_range(0, i + 1);
if k < reservoir.len() {
reservoir[k] = elem
}
@ -520,8 +418,8 @@ pub trait SeedableRng<Seed>: Rng {
/// Create a random number generator with a default algorithm and seed.
///
/// It returns the cryptographically-safest `Rng` algorithm currently
/// available in Rust. If you require a specifically seeded `Rng` for
/// It returns the strongest `Rng` algorithm currently implemented in
/// pure Rust. If you require a specifically seeded `Rng` for
/// consistency over time you should pick one algorithm and create the
/// `Rng` yourself.
///
@ -596,12 +494,16 @@ pub fn weak_rng() -> XorShiftRng {
XorShiftRng::new()
}
/// An [Xorshift random number
/// generator](http://en.wikipedia.org/wiki/Xorshift).
/// An Xorshift[1] random number
/// generator.
///
/// The Xorshift algorithm is not suitable for cryptographic purposes
/// but is very fast. If you do not know for sure that it fits your
/// requirements, use a more secure one such as `IsaacRng`.
/// requirements, use a more secure one such as `IsaacRng` or `OSRng`.
///
/// [1]: Marsaglia, George (July 2003). ["Xorshift
/// RNGs"](http://www.jstatsoft.org/v08/i14/paper). *Journal of
/// Statistical Software*. Vol. 8 (Issue 14).
pub struct XorShiftRng {
priv x: u32,
priv y: u32,
@ -749,47 +651,68 @@ pub fn random<T: Rand>() -> T {
mod test {
use iter::{Iterator, range};
use option::{Option, Some};
use vec;
use super::*;
struct ConstRng { i: u64 }
impl Rng for ConstRng {
fn next_u32(&mut self) -> u32 { self.i as u32 }
fn next_u64(&mut self) -> u64 { self.i }
// no fill_bytes on purpose
}
#[test]
fn test_fill_bytes_default() {
let mut r = weak_rng();
let mut r = ConstRng { i: 0x11_22_33_44_55_66_77_88 };
let mut v = [0u8, .. 100];
r.fill_bytes(v);
// check every remainder mod 8, both in small and big vectors.
let lengths = [0, 1, 2, 3, 4, 5, 6, 7,
80, 81, 82, 83, 84, 85, 86, 87];
for &n in lengths.iter() {
let mut v = vec::from_elem(n, 0u8);
r.fill_bytes(v);
// use this to get nicer error messages.
for (i, &byte) in v.iter().enumerate() {
if byte == 0 {
fail!("byte {} of {} is zero", i, n)
}
}
}
}
#[test]
fn test_gen_integer_range() {
fn test_gen_range() {
let mut r = rng();
for _ in range(0, 1000) {
let a = r.gen_integer_range(-3i, 42);
let a = r.gen_range(-3i, 42);
assert!(a >= -3 && a < 42);
assert_eq!(r.gen_integer_range(0, 1), 0);
assert_eq!(r.gen_integer_range(-12, -11), -12);
assert_eq!(r.gen_range(0, 1), 0);
assert_eq!(r.gen_range(-12, -11), -12);
}
for _ in range(0, 1000) {
let a = r.gen_integer_range(10, 42);
let a = r.gen_range(10, 42);
assert!(a >= 10 && a < 42);
assert_eq!(r.gen_integer_range(0, 1), 0);
assert_eq!(r.gen_integer_range(3_000_000u, 3_000_001), 3_000_000);
assert_eq!(r.gen_range(0, 1), 0);
assert_eq!(r.gen_range(3_000_000u, 3_000_001), 3_000_000);
}
}
#[test]
#[should_fail]
fn test_gen_integer_range_fail_int() {
fn test_gen_range_fail_int() {
let mut r = rng();
r.gen_integer_range(5i, -2);
r.gen_range(5i, -2);
}
#[test]
#[should_fail]
fn test_gen_integer_range_fail_uint() {
fn test_gen_range_fail_uint() {
let mut r = rng();
r.gen_integer_range(5u, 2u);
r.gen_range(5u, 2u);
}
#[test]
@ -843,44 +766,6 @@ mod test {
assert_eq!(r.choose_option(v), Some(&i));
}
#[test]
fn test_choose_weighted() {
let mut r = rng();
assert!(r.choose_weighted([
Weighted { weight: 1u, item: 42 },
]) == 42);
assert!(r.choose_weighted([
Weighted { weight: 0u, item: 42 },
Weighted { weight: 1u, item: 43 },
]) == 43);
}
#[test]
fn test_choose_weighted_option() {
let mut r = rng();
assert!(r.choose_weighted_option([
Weighted { weight: 1u, item: 42 },
]) == Some(42));
assert!(r.choose_weighted_option([
Weighted { weight: 0u, item: 42 },
Weighted { weight: 1u, item: 43 },
]) == Some(43));
let v: Option<int> = r.choose_weighted_option([]);
assert!(v.is_none());
}
#[test]
fn test_weighted_vec() {
let mut r = rng();
let empty: ~[int] = ~[];
assert_eq!(r.weighted_vec([]), empty);
assert!(r.weighted_vec([
Weighted { weight: 0u, item: 3u },
Weighted { weight: 1u, item: 2u },
Weighted { weight: 2u, item: 1u },
]) == ~[2u, 1u, 1u]);
}
#[test]
fn test_shuffle() {
let mut r = rng();
@ -894,7 +779,7 @@ mod test {
let mut r = task_rng();
r.gen::<int>();
assert_eq!(r.shuffle(~[1, 1, 1]), ~[1, 1, 1]);
assert_eq!(r.gen_integer_range(0u, 1u), 0u);
assert_eq!(r.gen_range(0u, 1u), 0u);
}
#[test]
@ -953,41 +838,53 @@ mod bench {
use extra::test::BenchHarness;
use rand::*;
use mem::size_of;
use iter::range;
use option::{Some, None};
static N: u64 = 100;
#[bench]
fn rand_xorshift(bh: &mut BenchHarness) {
let mut rng = XorShiftRng::new();
do bh.iter {
rng.gen::<uint>();
for _ in range(0, N) {
rng.gen::<uint>();
}
}
bh.bytes = size_of::<uint>() as u64;
bh.bytes = size_of::<uint>() as u64 * N;
}
#[bench]
fn rand_isaac(bh: &mut BenchHarness) {
let mut rng = IsaacRng::new();
do bh.iter {
rng.gen::<uint>();
for _ in range(0, N) {
rng.gen::<uint>();
}
}
bh.bytes = size_of::<uint>() as u64;
bh.bytes = size_of::<uint>() as u64 * N;
}
#[bench]
fn rand_isaac64(bh: &mut BenchHarness) {
let mut rng = Isaac64Rng::new();
do bh.iter {
rng.gen::<uint>();
for _ in range(0, N) {
rng.gen::<uint>();
}
}
bh.bytes = size_of::<uint>() as u64;
bh.bytes = size_of::<uint>() as u64 * N;
}
#[bench]
fn rand_std(bh: &mut BenchHarness) {
let mut rng = StdRng::new();
do bh.iter {
rng.gen::<uint>();
for _ in range(0, N) {
rng.gen::<uint>();
}
}
bh.bytes = size_of::<uint>() as u64;
bh.bytes = size_of::<uint>() as u64 * N;
}
#[bench]

View file

@ -30,8 +30,12 @@ type HCRYPTPROV = c_long;
// assume they work when we call them.
/// A random number generator that retrieves randomness straight from
/// the operating system. On Unix-like systems this reads from
/// `/dev/urandom`, on Windows this uses `CryptGenRandom`.
/// the operating system. Platform sources:
///
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
/// `/dev/urandom`.
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
/// service provider with the `PROV_RSA_FULL` type.
///
/// This does not block.
#[cfg(unix)]
@ -39,8 +43,12 @@ pub struct OSRng {
priv inner: ReaderRng<file::FileStream>
}
/// A random number generator that retrieves randomness straight from
/// the operating system. On Unix-like systems this reads from
/// `/dev/urandom`, on Windows this uses `CryptGenRandom`.
/// the operating system. Platform sources:
///
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
/// `/dev/urandom`.
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
/// service provider with the `PROV_RSA_FULL` type.
///
/// This does not block.
#[cfg(windows)]

235
src/libstd/rand/range.rs Normal file
View file

@ -0,0 +1,235 @@
// 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.
//! Generating numbers between two others.
// this is surprisingly complicated to be both generic & correct
use cmp::Ord;
use num::Bounded;
use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
/// Sample values uniformly between two bounds.
///
/// This gives a uniform distribution (assuming the RNG used to sample
/// it is itself uniform & the `SampleRange` implementation for the
/// given type is correct), even for edge cases like `low = 0u8`,
/// `high = 170u8`, for which a naive modulo operation would return
/// numbers less than 85 with double the probability to those greater
/// than 85.
///
/// Types should attempt to sample in `[low, high)`, i.e., not
/// including `high`, but this may be very difficult. All the
/// primitive integer types satisfy this property, and the float types
/// normally satisfy it, but rounding may mean `high` can occur.
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::distributions::{IndependentSample, Range};
///
/// fn main() {
/// let between = Range::new(10u, 10000u);
/// let rng = rand::task_rng();
/// let mut sum = 0;
/// for _ in range(0, 1000) {
/// sum += between.ind_sample(rng);
/// }
/// println!("{}", sum);
/// }
/// ```
pub struct Range<X> {
priv low: X,
priv range: X,
priv accept_zone: X
}
impl<X: SampleRange + Ord> Range<X> {
/// Create a new `Range` instance that samples uniformly from
/// `[low, high)`. Fails if `low >= high`.
pub fn new(low: X, high: X) -> Range<X> {
assert!(low < high, "Range::new called with `low >= high`");
SampleRange::construct_range(low, high)
}
}
impl<Sup: SampleRange> Sample<Sup> for Range<Sup> {
#[inline]
fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
}
impl<Sup: SampleRange> IndependentSample<Sup> for Range<Sup> {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
SampleRange::sample_range(self, rng)
}
}
/// The helper trait for types that have a sensible way to sample
/// uniformly between two values. This should not be used directly,
/// and is only to facilitate `Range`.
pub trait SampleRange {
/// Construct the `Range` object that `sample_range`
/// requires. This should not ever be called directly, only via
/// `Range::new`, which will check that `low < high`, so this
/// function doesn't have to repeat the check.
fn construct_range(low: Self, high: Self) -> Range<Self>;
/// Sample a value from the given `Range` with the given `Rng` as
/// a source of randomness.
fn sample_range<R: Rng>(r: &Range<Self>, rng: &mut R) -> Self;
}
macro_rules! integer_impl {
($ty:ty, $unsigned:ty) => {
impl SampleRange for $ty {
// we play free and fast with unsigned vs signed here
// (when $ty is signed), but that's fine, since the
// contract of this macro is for $ty and $unsigned to be
// "bit-equal", so casting between them is a no-op & a
// bijection.
fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
let range = high as $unsigned - low as $unsigned;
let unsigned_max: $unsigned = Bounded::max_value();
// this is the largest number that fits into $unsigned
// that `range` divides evenly, so, if we've sampled
// `n` uniformly from this region, then `n % range` is
// uniform in [0, range)
let zone = unsigned_max - unsigned_max % range;
Range {
low: low,
range: range as $ty,
accept_zone: zone as $ty
}
}
#[inline]
fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
loop {
// rejection sample
let v = rng.gen::<$unsigned>();
// until we find something that fits into the
// region which r.range evenly divides (this will
// be uniformly distributed)
if v < r.accept_zone as $unsigned {
// and return it, with some adjustments
return r.low + (v % r.range as $unsigned) as $ty;
}
}
}
}
}
}
integer_impl! { i8, u8 }
integer_impl! { i16, u16 }
integer_impl! { i32, u32 }
integer_impl! { i64, u64 }
integer_impl! { int, uint }
integer_impl! { u8, u8 }
integer_impl! { u16, u16 }
integer_impl! { u32, u32 }
integer_impl! { u64, u64 }
integer_impl! { uint, uint }
macro_rules! float_impl {
($ty:ty) => {
impl SampleRange for $ty {
fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
Range {
low: low,
range: high - low,
accept_zone: 0.0 // unused
}
}
fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
r.low + r.range * rng.gen()
}
}
}
}
float_impl! { f32 }
float_impl! { f64 }
#[cfg(test)]
mod tests {
use super::*;
use rand::*;
use num::Bounded;
use iter::range;
use option::{Some, None};
use vec::ImmutableVector;
#[should_fail]
#[test]
fn test_range_bad_limits_equal() {
Range::new(10, 10);
}
#[should_fail]
#[test]
fn test_range_bad_limits_flipped() {
Range::new(10, 5);
}
#[test]
fn test_integers() {
let rng = task_rng();
macro_rules! t (
($($ty:ty),*) => {{
$(
let v: &[($ty, $ty)] = [(0, 10),
(10, 127),
(Bounded::min_value(), Bounded::max_value())];
for &(low, high) in v.iter() {
let mut sampler: Range<$ty> = Range::new(low, high);
for _ in range(0, 1000) {
let v = sampler.sample(rng);
assert!(low <= v && v < high);
let v = sampler.ind_sample(rng);
assert!(low <= v && v < high);
}
}
)*
}}
);
t!(i8, i16, i32, i64, int,
u8, u16, u32, u64, uint)
}
#[test]
fn test_floats() {
let rng = task_rng();
macro_rules! t (
($($ty:ty),*) => {{
$(
let v: &[($ty, $ty)] = [(0.0, 100.0),
(-1e35, -1e25),
(1e-35, 1e-25),
(-1e35, 1e35)];
for &(low, high) in v.iter() {
let mut sampler: Range<$ty> = Range::new(low, high);
for _ in range(0, 1000) {
let v = sampler.sample(rng);
assert!(low <= v && v < high);
let v = sampler.ind_sample(rng);
assert!(low <= v && v < high);
}
}
)*
}}
);
t!(f32, f64)
}
}

View file

@ -41,7 +41,7 @@ pub fn align(size: uint, align: uint) -> uint {
/// Adaptor to wrap around visitors implementing MovePtr.
pub struct MovePtrAdaptor<V> {
inner: V
priv inner: V
}
pub fn MovePtrAdaptor<V:TyVisitor + MovePtr>(v: V) -> MovePtrAdaptor<V> {
MovePtrAdaptor { inner: v }

View file

@ -98,10 +98,10 @@ enum VariantState {
}
pub struct ReprVisitor<'self> {
ptr: *c_void,
ptr_stk: ~[*c_void],
var_stk: ~[VariantState],
writer: &'self mut io::Writer
priv ptr: *c_void,
priv ptr_stk: ~[*c_void],
priv var_stk: ~[VariantState],
priv writer: &'self mut io::Writer
}
pub fn ReprVisitor<'a>(ptr: *c_void,

View file

@ -29,9 +29,9 @@ static ALL_BITS: uint = FROZEN_BIT | MUT_BIT;
#[deriving(Eq)]
pub struct BorrowRecord {
box: *mut raw::Box<()>,
priv box: *mut raw::Box<()>,
file: *c_char,
line: size_t
priv line: size_t
}
fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> {

View file

@ -48,14 +48,14 @@ struct Packet<T> {
// A one-shot channel.
pub struct ChanOne<T> {
void_packet: *mut Void,
suppress_finalize: bool
priv void_packet: *mut Void,
priv suppress_finalize: bool
}
/// A one-shot port.
pub struct PortOne<T> {
void_packet: *mut Void,
suppress_finalize: bool
priv void_packet: *mut Void,
priv suppress_finalize: bool
}
pub fn oneshot<T: Send>() -> (PortOne<T>, ChanOne<T>) {
@ -1117,7 +1117,7 @@ mod test {
let total = stress_factor() + 10;
let mut rng = rand::rng();
do total.times {
let msgs = rng.gen_integer_range(0u, 10);
let msgs = rng.gen_range(0u, 10);
let pipe_clone = pipe.clone();
let end_chan_clone = end_chan.clone();
do spawntask_random {

View file

@ -25,11 +25,11 @@ pub static RED_ZONE: uint = 20 * 1024;
// then misalign the regs again.
pub struct Context {
/// The context entry point, saved here for later destruction
start: Option<~~fn()>,
priv start: Option<~~fn()>,
/// Hold the registers while the task or scheduler is suspended
regs: ~Registers,
priv regs: ~Registers,
/// Lower bound and upper bound for the stack
stack_bounds: Option<(uint, uint)>,
priv stack_bounds: Option<(uint, uint)>,
}
impl Context {
@ -391,36 +391,32 @@ pub unsafe fn record_sp_limit(limit: uint) {
/// As with the setter, this function does not have a __morestack header and can
/// therefore be called in a "we're out of stack" situation.
#[inline(always)]
// NOTE: after the next snapshot, can remove the initialization before inline
// assembly due to an improvement in how it's handled, then this specific
// allow directive should get removed.
#[allow(dead_assignment)]
pub unsafe fn get_sp_limit() -> uint {
return target_get_sp_limit();
// x86-64
#[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)]
unsafe fn target_get_sp_limit() -> uint {
let mut limit: uint = 0;
let limit;
asm!("movq $$0x60+90*8, %rsi
movq %gs:(%rsi), $0" : "=r"(limit) :: "rsi" : "volatile");
return limit;
}
#[cfg(target_arch = "x86_64", target_os = "linux")] #[inline(always)]
unsafe fn target_get_sp_limit() -> uint {
let mut limit: uint = 0;
let limit;
asm!("movq %fs:112, $0" : "=r"(limit) ::: "volatile");
return limit;
}
#[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)]
unsafe fn target_get_sp_limit() -> uint {
let mut limit: uint = 0;
let limit;
asm!("movq %gs:0x28, $0" : "=r"(limit) ::: "volatile");
return limit;
}
#[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)]
unsafe fn target_get_sp_limit() -> uint {
let mut limit: uint = 0;
let limit;
asm!("movq %fs:24, $0" : "=r"(limit) ::: "volatile");
return limit;
}
@ -428,7 +424,7 @@ pub unsafe fn get_sp_limit() -> uint {
// x86
#[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)]
unsafe fn target_get_sp_limit() -> uint {
let mut limit: uint = 0;
let limit;
asm!("movl $$0x48+90*4, %eax
movl %gs:(%eax), $0" : "=r"(limit) :: "eax" : "volatile");
return limit;
@ -436,13 +432,13 @@ pub unsafe fn get_sp_limit() -> uint {
#[cfg(target_arch = "x86", target_os = "linux")]
#[cfg(target_arch = "x86", target_os = "freebsd")] #[inline(always)]
unsafe fn target_get_sp_limit() -> uint {
let mut limit: uint = 0;
let limit;
asm!("movl %gs:48, $0" : "=r"(limit) ::: "volatile");
return limit;
}
#[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)]
unsafe fn target_get_sp_limit() -> uint {
let mut limit: uint = 0;
let limit;
asm!("movl %fs:0x14, $0" : "=r"(limit) ::: "volatile");
return limit;
}

View file

@ -26,9 +26,9 @@ pub struct ModEntry<'self> {
}
pub struct CrateMap<'self> {
version: i32,
entries: &'self [ModEntry<'self>],
children: &'self [&'self CrateMap<'self>]
priv version: i32,
priv entries: &'self [ModEntry<'self>],
priv children: &'self [&'self CrateMap<'self>]
}
#[cfg(not(windows))]

View file

@ -362,8 +362,8 @@ impl Seek for FileWriter {
/// For this reason, it is best to use the access-constrained wrappers that are
/// exposed via `FileInfo.open_reader()` and `FileInfo.open_writer()`.
pub struct FileStream {
fd: ~RtioFileStream,
last_nread: int,
priv fd: ~RtioFileStream,
priv last_nread: int,
}
/// a `std::rt::io::Reader` trait impl for file I/O.

View file

@ -17,7 +17,7 @@ use super::*;
/// A Writer decorator that compresses using the 'deflate' scheme
pub struct DeflateWriter<W> {
inner_writer: W
priv inner_writer: W
}
impl<W: Writer> DeflateWriter<W> {
@ -56,7 +56,7 @@ impl<W: Writer> Decorator<W> for DeflateWriter<W> {
/// A Reader decorator that decompresses using the 'deflate' scheme
pub struct InflateReader<R> {
inner_reader: R
priv inner_reader: R
}
impl<R: Reader> InflateReader<R> {

View file

@ -13,7 +13,7 @@ use rt::io::{Reader, Writer};
pub struct MockReader {
read: ~fn(buf: &mut [u8]) -> Option<uint>,
eof: ~fn() -> bool
priv eof: ~fn() -> bool
}
impl MockReader {
@ -31,8 +31,8 @@ impl Reader for MockReader {
}
pub struct MockWriter {
write: ~fn(buf: &[u8]),
flush: ~fn()
priv write: ~fn(buf: &[u8]),
priv flush: ~fn()
}
impl MockWriter {

View file

@ -12,8 +12,8 @@
This module defines the Rust interface for synchronous I/O.
It models byte-oriented input and output with the Reader and Writer traits.
Types that implement both `Reader` and `Writer` and called 'streams',
and automatically implement trait `Stream`.
Types that implement both `Reader` and `Writer` are called 'streams',
and automatically implement the `Stream` trait.
Implementations are provided for common I/O streams like
file, TCP, UDP, Unix domain sockets.
Readers and Writers may be composed to add capabilities like string

View file

@ -219,17 +219,17 @@ pub struct Death {
// might kill it. This is optional so we can take it by-value at exit time.
kill_handle: Option<KillHandle>,
// Handle to a watching parent, if we have one, for exit code propagation.
watching_parent: Option<KillHandle>,
priv watching_parent: Option<KillHandle>,
// Action to be done with the exit code. If set, also makes the task wait
// until all its watched children exit before collecting the status.
on_exit: Option<~fn(bool)>,
// nesting level counter for task::unkillable calls (0 == killable).
unkillable: int,
priv unkillable: int,
// nesting level counter for unstable::atomically calls (0 == can deschedule).
wont_sleep: int,
priv wont_sleep: int,
// A "spare" handle to the kill flag inside the kill handle. Used during
// blocking/waking as an optimization to avoid two xadds on the refcount.
spare_kill_flag: Option<KillFlagHandle>,
priv spare_kill_flag: Option<KillFlagHandle>,
}
impl Drop for KillFlag {

View file

@ -32,8 +32,8 @@ pub type OpaqueBox = c_void;
pub type TypeDesc = c_void;
pub struct LocalHeap {
memory_region: *MemoryRegion,
boxed_region: *BoxedRegion
priv memory_region: *MemoryRegion,
priv boxed_region: *BoxedRegion
}
impl LocalHeap {

View file

@ -24,7 +24,7 @@ use libc::c_void;
use cast;
pub struct RC<T> {
p: *c_void // ~(uint, T)
priv p: *c_void // ~(uint, T)
}
impl<T> RC<T> {

View file

@ -66,7 +66,7 @@ pub struct FileOpenConfig {
/// Flags for file access mode (as per open(2))
flags: int,
/// File creation mode, ignored unless O_CREAT is passed as part of flags
mode: int
priv mode: int
}
pub trait IoFactory {

View file

@ -66,26 +66,26 @@ pub struct Scheduler {
event_loop: ~EventLoopObject,
/// The scheduler runs on a special task. When it is not running
/// it is stored here instead of the work queue.
sched_task: Option<~Task>,
priv sched_task: Option<~Task>,
/// An action performed after a context switch on behalf of the
/// code running before the context switch
cleanup_job: Option<CleanupJob>,
priv cleanup_job: Option<CleanupJob>,
/// Should this scheduler run any task, or only pinned tasks?
run_anything: bool,
/// If the scheduler shouldn't run some tasks, a friend to send
/// them to.
friend_handle: Option<SchedHandle>,
priv friend_handle: Option<SchedHandle>,
/// A fast XorShift rng for scheduler use
rng: XorShiftRng,
/// A toggleable idle callback
idle_callback: Option<~PausibleIdleCallback>,
priv idle_callback: Option<~PausibleIdleCallback>,
/// A countdown that starts at a random value and is decremented
/// every time a yield check is performed. When it hits 0 a task
/// will yield.
yield_check_count: uint,
priv yield_check_count: uint,
/// A flag to tell the scheduler loop it needs to do some stealing
/// in order to introduce randomness as part of a yield
steal_for_yield: bool
priv steal_for_yield: bool
}
/// An indication of how hard to work on a given operation, the difference
@ -431,7 +431,7 @@ impl Scheduler {
fn try_steals(&mut self) -> Option<~Task> {
let work_queues = &mut self.work_queues;
let len = work_queues.len();
let start_index = self.rng.gen_integer_range(0, len);
let start_index = self.rng.gen_range(0, len);
for index in range(0, len).map(|i| (i + start_index) % len) {
match work_queues[index].steal() {
Some(task) => {

View file

@ -15,8 +15,8 @@ use ops::Drop;
use libc::{c_uint, uintptr_t};
pub struct StackSegment {
buf: ~[u8],
valgrind_id: c_uint
priv buf: ~[u8],
priv valgrind_id: c_uint
}
impl StackSegment {

View file

@ -44,7 +44,7 @@ use send_str::SendStr;
pub struct Task {
heap: LocalHeap,
gc: GarbageCollector,
priv gc: GarbageCollector,
storage: LocalStorage,
logger: StdErrLogger,
unwinder: Unwinder,
@ -69,7 +69,7 @@ pub struct Coroutine {
/// The segment of stack on which the task is currently running or
/// if the task is blocked, on which the task will resume
/// execution.
current_stack_segment: StackSegment,
priv current_stack_segment: StackSegment,
/// Always valid if the task is alive and not running.
saved_context: Context
}

View file

@ -18,9 +18,9 @@ use uint;
type raw_thread = libc::c_void;
pub struct Thread {
main: ~fn(),
raw_thread: *raw_thread,
joined: bool,
priv main: ~fn(),
priv raw_thread: *raw_thread,
priv joined: bool
}
impl Thread {

View file

@ -28,7 +28,7 @@ struct TubeState<T> {
}
pub struct Tube<T> {
p: RC<TubeState<T>>
priv p: RC<TubeState<T>>
}
impl<T> Tube<T> {

View file

@ -25,7 +25,7 @@ type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &UvAddrInfo, Option<UvError>)
pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t);
pub struct RequestData {
getaddrinfo_cb: Option<GetAddrInfoCallback>,
priv getaddrinfo_cb: Option<GetAddrInfoCallback>,
}
impl GetAddrInfoRequest {

View file

@ -25,7 +25,7 @@ pub struct FsRequest(*uvll::uv_fs_t);
impl Request for FsRequest {}
pub struct RequestData {
complete_cb: Option<FsCallback>
priv complete_cb: Option<FsCallback>
}
impl FsRequest {

View file

@ -80,7 +80,7 @@ pub mod pipe;
/// with dtors may not be destructured, but tuple structs can,
/// but the results are not correct.
pub struct Loop {
handle: *uvll::uv_loop_t
priv handle: *uvll::uv_loop_t
}
/// The trait implemented by uv 'watchers' (handles). Watchers are

View file

@ -180,7 +180,7 @@ fn socket_name<T, U: Watcher + NativeHandle<*T>>(sk: SocketNameKind,
// Obviously an Event Loop is always home.
pub struct UvEventLoop {
uvio: UvIoFactory
priv uvio: UvIoFactory
}
impl UvEventLoop {
@ -240,9 +240,9 @@ impl EventLoop for UvEventLoop {
}
pub struct UvPausibleIdleCallback {
watcher: IdleWatcher,
idle_flag: bool,
closed: bool
priv watcher: IdleWatcher,
priv idle_flag: bool,
priv closed: bool
}
impl UvPausibleIdleCallback {
@ -294,10 +294,10 @@ fn test_callback_run_once() {
// The entire point of async is to call into a loop from other threads so it does not need to home.
pub struct UvRemoteCallback {
// The uv async handle for triggering the callback
async: AsyncWatcher,
priv async: AsyncWatcher,
// A flag to tell the callback to exit, set from the dtor. This is
// almost never contested - only in rare races with the dtor.
exit_flag: Exclusive<bool>
priv exit_flag: Exclusive<bool>
}
impl UvRemoteCallback {
@ -804,8 +804,8 @@ impl IoFactory for UvIoFactory {
}
pub struct UvTcpListener {
watcher : TcpWatcher,
home: SchedHandle,
priv watcher : TcpWatcher,
priv home: SchedHandle,
}
impl HomingIO for UvTcpListener {
@ -866,8 +866,8 @@ impl RtioTcpListener for UvTcpListener {
}
pub struct UvTcpAcceptor {
listener: UvTcpListener,
incoming: Tube<Result<~RtioTcpStreamObject, IoError>>,
priv listener: UvTcpListener,
priv incoming: Tube<Result<~RtioTcpStreamObject, IoError>>,
}
impl HomingIO for UvTcpAcceptor {
@ -991,7 +991,7 @@ fn write_stream(mut watcher: StreamWatcher,
pub struct UvUnboundPipe {
pipe: Pipe,
home: SchedHandle,
priv home: SchedHandle,
}
impl HomingIO for UvUnboundPipe {
@ -1043,8 +1043,8 @@ impl RtioPipe for UvPipeStream {
}
pub struct UvTcpStream {
watcher: TcpWatcher,
home: SchedHandle,
priv watcher: TcpWatcher,
priv home: SchedHandle,
}
impl HomingIO for UvTcpStream {
@ -1143,8 +1143,8 @@ impl RtioTcpStream for UvTcpStream {
}
pub struct UvUdpSocket {
watcher: UdpWatcher,
home: SchedHandle,
priv watcher: UdpWatcher,
priv home: SchedHandle,
}
impl HomingIO for UvUdpSocket {
@ -1353,8 +1353,8 @@ impl RtioUdpSocket for UvUdpSocket {
}
pub struct UvTimer {
watcher: timer::TimerWatcher,
home: SchedHandle,
priv watcher: timer::TimerWatcher,
priv home: SchedHandle,
}
impl HomingIO for UvTimer {
@ -1400,10 +1400,10 @@ impl RtioTimer for UvTimer {
}
pub struct UvFileStream {
loop_: Loop,
fd: c_int,
close_on_drop: bool,
home: SchedHandle
priv loop_: Loop,
priv fd: c_int,
priv close_on_drop: bool,
priv home: SchedHandle
}
impl HomingIO for UvFileStream {
@ -1533,11 +1533,11 @@ impl RtioFileStream for UvFileStream {
}
pub struct UvProcess {
process: process::Process,
priv process: process::Process,
// Sadly, this structure must be created before we return it, so in that
// brief interim the `home` is None.
home: Option<SchedHandle>,
priv home: Option<SchedHandle>,
// All None until the process exits (exit_error may stay None)
priv exit_status: Option<int>,

View file

@ -134,26 +134,26 @@ pub type uv_pipe_t = c_void;
pub struct uv_timespec_t {
tv_sec: libc::c_long,
tv_nsec: libc::c_long
priv tv_nsec: libc::c_long
}
pub struct uv_stat_t {
st_dev: libc::uint64_t,
priv st_dev: libc::uint64_t,
st_mode: libc::uint64_t,
st_nlink: libc::uint64_t,
st_uid: libc::uint64_t,
st_gid: libc::uint64_t,
st_rdev: libc::uint64_t,
st_ino: libc::uint64_t,
priv st_nlink: libc::uint64_t,
priv st_uid: libc::uint64_t,
priv st_gid: libc::uint64_t,
priv st_rdev: libc::uint64_t,
priv st_ino: libc::uint64_t,
st_size: libc::uint64_t,
st_blksize: libc::uint64_t,
st_blocks: libc::uint64_t,
st_flags: libc::uint64_t,
st_gen: libc::uint64_t,
priv st_blksize: libc::uint64_t,
priv st_blocks: libc::uint64_t,
priv st_flags: libc::uint64_t,
priv st_gen: libc::uint64_t,
st_atim: uv_timespec_t,
st_mtim: uv_timespec_t,
st_ctim: uv_timespec_t,
st_birthtim: uv_timespec_t
priv st_birthtim: uv_timespec_t
}
impl uv_stat_t {
@ -231,37 +231,37 @@ pub type socklen_t = c_int;
#[cfg(target_os = "android")]
#[cfg(target_os = "linux")]
pub struct addrinfo {
ai_flags: c_int,
ai_family: c_int,
ai_socktype: c_int,
ai_protocol: c_int,
ai_addrlen: socklen_t,
priv ai_flags: c_int,
priv ai_family: c_int,
priv ai_socktype: c_int,
priv ai_protocol: c_int,
priv ai_addrlen: socklen_t,
ai_addr: *sockaddr,
ai_canonname: *char,
priv ai_canonname: *char,
ai_next: *addrinfo
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
pub struct addrinfo {
ai_flags: c_int,
ai_family: c_int,
ai_socktype: c_int,
ai_protocol: c_int,
ai_addrlen: socklen_t,
ai_canonname: *char,
priv ai_flags: c_int,
priv ai_family: c_int,
priv ai_socktype: c_int,
priv ai_protocol: c_int,
priv ai_addrlen: socklen_t,
priv ai_canonname: *char,
ai_addr: *sockaddr,
ai_next: *addrinfo
}
#[cfg(windows)]
pub struct addrinfo {
ai_flags: c_int,
ai_family: c_int,
ai_socktype: c_int,
ai_protocol: c_int,
ai_addrlen: size_t,
ai_canonname: *char,
priv ai_flags: c_int,
priv ai_family: c_int,
priv ai_socktype: c_int,
priv ai_protocol: c_int,
priv ai_addrlen: size_t,
priv ai_canonname: *char,
ai_addr: *sockaddr,
ai_next: *addrinfo
}
@ -960,8 +960,8 @@ pub unsafe fn freeaddrinfo(ai: *addrinfo) {
}
pub struct uv_err_data {
err_name: ~str,
err_msg: ~str,
priv err_name: ~str,
priv err_msg: ~str,
}
extern {

View file

@ -34,7 +34,6 @@ pub struct Process {
/// Options that can be given when starting a Process.
pub struct ProcessOptions<'self> {
/**
* If this is None then the new process will have the same initial
* environment as the parent process.
@ -99,7 +98,6 @@ impl <'self> ProcessOptions<'self> {
/// The output of a finished process.
pub struct ProcessOutput {
/// The status (exit code) of the process.
status: int,

View file

@ -998,7 +998,6 @@ pub fn utf8_char_width(b: u8) -> uint {
pub struct CharRange {
/// Current `char`
ch: char,
/// Index of the first byte of the next `char`
next: uint
}

View file

@ -108,7 +108,7 @@ pub enum SchedMode {
*
*/
pub struct SchedOpts {
mode: SchedMode,
priv mode: SchedMode,
}
/**
@ -144,11 +144,11 @@ pub struct SchedOpts {
* scheduler other tasks will be impeded or even blocked indefinitely.
*/
pub struct TaskOpts {
linked: bool,
supervised: bool,
watched: bool,
indestructible: bool,
notify_chan: Option<Chan<TaskResult>>,
priv linked: bool,
priv supervised: bool,
priv watched: bool,
priv indestructible: bool,
priv notify_chan: Option<Chan<TaskResult>>,
name: Option<SendStr>,
sched: SchedOpts,
stack_size: Option<uint>
@ -170,9 +170,9 @@ pub struct TaskOpts {
// FIXME (#3724): Replace the 'consumed' bit with move mode on self
pub struct TaskBuilder {
opts: TaskOpts,
gen_body: Option<~fn(v: ~fn()) -> ~fn()>,
can_not_copy: Option<util::NonCopyable>,
consumed: bool,
priv gen_body: Option<~fn(v: ~fn()) -> ~fn()>,
priv can_not_copy: Option<util::NonCopyable>,
priv consumed: bool,
}
/**

View file

@ -308,10 +308,10 @@ fn each_ancestor(list: &mut AncestorList,
// One of these per task.
pub struct Taskgroup {
// List of tasks with whose fates this one's is intertwined.
tasks: TaskGroupArc, // 'none' means the group has failed.
priv tasks: TaskGroupArc, // 'none' means the group has failed.
// Lists of tasks who will kill us if they fail, but whom we won't kill.
ancestors: AncestorList,
notifier: Option<AutoNotify>,
priv ancestors: AncestorList,
priv notifier: Option<AutoNotify>,
}
impl Drop for Taskgroup {

View file

@ -49,23 +49,23 @@ pub struct TyDesc {
align: uint,
// Called on a copy of a value of type `T` *after* memcpy
take_glue: GlueFn,
priv 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,
priv free_glue: GlueFn,
// Called by reflection visitor to visit a value of type `T`
visit_glue: GlueFn,
priv 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,
priv borrow_offset: uint,
// Name corresponding to the type
name: &'static str

View file

@ -15,7 +15,7 @@ use unstable::intrinsics::TyDesc;
pub struct Box<T> {
ref_count: uint,
type_desc: *TyDesc,
prev: *Box<T>,
priv prev: *Box<T>,
next: *Box<T>,
data: T
}

View file

@ -304,7 +304,7 @@ pub unsafe fn atomically<U>(f: &fn() -> U) -> U {
type rust_little_lock = *libc::c_void;
pub struct LittleLock {
l: rust_little_lock,
priv l: rust_little_lock,
}
impl Drop for LittleLock {
@ -353,7 +353,7 @@ struct ExData<T> {
* need to block or deschedule while accessing shared state, use extra::sync::RWArc.
*/
pub struct Exclusive<T> {
x: UnsafeArc<ExData<T>>
priv x: UnsafeArc<ExData<T>>
}
impl<T:Send> Clone for Exclusive<T> {

View file

@ -227,7 +227,7 @@ pub enum MethodProvenance {
pub enum Def {
DefFn(DefId, purity),
DefStaticMethod(/* method */ DefId, MethodProvenance, purity),
DefSelf(NodeId),
DefSelf(NodeId, bool /* is_mutbl */),
DefSelfTy(/* trait id */ NodeId),
DefMod(DefId),
DefForeignMod(DefId),
@ -921,10 +921,10 @@ pub enum ret_style {
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum explicit_self_ {
sty_static, // no self
sty_value, // `self`
sty_region(Option<Lifetime>, Mutability), // `&'lt self`
sty_value(Mutability), // `self`
sty_region(Option<Lifetime>, Mutability), // `&'lt self`
sty_box(Mutability), // `@self`
sty_uniq // `~self`
sty_uniq(Mutability) // `~self`
}
pub type explicit_self = Spanned<explicit_self_>;

View file

@ -66,7 +66,7 @@ pub fn def_id_of_def(d: Def) -> DefId {
DefUse(id) | DefStruct(id) | DefTrait(id) | DefMethod(id, _) => {
id
}
DefArg(id, _) | DefLocal(id, _) | DefSelf(id) | DefSelfTy(id)
DefArg(id, _) | DefLocal(id, _) | DefSelf(id, _) | DefSelfTy(id)
| DefUpvar(id, _, _, _) | DefBinding(id, _) | DefRegion(id)
| DefTyParamBinder(id) | DefLabel(id) => {
local_def(id)

View file

@ -240,13 +240,13 @@ pub fn get_explicit_self(cx: @ExtCtxt, span: Span, self_ptr: &Option<PtrTy>)
let self_path = cx.expr_self(span);
match *self_ptr {
None => {
(self_path, respan(span, ast::sty_value))
(self_path, respan(span, ast::sty_value(ast::MutImmutable)))
}
Some(ref ptr) => {
let self_ty = respan(
span,
match *ptr {
Send => ast::sty_uniq,
Send => ast::sty_uniq(ast::MutImmutable),
Managed(mutbl) => ast::sty_box(mutbl),
Borrowed(ref lt, mutbl) => {
let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s)));

View file

@ -3438,15 +3438,11 @@ impl Parser {
// parse the argument list and result type of a function
// that may have a self type.
fn parse_fn_decl_with_self(
&self,
parse_arg_fn:
&fn(&Parser) -> arg
) -> (explicit_self, fn_decl) {
fn maybe_parse_explicit_self(
cnstr: &fn(v: Mutability) -> ast::explicit_self_,
p: &Parser
) -> ast::explicit_self_ {
fn parse_fn_decl_with_self(&self, parse_arg_fn: &fn(&Parser) -> arg)
-> (explicit_self, fn_decl) {
fn maybe_parse_explicit_self(cnstr: &fn(v: Mutability) -> ast::explicit_self_,
p: &Parser) -> ast::explicit_self_ {
// We need to make sure it isn't a type
if p.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) ||
((p.look_ahead(1, |t| token::is_keyword(keywords::Const, t)) ||
@ -3524,25 +3520,39 @@ impl Parser {
self.span_err(*self.last_span,
"mutability declaration not allowed here");
}
sty_uniq
sty_uniq(MutImmutable)
}, self)
}
token::IDENT(*) if self.is_self_ident() => {
self.bump();
sty_value
sty_value(MutImmutable)
}
token::BINOP(token::STAR) => {
// Possibly "*self" or "*mut self" -- not supported. Try to avoid
// emitting cryptic "unexpected token" errors.
self.bump();
if self.token_is_mutability(self.token) {
self.bump();
}
let mutability = if self.token_is_mutability(self.token) {
self.parse_mutability()
} else { MutImmutable };
if self.is_self_ident() {
self.span_err(*self.span, "cannot pass self by unsafe pointer");
self.bump();
}
sty_value
sty_value(mutability)
}
_ if self.token_is_mutability(self.token) &&
self.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) => {
let mutability = self.parse_mutability();
self.expect_self_ident();
sty_value(mutability)
}
_ if self.token_is_mutability(self.token) &&
self.look_ahead(1, |t| *t == token::TILDE) &&
self.look_ahead(2, |t| token::is_keyword(keywords::Self, t)) => {
let mutability = self.parse_mutability();
self.bump();
self.expect_self_ident();
sty_uniq(mutability)
}
_ => {
sty_static

Some files were not shown because too many files have changed in this diff Show more