parse_name_value_directive(line, "exec-env").map(|nv| {
// nv is either FOO or FOO=BAR
let mut strs: Vec<String> = nv.as_slice()
- .splitn('=', 1)
+ .splitn(1, '=')
.map(|s| s.to_string())
.collect();
use std::str;
use std::string::String;
use std::task;
+use std::time::Duration;
use test::MetricMap;
pub fn run(config: Config, testfile: String) {
.expect(format!("failed to exec `{}`", config.adb_path).as_slice());
loop {
//waiting 1 second for gdbserver start
- timer::sleep(1000);
+ timer::sleep(Duration::milliseconds(1000));
let result = task::try(proc() {
tcp::TcpStream::connect("127.0.0.1", 5039).unwrap();
});
The full complement of runtime features is defined by the [`Runtime`
trait](std/rt/trait.Runtime.html) and the [`Task`
struct](std/rt/task/struct.Task.html). A `Task` is constant among all runtime
-implementations, but each runtime implements has its own implementation of the
+implementations, but each runtime has its own implementation of the
`Runtime` trait.
The local `Task` stores the runtime value inside of itself, and then ownership
For benchmarks relating to processing/generating data, one can set the
`bytes` field to the number of bytes consumed/produced in each
-iteration; this will used to show the throughput of the benchmark.
+iteration; this will be used to show the throughput of the benchmark.
This must be the amount used in each iteration, *not* the total
amount.
Going the opposite direction, from `*const` to a reference `&`, is not
safe. A `&T` is always valid, and so, at a minimum, the raw pointer
-`*const T` has to be a valid to a valid instance of type `T`. Furthermore,
+`*const T` has to point to a valid instance of type `T`. Furthermore,
the resulting pointer must satisfy the aliasing and mutability laws of
references. The compiler assumes these properties are true for any
references, no matter how they are created, and so any conversion from
```{ignore}
let x = 5i;
-let y: int = if x == 5 { 10i; } else { 15i; };
+let y: int = if x == 5i { 10i; } else { 15i; };
```
Note the semicolons after the 10 and 15. Rust will give us the following error:
Immutable static items are stored in the read-only data section.
The constant value bound to a static item is, like all constant values, evaluated at compile time.
Static items have the `static` lifetime, which outlives all other lifetimes in a Rust program.
+Only values stored in the global data section (such as string constants
+and static items) can have the `static` lifetime;
+dynamically constructed values cannot safely be assigned the `static` lifetime.
Static items are declared with the `static` keyword.
A static item must have a _constant expression_ giving its definition.
- `crate_id` - specify the this crate's crate ID.
- `crate_type` - see [linkage](#linkage).
- `feature` - see [compiler features](#compiler-features).
+- `no_builtins` - disable optimizing certain code patterns to invocations of
+ library functions that are assumed to exist
- `no_main` - disable emitting the `main` symbol. Useful when some other
object being linked to defines `main`.
- `no_start` - disable linking to the `native` crate, which specifies the
"start" language item.
- `no_std` - disable linking to the `std` crate.
-- `no_builtins` - disable optimizing certain code patterns to invocations of
- library functions that are assumed to exist
### Module-only attributes
### Function-only attributes
-- `plugin_registrar` - mark this function as the registration point for
- compiler plugins, such as loadable syntax extensions.
- `main` - indicates that this function should be passed to the entry point,
rather than the function in the crate root named `main`.
+- `plugin_registrar` - mark this function as the registration point for
+ compiler plugins, such as loadable syntax extensions.
- `start` - indicates that this function should be used as the entry point,
overriding the "start" language item. See the "start" [language
item](#language-items) for more details.
symbol for this item to its identifier.
- `packed` - on structs or enums, eliminate any padding that would be used to
align fields.
+- `phase` - on `extern crate` statements, allows specifying which "phase" of
+ compilation the crate should be loaded for. Currently, there are two
+ choices: `link` and `plugin`. `link` is the default. `plugin` will load the
+ crate at compile-time and use any syntax extensions or lints that the crate
+ defines. They can both be specified, `#[phase(link, plugin)]` to use a crate
+ both at runtime and compiletime.
- `repr` - on C-like enums, this sets the underlying type used for
representation. Useful for FFI. Takes one argument, which is the primitive
type this enum should be represented for, or `C`, which specifies that it
- `unsafe_no_drop_flag` - on structs, remove the flag that prevents
destructors from being run twice. Destructors might be run multiple times on
the same object with this attribute.
-- `phase` - on `extern crate` statements, allows specifying which "phase" of
- compilation the crate should be loaded for. Currently, there are two
- choices: `link` and `plugin`. `link` is the default. `plugin` will load the
- crate at compile-time and use any syntax extensions or lints that the crate
- defines. They can both be specified, `#[phase(link, plugin)]` to use a crate
- both at runtime and compiletime.
### Conditional compilation
For any lint check `C`:
- * `warn(C)` warns about violations of `C` but continues compilation,
- * `deny(C)` signals an error after encountering a violation of `C`,
* `allow(C)` overrides the check for `C` so that violations will go
unreported,
+ * `deny(C)` signals an error after encountering a violation of `C`,
* `forbid(C)` is the same as `deny(C)`, but also forbids changing the lint
- level afterwards.
+ level afterwards,
+ * `warn(C)` warns about violations of `C` but continues compilation.
The lint checks supported by the compiler can be found via `rustc -W help`,
along with their default settings.
#### Built-in Traits
+* `copy`
+ : Types that do not move ownership when used by-value.
+* `drop`
+ : Have destructors.
* `send`
: Able to be sent across task boundaries.
* `sized`
: Has a size known at compile time.
-* `copy`
- : Types that do not move ownership when used by-value.
* `sync`
: Able to be safely shared between tasks when aliased.
-* `drop`
- : Have destructors.
#### Operators
: Elements have a right shift operation.
* `index`
: Elements can be indexed.
+* `index_mut`
+ : ___Needs filling in___
* `eq`
: Elements can be compared for equality.
* `ord`
* `deref_mut`
: `*` can be applied, yielding a mutable reference to another type
-
These are functions:
+* `fn`
+ : ___Needs filling in___
+* `fn_mut`
+ : ___Needs filling in___
+* `fn_once`
+ : ___Needs filling in___
* `str_eq`
: Compare two strings (`&str`) for equality.
* `strdup_uniq`
#### Types
-* `unsafe`
- : A type whose contents can be mutated through an immutable reference
* `type_id`
: The type returned by the `type_id` intrinsic.
+* `unsafe`
+ : A type whose contents can be mutated through an immutable reference
#### Marker types
These types help drive the compiler's analysis
-* `covariant_type`
- : The type parameter should be considered covariant
-* `contravariant_type`
- : The type parameter should be considered contravariant
-* `invariant_type`
- : The type parameter should be considered invariant
-* `covariant_lifetime`
- : The lifetime parameter should be considered covariant
-* `contravariant_lifetime`
- : The lifetime parameter should be considered contravariant
-* `invariant_lifetime`
- : The lifetime parameter should be considered invariant
-* `no_send_bound`
- : This type does not implement "send", even if eligible
+* `begin_unwind`
+ : ___Needs filling in___
* `no_copy_bound`
: This type does not implement "copy", even if eligible
+* `no_send_bound`
+ : This type does not implement "send", even if eligible
* `no_sync_bound`
: This type does not implement "sync", even if eligible
* `managed_bound`
: This type implements "managed"
-
+* `eh_personality`
+ : ___Needs filling in___
+* `exchange_free`
+ : Free memory that was allocated on the exchange heap.
+* `exchange_malloc`
+ : Allocate memory on the exchange heap.
+* `closure_exchange_malloc`
+ : ___Needs filling in___
* `fail_`
: Abort the program with an error.
* `fail_bounds_check`
: Abort the program with a bounds check error.
-* `exchange_malloc`
- : Allocate memory on the exchange heap.
-* `exchange_free`
- : Free memory that was allocated on the exchange heap.
-* `malloc`
- : Allocate memory on the managed heap.
* `free`
: Free memory that was allocated on the managed heap.
+* `gc`
+ : ___Needs filling in___
+* `exchange_heap`
+ : ___Needs filling in___
+* `managed_heap`
+ : ___Needs filling in___
+* `iterator`
+ : ___Needs filling in___
+* `contravariant_lifetime`
+ : The lifetime parameter should be considered contravariant
+* `covariant_lifetime`
+ : The lifetime parameter should be considered covariant
+* `invariant_lifetime`
+ : The lifetime parameter should be considered invariant
+* `malloc`
+ : Allocate memory on the managed heap.
+* `opaque`
+ : ___Needs filling in___
+* `owned_box`
+ : ___Needs filling in___
+* `stack_exhausted`
+ : ___Needs filling in___
+* `start`
+ : ___Needs filling in___
+* `contravariant_type`
+ : The type parameter should be considered contravariant
+* `covariant_type`
+ : The type parameter should be considered covariant
+* `invariant_type`
+ : The type parameter should be considered invariant
+* `ty_desc`
+ : ___Needs filling in___
+* `ty_visitor`
+ : ___Needs filling in___
> **Note:** This list is likely to become out of date. We should auto-generate it
> from `librustc/middle/lang_items.rs`.
* Comparison traits: `PartialEq`, `Eq`, `PartialOrd`, `Ord`.
* Serialization: `Encodable`, `Decodable`. These require `serialize`.
* `Clone`, to create `T` from `&T` via a copy.
-* `Hash`, to iterate over the bytes in a data type.
-* `Rand`, to create a random instance of a data type.
* `Default`, to create an empty instance of a data type.
-* `Zero`, to create a zero instance of a numeric data type.
* `FromPrimitive`, to create an instance from a numeric primitive.
+* `Hash`, to iterate over the bytes in a data type.
+* `Rand`, to create a random instance of a data type.
* `Show`, to format a value using the `{}` formatter.
+* `Zero`, to create a zero instance of a numeric data type.
### Stability
The currently implemented features of the reference compiler are:
-* `macro_rules` - The definition of new macros. This does not encompass
- macro-invocation, that is always enabled by default, this only
- covers the definition of new macros. There are currently
- various problems with invoking macros, how they interact with
- their environment, and possibly how they are used outside of
- location in which they are defined. Macro definitions are
- likely to change slightly in the future, so they are currently
- hidden behind this feature.
+* `asm` - The `asm!` macro provides a means for inline assembly. This is often
+ useful, but the exact syntax for this feature along with its semantics
+ are likely to change, so this macro usage must be opted into.
+
+* `concat_idents` - Allows use of the `concat_idents` macro, which is in many
+ ways insufficient for concatenating identifiers, and may
+ be removed entirely for something more wholsome.
+
+* `default_type_params` - Allows use of default type parameters. The future of
+ this feature is uncertain.
* `globs` - Importing everything in a module through `*`. This is currently a
large source of bugs in name resolution for Rust, and it's not clear
whether this will continue as a feature or not. For these reasons,
the glob import statement has been hidden behind this feature flag.
-* `struct_variant` - Structural enum variants (those with named fields). It is
- currently unknown whether this style of enum variant is as
- fully supported as the tuple-forms, and it's not certain
- that this style of variant should remain in the language.
- For now this style of variant is hidden behind a feature
- flag.
+* `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics
+ are inherently unstable and no promise about them is made.
-* `once_fns` - Onceness guarantees a closure is only executed once. Defining a
- closure as `once` is unlikely to be supported going forward. So
- they are hidden behind this feature until they are to be removed.
+* `lang_items` - Allows use of the `#[lang]` attribute. Like `intrinsics`,
+ lang items are inherently unstable and no promise about
+ them is made.
-* `asm` - The `asm!` macro provides a means for inline assembly. This is often
- useful, but the exact syntax for this feature along with its semantics
- are likely to change, so this macro usage must be opted into.
+* `link_args` - This attribute is used to specify custom flags to the linker,
+ but usage is strongly discouraged. The compiler's usage of the
+ system linker is not guaranteed to continue in the future, and
+ if the system linker is not used then specifying custom flags
+ doesn't have much meaning.
+
+* `linkage` - Allows use of the `linkage` attribute, which is not portable.
+
+* `log_syntax` - Allows use of the `log_syntax` macro attribute, which is a
+ nasty hack that will certainly be removed.
+
+* `macro_rules` - The definition of new macros. This does not encompass
+ macro-invocation, that is always enabled by default, this only
+ covers the definition of new macros. There are currently
+ various problems with invoking macros, how they interact with
+ their environment, and possibly how they are used outside of
+ location in which they are defined. Macro definitions are
+ likely to change slightly in the future, so they are currently
+ hidden behind this feature.
* `managed_boxes` - Usage of `@` is gated due to many
planned changes to this feature. In the past, this has meant
now until the specification of identifiers is fully
fleshed out.
-* `thread_local` - The usage of the `#[thread_local]` attribute is experimental
- and should be seen as unstable. This attribute is used to
- declare a `static` as being unique per-thread leveraging
- LLVM's implementation which works in concert with the kernel
- loader and dynamic linker. This is not necessarily available
- on all platforms, and usage of it is discouraged (rust
- focuses more on task-local data instead of thread-local
- data).
+* `once_fns` - Onceness guarantees a closure is only executed once. Defining a
+ closure as `once` is unlikely to be supported going forward. So
+ they are hidden behind this feature until they are to be removed.
-* `link_args` - This attribute is used to specify custom flags to the linker,
- but usage is strongly discouraged. The compiler's usage of the
- system linker is not guaranteed to continue in the future, and
- if the system linker is not used then specifying custom flags
- doesn't have much meaning.
+* `overloaded_calls` - Allow implementing the `Fn*` family of traits on user
+ types, allowing overloading the call operator (`()`).
+ This feature may still undergo changes before being
+ stabilized.
* `phase` - Usage of the `#[phase]` attribute allows loading compiler plugins
for custom lints or syntax extensions. The implementation is considered
in need of a overhaul, and it is not clear that plugins
defined using this will continue to work.
-* `log_syntax` - Allows use of the `log_syntax` macro attribute, which is a
- nasty hack that will certainly be removed.
-
-* `trace_macros` - Allows use of the `trace_macros` macro, which is a nasty
- hack that will certainly be removed.
-
-* `concat_idents` - Allows use of the `concat_idents` macro, which is in many
- ways insufficient for concatenating identifiers, and may
- be removed entirely for something more wholsome.
-
-* `unsafe_destructor` - Allows use of the `#[unsafe_destructor]` attribute,
- which is considered wildly unsafe and will be
- obsoleted by language improvements.
-
-* `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics
- are inherently unstable and no promise about them is made.
-
-* `lang_items` - Allows use of the `#[lang]` attribute. Like `intrinsics`,
- lang items are inherently unstable and no promise about
- them is made.
-
-* `simd` - Allows use of the `#[simd]` attribute, which is overly simple and
- not the SIMD interface we want to expose in the long term.
-
-* `default_type_params` - Allows use of default type parameters. The future of
- this feature is uncertain.
-
* `quote` - Allows use of the `quote_*!` family of macros, which are
implemented very poorly and will likely change significantly
with a proper implementation.
-* `linkage` - Allows use of the `linkage` attribute, which is not portable.
+* `rustc_diagnostic_macros`- A mysterious feature, used in the implementation
+ of rustc, not meant for mortals.
+
+* `simd` - Allows use of the `#[simd]` attribute, which is overly simple and
+ not the SIMD interface we want to expose in the long term.
* `struct_inherit` - Allows using struct inheritance, which is barely
implemented and will probably be removed. Don't use this.
-* `overloaded_calls` - Allow implementing the `Fn*` family of traits on user
- types, allowing overloading the call operator (`()`).
- This feature may still undergo changes before being
- stabilized.
+* `struct_variant` - Structural enum variants (those with named fields). It is
+ currently unknown whether this style of enum variant is as
+ fully supported as the tuple-forms, and it's not certain
+ that this style of variant should remain in the language.
+ For now this style of variant is hidden behind a feature
+ flag.
+
+* `thread_local` - The usage of the `#[thread_local]` attribute is experimental
+ and should be seen as unstable. This attribute is used to
+ declare a `static` as being unique per-thread leveraging
+ LLVM's implementation which works in concert with the kernel
+ loader and dynamic linker. This is not necessarily available
+ on all platforms, and usage of it is discouraged (rust
+ focuses more on task-local data instead of thread-local
+ data).
+
+* `trace_macros` - Allows use of the `trace_macros` macro, which is a nasty
+ hack that will certainly be removed.
* `unboxed_closure_sugar` - Allows using `|Foo| -> Bar` as a trait bound
meaning one of the `Fn` traits. Still
experimental.
-* `rustc_diagnostic_macros`- A mysterious feature, used in the implementation
- of rustc, not meant for mortals.
-
* `unboxed_closures` - A work in progress feature with many known bugs.
+* `unsafe_destructor` - Allows use of the `#[unsafe_destructor]` attribute,
+ which is considered wildly unsafe and will be
+ obsoleted by language improvements.
+
If a feature is promoted to a language feature, then all existing programs will
start to receive compilation warnings about #[feature] directives which enabled
the new feature (because the directive is no longer necessary). However, if
References arise by (automatic) conversion from owning pointers, managed pointers,
or by applying the borrowing operator `&` to some other value,
including [lvalues, rvalues or temporaries](#lvalues,-rvalues-and-temporaries).
- References are written `&content`, or in some cases `&'f content` for some lifetime-variable `f`,
+ A borrow expression is written `&content`.
+
+ A reference type is written `&'f type` for some lifetime-variable `f`,
+ or just `&type` when the lifetime can be elided;
for example `&int` means a reference to an integer.
Copying a reference is a "shallow" operation:
it involves only copying the pointer itself.
f.write("""
fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
use core::cmp::{Equal, Less, Greater};
- use core::slice::ImmutableVector;
- use core::option::None;
- r.bsearch(|&(lo,hi)| {
+ use core::slice::ImmutableSlice;
+ r.binary_search(|&(lo,hi)| {
if lo <= c && c <= hi { Equal }
else if hi < c { Less }
else { Greater }
- }) != None
+ }).found().is_some()
}\n
""")
f.write("pub mod conversions {")
f.write("""
use core::cmp::{Equal, Less, Greater};
- use core::slice::ImmutableVector;
+ use core::slice::ImmutableSlice;
use core::tuple::Tuple2;
use core::option::{Option, Some, None};
+ use core::slice;
pub fn to_lower(c: char) -> char {
match bsearch_case_table(c, LuLl_table) {
}
fn bsearch_case_table(c: char, table: &'static [(char, char)]) -> Option<uint> {
- table.bsearch(|&(key, _)| {
+ match table.binary_search(|&(key, _)| {
if c == key { Equal }
else if key < c { Less }
else { Greater }
- })
+ }) {
+ slice::Found(i) => Some(i),
+ slice::NotFound(_) => None,
+ }
}
""")
def emit_grapheme_module(f, grapheme_table, grapheme_cats):
f.write("""pub mod grapheme {
- use core::option::{Some, None};
- use core::slice::ImmutableVector;
+ use core::slice::ImmutableSlice;
+ use core::slice;
#[allow(non_camel_case_types)]
#[deriving(Clone)]
fn bsearch_range_value_table(c: char, r: &'static [(char, char, GraphemeCat)]) -> GraphemeCat {
use core::cmp::{Equal, Less, Greater};
- match r.bsearch(|&(lo, hi, _)| {
+ match r.binary_search(|&(lo, hi, _)| {
if lo <= c && c <= hi { Equal }
else if hi < c { Less }
else { Greater }
}) {
- Some(idx) => {
+ slice::Found(idx) => {
let (_, _, cat) = r[idx];
cat
}
- None => GC_Any
+ slice::NotFound(_) => GC_Any
}
}
def emit_charwidth_module(f, width_table):
f.write("pub mod charwidth {\n")
f.write(" use core::option::{Option, Some, None};\n")
- f.write(" use core::slice::ImmutableVector;\n")
+ f.write(" use core::slice::ImmutableSlice;\n")
+ f.write(" use core::slice;\n")
f.write("""
fn bsearch_range_value_table(c: char, is_cjk: bool, r: &'static [(char, char, u8, u8)]) -> u8 {
use core::cmp::{Equal, Less, Greater};
- match r.bsearch(|&(lo, hi, _, _)| {
+ match r.binary_search(|&(lo, hi, _, _)| {
if lo <= c && c <= hi { Equal }
else if hi < c { Less }
else { Greater }
}) {
- Some(idx) => {
+ slice::Found(idx) => {
let (_, _, r_ncjk, r_cjk) = r[idx];
if is_cjk { r_cjk } else { r_ncjk }
}
- None => 1
+ slice::NotFound(_) => 1
}
}
""")
f.write("""
fn bsearch_range_value_table(c: char, r: &'static [(char, char, u8)]) -> u8 {
- use core::option::{Some, None};
use core::cmp::{Equal, Less, Greater};
- use core::slice::ImmutableVector;
- match r.bsearch(|&(lo, hi, _)| {
+ use core::slice::ImmutableSlice;
+ use core::slice;
+ match r.binary_search(|&(lo, hi, _)| {
if lo <= c && c <= hi { Equal }
else if hi < c { Less }
else { Greater }
}) {
- Some(idx) => {
+ slice::Found(idx) => {
let (_, _, result) = r[idx];
result
}
- None => 0
+ slice::NotFound(_) => 0
}
}\n
""")
assert!(i < self.nbits);
let w = i / uint::BITS;
let b = i % uint::BITS;
- let x = self.storage.get(w) & (1 << b);
+ let x = self.storage[w] & (1 << b);
x != 0
}
let w = i / uint::BITS;
let b = i % uint::BITS;
let flag = 1 << b;
- *self.storage.get_mut(w) = if x { *self.storage.get(w) | flag }
- else { *self.storage.get(w) & !flag };
+ *self.storage.get_mut(w) = if x { self.storage[w] | flag }
+ else { self.storage[w] & !flag };
}
/// Set all bits to 1.
fn clone_from(&mut self, source: &Bitv) {
self.nbits = source.nbits;
self.storage.reserve(source.storage.len());
- for (i, w) in self.storage.mut_iter().enumerate() { *w = *source.storage.get(i); }
+ for (i, w) in self.storage.mut_iter().enumerate() { *w = source.storage[i]; }
}
}
self_bitv.reserve(other_bitv.capacity());
// Apply values
for (i, w) in other_bitv.mask_words(0) {
- let old = *self_bitv.storage.get(i);
+ let old = self_bitv.storage[i];
let new = f(old, w);
*self_bitv.storage.get_mut(i) = new;
}
// one Bitv might be longer than the other
let word_idx = self.next_idx / uint::BITS;
let w1 = if word_idx < s_bitv.storage.len() {
- *s_bitv.storage.get(word_idx)
+ s_bitv.storage[word_idx]
} else { 0 };
let w2 = if word_idx < o_bitv.storage.len() {
- *o_bitv.storage.get(word_idx)
+ o_bitv.storage[word_idx]
} else { 0 };
self.current_word = (self.merge)(w1, w2);
}
midpoint = 0;
}
loop {
- let order = self.elts.get(midpoint).key.cmp(&k);
+ let order = self.elts[midpoint].key.cmp(&k);
match order {
Equal => {
return None;
}
Greater => {
if midpoint > 0 {
- if self.elts.get(midpoint - 1).key.cmp(&k) == Less {
+ if self.elts[midpoint - 1].key.cmp(&k) == Less {
return Some(midpoint);
}
else {
}
Less => {
if midpoint + 1 < self.elts.len() {
- if self.elts.get(midpoint + 1).key.cmp(&k) == Greater {
+ if self.elts[midpoint + 1].key.cmp(&k) == Greater {
return Some(midpoint);
}
else {
if self.elts.len() < other.elts.len() {
return Less;
}
- self.elts.get(0).cmp(other.elts.get(0))
+ self.elts[0].cmp(&other.elts[0])
}
}
midpoint = 0u;
}
loop {
- let order = self.elts.get(midpoint).key.cmp(&k);
+ let order = self.elts[midpoint].key.cmp(&k);
match order {
Equal => {
return None;
}
Greater => {
if midpoint > 0 {
- if self.elts.get(midpoint - 1).key.cmp(&k) == Less {
+ if self.elts[midpoint - 1].key.cmp(&k) == Less {
return Some(midpoint);
}
else {
}
Less => {
if midpoint + 1 < self.elts.len() {
- if self.elts.get(midpoint + 1).key.cmp(&k) == Greater {
+ if self.elts[midpoint + 1].key.cmp(&k) == Greater {
return Some(midpoint);
}
else {
Some(i) => {
if i == self.elts.len() {
let new_outcome = self.clone().rightmost_child.insert(k.clone(),
- v.clone(),
- ub.clone());
+ v.clone(),
+ ub.clone());
new_branch = new_outcome.clone().val0();
outcome = new_outcome.val1();
}
else {
- let new_outcome = self.elts.get(i).left.clone().insert(k.clone(),
- v.clone(),
- ub.clone());
+ let new_outcome = self.elts[i].left.clone().insert(k.clone(),
+ v.clone(),
+ ub.clone());
new_branch = new_outcome.clone().val0();
outcome = new_outcome.val1();
}
//If we have a new branch node, attempt to insert it into the tree
//as with the key-value pair, then check to see if the node is overfull.
BranchNode(branch) => {
- let new_elt = branch.elts.get(0).clone();
+ let new_elt = branch.elts[0].clone();
let new_elt_index = self.bsearch_branch(new_elt.clone().key);
match new_elt_index {
None => {
if self.elts.len() < other.elts.len() {
return Less;
}
- self.elts.get(0).cmp(other.elts.get(0))
+ self.elts[0].cmp(&other.elts[0])
}
}
impl<A> DoubleEndedIterator<A> for MoveItems<A> {
#[inline]
- fn next_back(&mut self) -> Option<A> { self.list.pop_back() }
+ fn next_back(&mut self) -> Option<A> { self.list.pop() }
}
impl<A> FromIterator<A> for DList<A> {
impl<A> Extendable<A> for DList<A> {
fn extend<T: Iterator<A>>(&mut self, mut iterator: T) {
- for elt in iterator { self.push_back(elt); }
+ for elt in iterator { self.push(elt); }
}
}
use std::prelude::*;
use std::mem;
- use slice::ImmutableVector;
+ use slice::ImmutableSlice;
use super::{Hash, Hasher, Writer};
struct MyWriterHasher;
use str::Str;
use string::String;
- use slice::{Vector, ImmutableVector};
+ use slice::{Slice, ImmutableSlice};
use vec::Vec;
use super::super::{Hash, Writer};
///
/// ```
pub fn top<'a>(&'a self) -> Option<&'a T> {
- if self.is_empty() { None } else { Some(self.data.get(0)) }
+ if self.is_empty() { None } else { Some(&self.data[0]) }
}
#[deprecated="renamed to `top`"]
while pos > start {
let parent = (pos - 1) >> 1;
- if new > *self.data.get(parent) {
+ if new > self.data[parent] {
let x = replace(self.data.get_mut(parent), zeroed());
ptr::write(self.data.get_mut(pos), x);
pos = parent;
let mut child = 2 * pos + 1;
while child < end {
let right = child + 1;
- if right < end && !(*self.data.get(child) > *self.data.get(right)) {
+ if right < end && !(self.data[child] > self.data[right]) {
child = right;
}
let x = replace(self.data.get_mut(child), zeroed());
impl<T> Deque<T> for RingBuf<T> {
/// Return a reference to the first element in the RingBuf
fn front<'a>(&'a self) -> Option<&'a T> {
- if self.nelts > 0 { Some(self.get(0)) } else { None }
+ if self.nelts > 0 { Some(&self[0]) } else { None }
}
/// Return a mutable reference to the first element in the RingBuf
/// Return a reference to the last element in the RingBuf
fn back<'a>(&'a self) -> Option<&'a T> {
- if self.nelts > 0 { Some(self.get(self.nelts - 1)) } else { None }
+ if self.nelts > 0 { Some(&self[self.nelts - 1]) } else { None }
}
/// Return a mutable reference to the last element in the RingBuf
#[deprecated = "prefer using indexing, e.g., ringbuf[0]"]
pub fn get<'a>(&'a self, i: uint) -> &'a T {
let idx = self.raw_index(i);
- match *self.elts.get(idx) {
+ match self.elts[idx] {
None => fail!(),
Some(ref v) => v
}
impl<'a, T> Iterator<&'a mut T> for MutItems<'a, T> {
#[inline]
+ #[allow(deprecated)] // mut_shift_ref
fn next(&mut self) -> Option<&'a mut T> {
if self.nelts == 0 {
return None;
impl<'a, T> DoubleEndedIterator<&'a mut T> for MutItems<'a, T> {
#[inline]
+ #[allow(deprecated)] // mut_shift_ref
fn next_back(&mut self) -> Option<&'a mut T> {
if self.nelts == 0 {
return None;
impl<A> Index<uint, A> for RingBuf<A> {
#[inline]
+ #[allow(deprecated)]
fn index<'a>(&'a self, i: &uint) -> &'a A {
self.get(*i)
}
impl<A> Extendable<A> for RingBuf<A> {
fn extend<T: Iterator<A>>(&mut self, mut iterator: T) {
for elt in iterator {
- self.push_back(elt);
+ self.push(elt);
}
}
}
## Traits
A number of traits add methods that allow you to accomplish tasks with slices.
-These traits include `ImmutableVector`, which is defined for `&[T]` types,
-and `MutableVector`, defined for `&mut [T]` types.
+These traits include `ImmutableSlice`, which is defined for `&[T]` types,
+and `MutableSlice`, defined for `&mut [T]` types.
An example is the method `.slice(a, b)` that returns an immutable "view" into
a `Vec` or another slice from the index interval `[a, b)`:
use vec::Vec;
pub use core::slice::{ref_slice, mut_ref_slice, Splits, Windows};
-pub use core::slice::{Chunks, Vector, ImmutableVector, ImmutableEqVector};
-pub use core::slice::{ImmutableOrdVector, MutableVector, Items, MutItems};
+pub use core::slice::{Chunks, Slice, ImmutableSlice, ImmutablePartialEqSlice};
+pub use core::slice::{ImmutableOrdSlice, MutableSlice, Items, MutItems};
pub use core::slice::{MutSplits, MutChunks};
-pub use core::slice::{bytes, MutableCloneableVector};
+pub use core::slice::{bytes, MutableCloneableSlice};
+pub use core::slice::{BinarySearchResult, Found, NotFound};
// Functional utilities
fn connect_vec(&self, sep: &T) -> Vec<T>;
}
-impl<'a, T: Clone, V: Vector<T>> VectorVector<T> for &'a [V] {
+impl<'a, T: Clone, V: Slice<T>> VectorVector<T> for &'a [V] {
fn concat_vec(&self) -> Vec<T> {
let size = self.iter().fold(0u, |acc, v| acc + v.as_slice().len());
let mut result = Vec::with_capacity(size);
let max = self.sdir.iter().map(|&x| x).enumerate()
.filter(|&(i, sd)|
new_pos(i, sd.dir) < self.sdir.len() &&
- self.sdir.get(new_pos(i, sd.dir)).size < sd.size)
+ self.sdir[new_pos(i, sd.dir)].size < sd.size)
.max_by(|&(_, sd)| sd.size);
match max {
Some((i, sd)) => {
/// Extension methods for vectors such that their elements are
/// mutable.
-pub trait MutableVectorAllocating<'a, T> {
+pub trait MutableSliceAllocating<'a, T> {
/// Sort the vector, in place, using `compare` to compare
/// elements.
///
fn move_from(self, src: Vec<T>, start: uint, end: uint) -> uint;
}
-impl<'a,T> MutableVectorAllocating<'a, T> for &'a mut [T] {
+impl<'a,T> MutableSliceAllocating<'a, T> for &'a mut [T] {
#[inline]
fn sort_by(self, compare: |&T, &T| -> Ordering) {
merge_sort(self, compare)
/// Methods for mutable vectors with orderable elements, such as
/// in-place sorting.
-pub trait MutableOrdVector<T> {
+pub trait MutableOrdSlice<T> {
/// Sort the vector, in place.
///
/// This is equivalent to `self.sort_by(|a, b| a.cmp(b))`.
fn prev_permutation(self) -> bool;
}
-impl<'a, T: Ord> MutableOrdVector<T> for &'a mut [T] {
+impl<'a, T: Ord> MutableOrdSlice<T> for &'a mut [T] {
#[inline]
fn sort(self) {
self.sort_by(|a,b| a.cmp(b))
/// Return a reference to the value corresponding to the key.
fn find<'a>(&'a self, key: &uint) -> Option<&'a V> {
if *key < self.v.len() {
- match *self.v.get(*key) {
+ match self.v[*key] {
Some(ref value) => Some(value),
None => None
}
impl<V> Index<uint, V> for SmallIntMap<V> {
#[inline]
+ #[allow(deprecated)]
fn index<'a>(&'a self, i: &uint) -> &'a V {
self.get(i)
}
match self.buffer.as_slice().head() {
Some(&(c, 0)) => {
self.sorted = false;
- self.buffer.shift();
+ self.buffer.remove(0);
return Some(c);
}
Some(&(c, _)) if self.sorted => {
- self.buffer.shift();
+ self.buffer.remove(0);
return Some(c);
}
_ => self.sorted = false
self.sorted = true;
}
- match self.buffer.shift() {
+ match self.buffer.remove(0) {
Some((c, 0)) => {
self.sorted = false;
Some(c)
for (j, tc) in t.chars().enumerate() {
- let next = *dcol.get(j + 1);
+ let next = dcol[j + 1];
if sc == tc {
*dcol.get_mut(j + 1) = current;
} else {
*dcol.get_mut(j + 1) = cmp::min(current, next);
- *dcol.get_mut(j + 1) = cmp::min(*dcol.get(j + 1),
- *dcol.get(j)) + 1;
+ *dcol.get_mut(j + 1) = cmp::min(dcol[j + 1],
+ dcol[j]) + 1;
}
current = next;
}
}
- return *dcol.get(tlen);
+ return dcol[tlen];
}
/// An Iterator over the string in Unicode Normalization Form D
use {Collection, MutableSeq};
use super::*;
- use std::slice::{Vector, ImmutableVector};
+ use std::slice::{Slice, ImmutableSlice};
use string::String;
use vec::Vec;
fn test_splitn_char_iterator() {
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
- let split: Vec<&str> = data.splitn(' ', 3).collect();
+ let split: Vec<&str> = data.splitn(3, ' ').collect();
assert_eq!(split, vec!["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
- let split: Vec<&str> = data.splitn(|c: char| c == ' ', 3).collect();
+ let split: Vec<&str> = data.splitn(3, |c: char| c == ' ').collect();
assert_eq!(split, vec!["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
// Unicode
- let split: Vec<&str> = data.splitn('ä', 3).collect();
+ let split: Vec<&str> = data.splitn(3, 'ä').collect();
assert_eq!(split, vec!["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
- let split: Vec<&str> = data.splitn(|c: char| c == 'ä', 3).collect();
+ let split: Vec<&str> = data.splitn(3, |c: char| c == 'ä').collect();
assert_eq!(split, vec!["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
}
fn test_rsplitn_char_iterator() {
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
- let mut split: Vec<&str> = data.rsplitn(' ', 3).collect();
+ let mut split: Vec<&str> = data.rsplitn(3, ' ').collect();
split.reverse();
assert_eq!(split, vec!["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
- let mut split: Vec<&str> = data.rsplitn(|c: char| c == ' ', 3).collect();
+ let mut split: Vec<&str> = data.rsplitn(3, |c: char| c == ' ').collect();
split.reverse();
assert_eq!(split, vec!["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
// Unicode
- let mut split: Vec<&str> = data.rsplitn('ä', 3).collect();
+ let mut split: Vec<&str> = data.rsplitn(3, 'ä').collect();
split.reverse();
assert_eq!(split, vec!["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
- let mut split: Vec<&str> = data.rsplitn(|c: char| c == 'ä', 3).collect();
+ let mut split: Vec<&str> = data.rsplitn(3, |c: char| c == 'ä').collect();
split.reverse();
assert_eq!(split, vec!["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
}
use core::fmt;
use core::mem;
use core::ptr;
-use core::raw::Slice;
+// FIXME: ICE's abound if you import the `Slice` type while importing `Slice` trait
+use RawSlice = core::raw::Slice;
+use core::slice::Slice;
use {Collection, Mutable, MutableSeq};
use hash;
use str;
-use str::{CharRange, StrAllocating, MaybeOwned, Owned, Slice};
+use str::{CharRange, StrAllocating, MaybeOwned, Owned};
+use MaybeOwnedSlice = str::Slice; // So many `Slice`s...
use vec::Vec;
/// A growable string stored as a UTF-8 encoded buffer.
/// ```
pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> MaybeOwned<'a> {
if str::is_utf8(v) {
- return Slice(unsafe { mem::transmute(v) })
+ return MaybeOwnedSlice(unsafe { mem::transmute(v) })
}
static TAG_CONT_U8: u8 = 128u8;
let mut i = 0;
let total = v.len();
fn unsafe_get(xs: &[u8], i: uint) -> u8 {
- unsafe { *xs.unsafe_ref(i) }
+ unsafe { *xs.unsafe_get(i) }
}
fn safe_get(xs: &[u8], i: uint, total: uint) -> u8 {
if i >= total {
unsafe {
// Attempt to not use an intermediate buffer by just pushing bytes
// directly onto this string.
- let slice = Slice {
+ let slice = RawSlice {
data: self.vec.as_ptr().offset(cur_len as int),
len: 4,
};
/// }
/// ```
pub unsafe fn shift_byte(&mut self) -> Option<u8> {
- self.vec.shift()
+ self.vec.remove(0)
}
/// Removes the first character from the string buffer and returns it.
// such thing as invalid pointers and memory unsafety. The
// reason is performance, without doing this we can get the
// bench_iter_large microbenchmark down to about 30000 ns/iter
- // (using .unsafe_ref to index self.stack directly, 38000
+ // (using .unsafe_get to index self.stack directly, 38000
// ns/iter with [] checked indexing), but this smashes that down
// to 13500 ns/iter.
//
use core::prelude::*;
use alloc::heap::{allocate, reallocate, deallocate};
-use core::raw::Slice;
+use RawSlice = core::raw::Slice;
+use core::slice::Slice;
use core::cmp::max;
use core::default::Default;
use core::fmt;
use core::uint;
use {Collection, Mutable, MutableSeq};
-use slice::{MutableOrdVector, MutableVectorAllocating, CloneableVector};
+use slice::{MutableOrdSlice, MutableSliceAllocating, CloneableVector};
use slice::{Items, MutItems};
unsafe {
ptr::write(
self.as_mut_slice().unsafe_mut_ref(len),
- other.unsafe_ref(i).clone());
+ other.unsafe_get(i).clone());
self.set_len(len + 1);
}
}
impl<T> Index<uint,T> for Vec<T> {
#[inline]
+ #[allow(deprecated)] // allow use of get
fn index<'a>(&'a self, index: &uint) -> &'a T {
self.get(*index)
}
impl<T: Eq> Eq for Vec<T> {}
-impl<T: PartialEq, V: Vector<T>> Equiv<V> for Vec<T> {
+impl<T: PartialEq, V: Slice<T>> Equiv<V> for Vec<T> {
#[inline]
fn equiv(&self, other: &V) -> bool { self.as_slice() == other.as_slice() }
}
// decrement len before the read(), so a failure on Drop doesn't
// re-drop the just-failed value.
self.len -= 1;
- ptr::read(self.as_slice().unsafe_ref(self.len));
+ ptr::read(self.as_slice().unsafe_get(self.len));
}
}
}
#[inline]
pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
unsafe {
- mem::transmute(Slice {
+ mem::transmute(RawSlice {
data: self.as_mut_ptr() as *const T,
len: self.len,
})
/// assert!(vec.tailn(2) == [3, 4]);
/// ```
#[inline]
+ #[deprecated = "use slice_from"]
pub fn tailn<'a>(&'a self, n: uint) -> &'a [T] {
- self.as_slice().tailn(n)
+ self.as_slice().slice_from(n)
}
/// Returns a reference to the last element of a vector, or `None` if it is
}
}
-impl<T> Vector<T> for Vec<T> {
+impl<T> Slice<T> for Vec<T> {
/// Work with `self` as a slice.
///
/// # Example
/// ```
#[inline]
fn as_slice<'a>(&'a self) -> &'a [T] {
- unsafe { mem::transmute(Slice { data: self.as_ptr(), len: self.len }) }
+ unsafe { mem::transmute(RawSlice { data: self.as_ptr(), len: self.len }) }
}
}
-impl<T: Clone, V: Vector<T>> Add<V, Vec<T>> for Vec<T> {
+impl<T: Clone, V: Slice<T>> Add<V, Vec<T>> for Vec<T> {
#[inline]
fn add(&self, rhs: &V) -> Vec<T> {
let mut res = Vec::with_capacity(self.len() + rhs.as_slice().len());
} else {
unsafe {
self.len -= 1;
- Some(ptr::read(self.as_slice().unsafe_ref(self.len())))
+ Some(ptr::read(self.as_slice().unsafe_get(self.len())))
}
}
}
use num::{Float, FPNaN, FPInfinite, ToPrimitive, Primitive};
use num::{Zero, One, cast};
use result::Ok;
-use slice::{ImmutableVector, MutableVector};
+use slice::{ImmutableSlice, MutableSlice};
use slice;
use str::StrSlice;
use iter::{Iterator, range};
use kinds::Copy;
use mem;
+use num::Float;
use option::{Option, Some, None};
use ops::Deref;
use result::{Ok, Err};
use result;
-use slice::{Vector, ImmutableVector};
+use slice::{Slice, ImmutableSlice};
use slice;
use str::StrSlice;
use str;
float::ExpNone,
false,
|bytes| {
- fmt.pad_integral(*self >= 0.0, "", bytes)
+ fmt.pad_integral(self.is_nan() || *self >= 0.0, "", bytes)
})
}
}
float::ExpDec,
false,
|bytes| {
- fmt.pad_integral(*self >= 0.0, "", bytes)
+ fmt.pad_integral(self.is_nan() || *self >= 0.0, "", bytes)
})
}
}
float::ExpDec,
true,
|bytes| {
- fmt.pad_integral(*self >= 0.0, "", bytes)
+ fmt.pad_integral(self.is_nan() || *self >= 0.0, "", bytes)
})
}
}
use fmt;
use iter::DoubleEndedIterator;
use num::{Int, cast, zero};
-use slice::{ImmutableVector, MutableVector};
+use slice::{ImmutableSlice, MutableSlice};
/// A type that represents a specific radix
#[doc(hidden)]
/// ```
pub fn transmute<T,U>(e: T) -> U;
+ /// Gives the address for the return value of the enclosing function.
+ ///
+ /// Using this instrinsic in a function that does not use an out pointer
+ /// will trigger a compiler error.
+ #[cfg(not(stage0))]
+ pub fn return_address() -> *const u8;
+
/// Returns `true` if a type requires drop glue.
pub fn needs_drop<T>() -> bool;
use cmp::{PartialEq, Eq, Ord};
use default::Default;
-use slice::Vector;
+use slice::Slice;
use iter::{Iterator, DoubleEndedIterator, FromIterator, ExactSize};
use mem;
use slice;
// Trait implementations
/////////////////////////////////////////////////////////////////////////////
-impl<T> Vector<T> for Option<T> {
+impl<T> Slice<T> for Option<T> {
/// Convert from `Option<T>` to `&[T]` (without copying)
#[inline]
fn as_slice<'a>(&'a self) -> &'a [T] {
pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4};
pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8};
pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12};
-pub use slice::{ImmutableEqVector, ImmutableOrdVector};
-pub use slice::{MutableVector};
-pub use slice::{Vector, ImmutableVector};
+pub use slice::{ImmutablePartialEqSlice, ImmutableOrdSlice};
+pub use slice::{MutableSlice};
+pub use slice::{Slice, ImmutableSlice};
//!
//! For more details `std::slice`.
+#![stable]
#![doc(primitive = "slice")]
// How this module is organized.
use mem;
use mem::size_of;
use kinds::marker;
-use raw::{Repr, Slice};
+use raw::Repr;
+// Avoid conflicts with *both* the Slice trait (buggy) and the `slice::raw` module.
+use RawSlice = raw::Slice;
+
//
// Extension traits
//
/// Extension methods for vectors
-pub trait ImmutableVector<'a, T> {
+#[unstable = "may merge with other traits; region parameter may disappear"]
+pub trait ImmutableSlice<'a, T> {
/**
* Returns a slice of self spanning the interval [`start`, `end`).
*
* Fails when the slice (or part of it) is outside the bounds of self,
* or when `start` > `end`.
*/
+ #[unstable]
fn slice(&self, start: uint, end: uint) -> &'a [T];
/**
*
* Fails when `start` points outside the bounds of self.
*/
+ #[unstable]
fn slice_from(&self, start: uint) -> &'a [T];
/**
*
* Fails when `end` points outside the bounds of self.
*/
+ #[unstable]
fn slice_to(&self, end: uint) -> &'a [T];
/// Divides one slice into two at an index.
/// indices from `[mid, len)` (excluding the index `len` itself).
///
/// Fails if `mid > len`.
+ #[unstable]
fn split_at(&self, mid: uint) -> (&'a [T], &'a [T]);
/// Returns an iterator over the vector
+ #[unstable = "iterator type may change"]
fn iter(self) -> Items<'a, T>;
/// Returns an iterator over the subslices of the vector which are
/// separated by elements that match `pred`. The matched element
/// is not contained in the subslices.
+ #[unstable = "iterator type may change"]
fn split(self, pred: |&T|: 'a -> bool) -> Splits<'a, T>;
/// Returns an iterator over the subslices of the vector which are
/// separated by elements that match `pred`, limited to splitting
/// at most `n` times. The matched element is not contained in
/// the subslices.
+ #[unstable = "iterator type may change"]
fn splitn(self, n: uint, pred: |&T|: 'a -> bool) -> SplitsN<'a, T>;
/// Returns an iterator over the subslices of the vector which are
/// separated by elements that match `pred` limited to splitting
/// at most `n` times. This starts at the end of the vector and
/// works backwards. The matched element is not contained in the
/// subslices.
+ #[unstable = "iterator type may change"]
fn rsplitn(self, n: uint, pred: |&T|: 'a -> bool) -> SplitsN<'a, T>;
/**
* ```
*
*/
+ #[unstable = "iterator type may change"]
fn windows(self, size: uint) -> Windows<'a, T>;
/**
*
* ```
*
*/
+ #[unstable = "iterator type may change"]
fn chunks(self, size: uint) -> Chunks<'a, T>;
/// Returns the element of a vector at the given index, or `None` if the
/// index is out of bounds
+ #[unstable]
fn get(&self, index: uint) -> Option<&'a T>;
/// Returns the first element of a vector, or `None` if it is empty
+ #[unstable = "name may change"]
fn head(&self) -> Option<&'a T>;
/// Returns all but the first element of a vector
+ #[unstable = "name may change"]
fn tail(&self) -> &'a [T];
/// Returns all but the first `n' elements of a vector
+ #[deprecated = "use slice_from"]
fn tailn(&self, n: uint) -> &'a [T];
/// Returns all but the last element of a vector
+ #[unstable = "name may change"]
fn init(&self) -> &'a [T];
/// Returns all but the last `n' elements of a vector
+ #[deprecated = "use slice_to but note the arguments are different"]
fn initn(&self, n: uint) -> &'a [T];
/// Returns the last element of a vector, or `None` if it is empty.
+ #[unstable = "name may change"]
fn last(&self) -> Option<&'a T>;
/// Returns a pointer to the element at the given index, without doing
/// bounds checking.
+ #[deprecated = "renamed to `unsafe_get`"]
unsafe fn unsafe_ref(self, index: uint) -> &'a T;
+ /// Returns a pointer to the element at the given index, without doing
+ /// bounds checking.
+ #[unstable]
+ unsafe fn unsafe_get(self, index: uint) -> &'a T;
+
/**
* Returns an unsafe pointer to the vector's buffer
*
* Modifying the vector may cause its buffer to be reallocated, which
* would also make any pointers to it invalid.
*/
+ #[unstable]
fn as_ptr(&self) -> *const T;
/**
* Returns the index where the comparator returned `Equal`, or `None` if
* not found.
*/
+ #[deprecated = "use binary_search"]
fn bsearch(&self, f: |&T| -> Ordering) -> Option<uint>;
+ /// Binary search a sorted vector with a comparator function.
+ ///
+ /// The comparator function should implement an order consistent
+ /// with the sort order of the underlying vector, returning an
+ /// order code that indicates whether its argument is `Less`,
+ /// `Equal` or `Greater` the desired target.
+ ///
+ /// If the value is found then `Found` is returned, containing the
+ /// index of the matching element; if the value is not found then
+ /// `NotFound` is returned, containing the index where a matching
+ /// element could be inserted while maintaining sorted order.
+ #[unstable]
+ fn binary_search(&self, f: |&T| -> Ordering) -> BinarySearchResult;
+
/**
* Returns an immutable reference to the first element in this slice
* and adjusts the slice in place so that it no longer contains
*
* Returns `None` if vector is empty
*/
+ #[deprecated = "find some other way. sorry"]
fn shift_ref(&mut self) -> Option<&'a T>;
/**
*
* Returns `None` if slice is empty.
*/
+ #[deprecated = "find some other way. sorry"]
fn pop_ref(&mut self) -> Option<&'a T>;
}
-impl<'a,T> ImmutableVector<'a, T> for &'a [T] {
+#[unstable]
+impl<'a,T> ImmutableSlice<'a, T> for &'a [T] {
#[inline]
fn slice(&self, start: uint, end: uint) -> &'a [T] {
assert!(start <= end);
assert!(end <= self.len());
unsafe {
- transmute(Slice {
+ transmute(RawSlice {
data: self.as_ptr().offset(start as int),
len: (end - start)
})
fn tail(&self) -> &'a [T] { self.slice(1, self.len()) }
#[inline]
+ #[deprecated = "use slice_from"]
fn tailn(&self, n: uint) -> &'a [T] { self.slice(n, self.len()) }
#[inline]
}
#[inline]
+ #[deprecated = "use slice_to but note the arguments are different"]
fn initn(&self, n: uint) -> &'a [T] {
self.slice(0, self.len() - n)
}
}
#[inline]
+ #[deprecated = "renamed to `unsafe_get`"]
unsafe fn unsafe_ref(self, index: uint) -> &'a T {
transmute(self.repr().data.offset(index as int))
}
+ #[inline]
+ unsafe fn unsafe_get(self, index: uint) -> &'a T {
+ transmute(self.repr().data.offset(index as int))
+ }
+
#[inline]
fn as_ptr(&self) -> *const T {
self.repr().data
}
+ #[deprecated = "use binary_search"]
fn bsearch(&self, f: |&T| -> Ordering) -> Option<uint> {
let mut base : uint = 0;
let mut lim : uint = self.len();
return None;
}
+ #[unstable]
+ fn binary_search(&self, f: |&T| -> Ordering) -> BinarySearchResult {
+ let mut base : uint = 0;
+ let mut lim : uint = self.len();
+
+ while lim != 0 {
+ let ix = base + (lim >> 1);
+ match f(&self[ix]) {
+ Equal => return Found(ix),
+ Less => {
+ base = ix + 1;
+ lim -= 1;
+ }
+ Greater => ()
+ }
+ lim >>= 1;
+ }
+ return NotFound(base);
+ }
+
fn shift_ref(&mut self) -> Option<&'a T> {
unsafe {
- let s: &mut Slice<T> = transmute(self);
+ let s: &mut RawSlice<T> = transmute(self);
match raw::shift_ptr(s) {
Some(p) => Some(&*p),
None => None
fn pop_ref(&mut self) -> Option<&'a T> {
unsafe {
- let s: &mut Slice<T> = transmute(self);
+ let s: &mut RawSlice<T> = transmute(self);
match raw::pop_ptr(s) {
Some(p) => Some(&*p),
None => None
/// Extension methods for vectors such that their elements are
/// mutable.
-pub trait MutableVector<'a, T> {
+#[experimental = "may merge with other traits; may lose region param; needs review"]
+pub trait MutableSlice<'a, T> {
/// Returns a mutable reference to the element at the given index,
/// or `None` if the index is out of bounds
fn get_mut(self, index: uint) -> Option<&'a mut T>;
*
* Returns `None` if slice is empty
*/
+ #[deprecated = "find some other way. sorry"]
fn mut_shift_ref(&mut self) -> Option<&'a mut T>;
/**
*
* Returns `None` if slice is empty.
*/
+ #[deprecated = "find some other way. sorry"]
fn mut_pop_ref(&mut self) -> Option<&'a mut T>;
/// Swaps two elements in a vector.
unsafe fn copy_memory(self, src: &[T]);
}
-impl<'a,T> MutableVector<'a, T> for &'a mut [T] {
+#[experimental = "trait is experimental"]
+impl<'a,T> MutableSlice<'a, T> for &'a mut [T] {
#[inline]
fn get_mut(self, index: uint) -> Option<&'a mut T> {
if index < self.len() { Some(&mut self[index]) } else { None }
assert!(start <= end);
assert!(end <= self.len());
unsafe {
- transmute(Slice {
+ transmute(RawSlice {
data: self.as_mut_ptr().offset(start as int) as *const T,
len: (end - start)
})
fn mut_shift_ref(&mut self) -> Option<&'a mut T> {
unsafe {
- let s: &mut Slice<T> = transmute(self);
+ let s: &mut RawSlice<T> = transmute(self);
match raw::shift_ptr(s) {
// FIXME #13933: this `&` -> `&mut` cast is a little
// dubious
fn mut_pop_ref(&mut self) -> Option<&'a mut T> {
unsafe {
- let s: &mut Slice<T> = transmute(self);
+ let s: &mut RawSlice<T> = transmute(self);
match raw::pop_ptr(s) {
// FIXME #13933: this `&` -> `&mut` cast is a little
// dubious
}
/// Extension methods for vectors contain `PartialEq` elements.
-pub trait ImmutableEqVector<T:PartialEq> {
+#[unstable = "may merge with other traits"]
+pub trait ImmutablePartialEqSlice<T:PartialEq> {
/// Find the first index containing a matching value
fn position_elem(&self, t: &T) -> Option<uint>;
fn ends_with(&self, needle: &[T]) -> bool;
}
-impl<'a,T:PartialEq> ImmutableEqVector<T> for &'a [T] {
+#[unstable = "trait is unstable"]
+impl<'a,T:PartialEq> ImmutablePartialEqSlice<T> for &'a [T] {
#[inline]
fn position_elem(&self, x: &T) -> Option<uint> {
self.iter().position(|y| *x == *y)
}
/// Extension methods for vectors containing `Ord` elements.
-pub trait ImmutableOrdVector<T: Ord> {
+#[unstable = "may merge with other traits"]
+pub trait ImmutableOrdSlice<T: Ord> {
/**
* Binary search a sorted vector for a given element.
*
* Returns the index of the element or None if not found.
*/
+ #[deprecated = "use binary_search_elem"]
fn bsearch_elem(&self, x: &T) -> Option<uint>;
+
+ /**
+ * Binary search a sorted vector for a given element.
+ *
+ * If the value is found then `Found` is returned, containing the
+ * index of the matching element; if the value is not found then
+ * `NotFound` is returned, containing the index where a matching
+ * element could be inserted while maintaining sorted order.
+ */
+ #[unstable]
+ fn binary_search_elem(&self, x: &T) -> BinarySearchResult;
}
-impl<'a, T: Ord> ImmutableOrdVector<T> for &'a [T] {
+#[unstable = "trait is unstable"]
+impl<'a, T: Ord> ImmutableOrdSlice<T> for &'a [T] {
+ #[deprecated = "use binary_search_elem"]
+ #[allow(deprecated)]
fn bsearch_elem(&self, x: &T) -> Option<uint> {
self.bsearch(|p| p.cmp(x))
}
+
+ #[unstable]
+ fn binary_search_elem(&self, x: &T) -> BinarySearchResult {
+ self.binary_search(|p| p.cmp(x))
+ }
}
/// Trait for &[T] where T is Cloneable
-pub trait MutableCloneableVector<T> {
+#[unstable = "may merge with other traits"]
+pub trait MutableCloneableSlice<T> {
+ /// Copies as many elements from `src` as it can into `self` (the
+ /// shorter of `self.len()` and `src.len()`). Returns the number
+ /// of elements copied.
+ #[deprecated = "renamed to clone_from_slice"]
+ fn copy_from(self, s: &[T]) -> uint { self.clone_from_slice(s) }
+
/// Copies as many elements from `src` as it can into `self` (the
/// shorter of `self.len()` and `src.len()`). Returns the number
/// of elements copied.
/// # Example
///
/// ```rust
- /// use std::slice::MutableCloneableVector;
+ /// use std::slice::MutableCloneableSlice;
///
/// let mut dst = [0i, 0, 0];
/// let src = [1i, 2];
/// assert!(dst.copy_from(src2) == 3);
/// assert!(dst == [3i, 4, 5]);
/// ```
- fn copy_from(self, &[T]) -> uint;
+ fn clone_from_slice(self, &[T]) -> uint;
}
-impl<'a, T:Clone> MutableCloneableVector<T> for &'a mut [T] {
+#[unstable = "trait is unstable"]
+impl<'a, T:Clone> MutableCloneableSlice<T> for &'a mut [T] {
#[inline]
- fn copy_from(self, src: &[T]) -> uint {
+ fn clone_from_slice(self, src: &[T]) -> uint {
for (a, b) in self.mut_iter().zip(src.iter()) {
a.clone_from(b);
}
//
/// Any vector that can be represented as a slice.
-pub trait Vector<T> {
+#[unstable = "may merge with other traits"]
+pub trait Slice<T> {
/// Work with `self` as a slice.
fn as_slice<'a>(&'a self) -> &'a [T];
}
-impl<'a,T> Vector<T> for &'a [T] {
+#[unstable = "trait is unstable"]
+impl<'a,T> Slice<T> for &'a [T] {
#[inline(always)]
fn as_slice<'a>(&'a self) -> &'a [T] { *self }
}
+#[experimental = "trait is experimental"]
impl<'a, T> Collection for &'a [T] {
/// Returns the length of a vector
#[inline]
}
}
+#[unstable = "waiting for DST"]
impl<'a, T> Default for &'a [T] {
fn default() -> &'a [T] { &[] }
}
// The shared definition of the `Item` and `MutItems` iterators
macro_rules! iterator {
(struct $name:ident -> $ptr:ty, $elem:ty) => {
+ #[experimental = "needs review"]
impl<'a, T> Iterator<$elem> for $name<'a, T> {
#[inline]
fn next(&mut self) -> Option<$elem> {
}
}
+ #[experimental = "needs review"]
impl<'a, T> DoubleEndedIterator<$elem> for $name<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<$elem> {
}
/// Immutable slice iterator
+#[experimental = "needs review"]
pub struct Items<'a, T> {
ptr: *const T,
end: *const T,
iterator!{struct Items -> *const T, &'a T}
+#[experimental = "needs review"]
impl<'a, T> ExactSize<&'a T> for Items<'a, T> {}
+#[experimental = "needs review"]
impl<'a, T> Clone for Items<'a, T> {
fn clone(&self) -> Items<'a, T> { *self }
}
+#[experimental = "needs review"]
impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> {
#[inline]
fn indexable(&self) -> uint {
}
/// Mutable slice iterator
+#[experimental = "needs review"]
pub struct MutItems<'a, T> {
ptr: *mut T,
end: *mut T,
iterator!{struct MutItems -> *mut T, &'a mut T}
+#[experimental = "needs review"]
impl<'a, T> ExactSize<&'a mut T> for MutItems<'a, T> {}
/// An iterator over the slices of a vector separated by elements that
/// match a predicate function.
+#[experimental = "needs review"]
pub struct Splits<'a, T> {
v: &'a [T],
pred: |t: &T|: 'a -> bool,
finished: bool
}
+#[experimental = "needs review"]
impl<'a, T> Iterator<&'a [T]> for Splits<'a, T> {
#[inline]
fn next(&mut self) -> Option<&'a [T]> {
}
}
+#[experimental = "needs review"]
impl<'a, T> DoubleEndedIterator<&'a [T]> for Splits<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<&'a [T]> {
/// An iterator over the subslices of the vector which are separated
/// by elements that match `pred`.
+#[experimental = "needs review"]
pub struct MutSplits<'a, T> {
v: &'a mut [T],
pred: |t: &T|: 'a -> bool,
finished: bool
}
+#[experimental = "needs review"]
impl<'a, T> Iterator<&'a mut [T]> for MutSplits<'a, T> {
#[inline]
fn next(&mut self) -> Option<&'a mut [T]> {
}
}
+#[experimental = "needs review"]
impl<'a, T> DoubleEndedIterator<&'a mut [T]> for MutSplits<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<&'a mut [T]> {
/// An iterator over the slices of a vector separated by elements that
/// match a predicate function, splitting at most a fixed number of times.
+#[experimental = "needs review"]
pub struct SplitsN<'a, T> {
iter: Splits<'a, T>,
count: uint,
invert: bool
}
+#[experimental = "needs review"]
impl<'a, T> Iterator<&'a [T]> for SplitsN<'a, T> {
#[inline]
fn next(&mut self) -> Option<&'a [T]> {
/// An iterator over the (overlapping) slices of length `size` within
/// a vector.
#[deriving(Clone)]
+#[experimental = "needs review"]
pub struct Windows<'a, T> {
v: &'a [T],
size: uint
}
+#[experimental = "needs review"]
impl<'a, T> Iterator<&'a [T]> for Windows<'a, T> {
#[inline]
fn next(&mut self) -> Option<&'a [T]> {
/// When the vector len is not evenly divided by the chunk size,
/// the last slice of the iteration will be the remainder.
#[deriving(Clone)]
+#[experimental = "needs review"]
pub struct Chunks<'a, T> {
v: &'a [T],
size: uint
}
+#[experimental = "needs review"]
impl<'a, T> Iterator<&'a [T]> for Chunks<'a, T> {
#[inline]
fn next(&mut self) -> Option<&'a [T]> {
}
}
+#[experimental = "needs review"]
impl<'a, T> DoubleEndedIterator<&'a [T]> for Chunks<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<&'a [T]> {
}
}
+#[experimental = "needs review"]
impl<'a, T> RandomAccessIterator<&'a [T]> for Chunks<'a, T> {
#[inline]
fn indexable(&self) -> uint {
/// An iterator over a vector in (non-overlapping) mutable chunks (`size` elements at a time). When
/// the vector len is not evenly divided by the chunk size, the last slice of the iteration will be
/// the remainder.
+#[experimental = "needs review"]
pub struct MutChunks<'a, T> {
v: &'a mut [T],
chunk_size: uint
}
+#[experimental = "needs review"]
impl<'a, T> Iterator<&'a mut [T]> for MutChunks<'a, T> {
#[inline]
fn next(&mut self) -> Option<&'a mut [T]> {
}
}
+#[experimental = "needs review"]
impl<'a, T> DoubleEndedIterator<&'a mut [T]> for MutChunks<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<&'a mut [T]> {
+/// The result of calling `binary_search`.
+///
+/// `Found` means the search succeeded, and the contained value is the
+/// index of the matching element. `NotFound` means the search
+/// succeeded, and the contained value is an index where a matching
+/// value could be inserted while maintaining sort order.
+#[deriving(PartialEq, Show)]
+#[experimental = "needs review"]
+pub enum BinarySearchResult {
+ /// The index of the found value.
+ Found(uint),
+ /// The index where the value should have been found.
+ NotFound(uint)
+}
+
+#[experimental = "needs review"]
+impl BinarySearchResult {
+ /// Converts a `Found` to `Some`, `NotFound` to `None`.
+ /// Similar to `Result::ok`.
+ pub fn found(&self) -> Option<uint> {
+ match *self {
+ Found(i) => Some(i),
+ NotFound(_) => None
+ }
+ }
+
+ /// Convert a `Found` to `None`, `NotFound` to `Some`.
+ /// Similar to `Result::err`.
+ pub fn not_found(&self) -> Option<uint> {
+ match *self {
+ Found(_) => None,
+ NotFound(i) => Some(i)
+ }
+ }
+}
+
+
//
// Free functions
/**
* Converts a pointer to A into a slice of length 1 (without copying).
*/
+#[unstable = "waiting for DST"]
pub fn ref_slice<'a, A>(s: &'a A) -> &'a [A] {
unsafe {
- transmute(Slice { data: s, len: 1 })
+ transmute(RawSlice { data: s, len: 1 })
}
}
/**
* Converts a pointer to A into a slice of length 1 (without copying).
*/
+#[unstable = "waiting for DST"]
pub fn mut_ref_slice<'a, A>(s: &'a mut A) -> &'a mut [A] {
unsafe {
let ptr: *const A = transmute(s);
- transmute(Slice { data: ptr, len: 1 })
+ transmute(RawSlice { data: ptr, len: 1 })
}
}
//
/// Unsafe operations
+#[experimental = "needs review"]
pub mod raw {
use mem::transmute;
use ptr::RawPtr;
}
/// Operations on `[u8]`.
+#[experimental = "needs review"]
pub mod bytes {
use collections::Collection;
use ptr;
- use slice::MutableVector;
+ use slice::MutableSlice;
/// A trait for operations on mutable `[u8]`s.
pub trait MutableByteVector {
// Boilerplate traits
//
+#[unstable = "waiting for DST"]
impl<'a,T:PartialEq> PartialEq for &'a [T] {
fn eq(&self, other: & &'a [T]) -> bool {
self.len() == other.len() &&
}
}
+#[unstable = "waiting for DST"]
impl<'a,T:Eq> Eq for &'a [T] {}
-impl<'a,T:PartialEq, V: Vector<T>> Equiv<V> for &'a [T] {
+#[unstable = "waiting for DST"]
+impl<'a,T:PartialEq, V: Slice<T>> Equiv<V> for &'a [T] {
#[inline]
fn equiv(&self, other: &V) -> bool { self.as_slice() == other.as_slice() }
}
+#[unstable = "waiting for DST"]
impl<'a,T:Ord> Ord for &'a [T] {
fn cmp(&self, other: & &'a [T]) -> Ordering {
order::cmp(self.iter(), other.iter())
}
}
+#[unstable = "waiting for DST"]
impl<'a, T: PartialOrd> PartialOrd for &'a [T] {
#[inline]
fn partial_cmp(&self, other: &&'a [T]) -> Option<Ordering> {
use num::{CheckedMul, Saturating};
use option::{Option, None, Some};
use raw::Repr;
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use slice;
use uint;
use collections::Collection;
use ptr::RawPtr;
use raw::Slice;
- use slice::{ImmutableVector};
+ use slice::{ImmutableSlice};
use str::{is_utf8, StrSlice};
/// Converts a slice of bytes to a string slice without checking
/// # Example
///
/// ```rust
- /// let v: Vec<&str> = "Mary had a little lambda".splitn(' ', 2).collect();
+ /// let v: Vec<&str> = "Mary had a little lambda".splitn(2, ' ').collect();
/// assert_eq!(v, vec!["Mary", "had", "a little lambda"]);
///
- /// let v: Vec<&str> = "abc1def2ghi".splitn(|c: char| c.is_digit(), 1).collect();
+ /// let v: Vec<&str> = "abc1def2ghi".splitn(1, |c: char| c.is_digit()).collect();
/// assert_eq!(v, vec!["abc", "def2ghi"]);
///
- /// let v: Vec<&str> = "lionXXtigerXleopard".splitn('X', 2).collect();
+ /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(2, 'X').collect();
/// assert_eq!(v, vec!["lion", "", "tigerXleopard"]);
///
- /// let v: Vec<&str> = "abcXdef".splitn('X', 0).collect();
+ /// let v: Vec<&str> = "abcXdef".splitn(0, 'X').collect();
/// assert_eq!(v, vec!["abcXdef"]);
///
- /// let v: Vec<&str> = "".splitn('X', 1).collect();
+ /// let v: Vec<&str> = "".splitn(1, 'X').collect();
/// assert_eq!(v, vec![""]);
/// ```
- fn splitn<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitsN<'a, Sep>;
+ fn splitn<Sep: CharEq>(&self, count: uint, sep: Sep) -> CharSplitsN<'a, Sep>;
/// An iterator over substrings of `self`, separated by characters
/// matched by `sep`.
/// # Example
///
/// ```rust
- /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(' ', 2).collect();
+ /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(2, ' ').collect();
/// assert_eq!(v, vec!["lamb", "little", "Mary had a"]);
///
- /// let v: Vec<&str> = "abc1def2ghi".rsplitn(|c: char| c.is_digit(), 1).collect();
+ /// let v: Vec<&str> = "abc1def2ghi".rsplitn(1, |c: char| c.is_digit()).collect();
/// assert_eq!(v, vec!["ghi", "abc1def"]);
///
- /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn('X', 2).collect();
+ /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(2, 'X').collect();
/// assert_eq!(v, vec!["leopard", "tiger", "lionX"]);
/// ```
- fn rsplitn<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitsN<'a, Sep>;
+ fn rsplitn<Sep: CharEq>(&self, count: uint, sep: Sep) -> CharSplitsN<'a, Sep>;
/// An iterator over the start and end indices of the disjoint
/// matches of `sep` within `self`.
}
#[inline]
- fn splitn<Sep: CharEq>(&self, sep: Sep, count: uint)
+ fn splitn<Sep: CharEq>(&self, count: uint, sep: Sep)
-> CharSplitsN<'a, Sep> {
CharSplitsN {
iter: self.split(sep),
}
#[inline]
- fn rsplitn<Sep: CharEq>(&self, sep: Sep, count: uint)
+ fn rsplitn<Sep: CharEq>(&self, count: uint, sep: Sep)
-> CharSplitsN<'a, Sep> {
CharSplitsN {
iter: self.split(sep),
mod ptr;
mod raw;
mod result;
+mod slice;
mod tuple;
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::slice::{Found, NotFound};
+
+#[test]
+fn binary_search_not_found() {
+ let b = [1i, 2, 4, 6, 8, 9];
+ assert!(b.binary_search(|v| v.cmp(&6)) == Found(3));
+ let b = [1i, 2, 4, 6, 8, 9];
+ assert!(b.binary_search(|v| v.cmp(&5)) == NotFound(3));
+ let b = [1i, 2, 4, 6, 7, 8, 9];
+ assert!(b.binary_search(|v| v.cmp(&6)) == Found(3));
+ let b = [1i, 2, 4, 6, 7, 8, 9];
+ assert!(b.binary_search(|v| v.cmp(&5)) == NotFound(3));
+ let b = [1i, 2, 4, 6, 8, 9];
+ assert!(b.binary_search(|v| v.cmp(&8)) == Found(4));
+ let b = [1i, 2, 4, 6, 8, 9];
+ assert!(b.binary_search(|v| v.cmp(&7)) == NotFound(4));
+ let b = [1i, 2, 4, 6, 7, 8, 9];
+ assert!(b.binary_search(|v| v.cmp(&8)) == Found(5));
+ let b = [1i, 2, 4, 5, 6, 8, 9];
+ assert!(b.binary_search(|v| v.cmp(&7)) == NotFound(5));
+ let b = [1i, 2, 4, 5, 6, 8, 9];
+ assert!(b.binary_search(|v| v.cmp(&0)) == NotFound(0));
+ let b = [1i, 2, 4, 5, 6, 8];
+ assert!(b.binary_search(|v| v.cmp(&9)) == NotFound(6));
+}
#![crate_name = "fourcc"]
#![deprecated = "This is now a cargo package located at: \
https://github.com/rust-lang/fourcc"]
+#![allow(deprecated)]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
}
}
-impl<'a, T: PartialEq, V: Vector<T>> Equiv<V> for MaybeOwnedVector<'a, T> {
+impl<'a, T: PartialEq, V: Slice<T>> Equiv<V> for MaybeOwnedVector<'a, T> {
fn equiv(&self, other: &V) -> bool {
self.as_slice() == other.as_slice()
}
// In any case, with `Vector` in place, the client can just use
// `as_slice` if they prefer that over `match`.
-impl<'b,T> slice::Vector<T> for MaybeOwnedVector<'b,T> {
+impl<'b,T> Slice<T> for MaybeOwnedVector<'b,T> {
fn as_slice<'a>(&'a self) -> &'a [T] {
match self {
&Growable(ref v) => v.as_slice(),
use std::rt::task::TaskOpts;
use std::rt::task::Task;
use std::rt::local::Local;
+ use std::time::Duration;
use {TaskState, PoolConfig, SchedPool};
use basic;
// doesn't exit before emptying the work queue
pool.spawn(TaskOpts::new(), proc() {
spawn(proc() {
- timer::sleep(10);
+ timer::sleep(Duration::milliseconds(10));
});
});
#![crate_name = "hexfloat"]
#![deprecated = "This is now a cargo package located at: \
https://github.com/rust-lang/hexfloat"]
+#![allow(deprecated)]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
rtio::Ignored => { ret.push(None); Ok(None) }
rtio::InheritFd(fd) => {
ret.push(None);
- Ok(Some(file::FileDesc::new(fd, true)))
+ Ok(Some(file::FileDesc::new(fd, false)))
}
rtio::CreatePipe(readable, _writable) => {
let (reader, writer) = try!(pipe());
FromStr for Ratio<T> {
/// Parses `numer/denom` or just `numer`.
fn from_str(s: &str) -> Option<Ratio<T>> {
- let mut split = s.splitn('/', 1);
+ let mut split = s.splitn(1, '/');
let num = split.next().and_then(|n| FromStr::from_str(n));
let den = split.next().or(Some("1")).and_then(|d| FromStr::from_str(d));
FromStrRadix for Ratio<T> {
/// Parses `numer/denom` where the numbers are in base `radix`.
fn from_str_radix(s: &str, radix: uint) -> Option<Ratio<T>> {
- let split: Vec<&str> = s.splitn('/', 1).collect();
+ let split: Vec<&str> = s.splitn(1, '/').collect();
if split.len() < 2 {
None
} else {
static MP_VEC: [(uint, uint), .. 2] = [(0,MIDPOINT), (MIDPOINT, 0)];
macro_rules! ind (
($x:expr) => {
- *self.mem.unsafe_ref(($x as uint >> 3) & (RAND_SIZE_64 - 1))
+ *self.mem.unsafe_get(($x as uint >> 3) & (RAND_SIZE_64 - 1))
}
);
let mix = if $j == 0 {!mix} else {mix};
unsafe {
- let x = *self.mem.unsafe_ref(base + mr_offset);
- a = mix + *self.mem.unsafe_ref(base + m2_offset);
+ let x = *self.mem.unsafe_get(base + mr_offset);
+ a = mix + *self.mem.unsafe_get(base + m2_offset);
let y = ind!(x) + a + b;
self.mem.unsafe_set(base + mr_offset, y);
let mix = if $j == 0 {!mix} else {mix};
unsafe {
- let x = *self.mem.unsafe_ref(base + mr_offset);
- a = mix + *self.mem.unsafe_ref(base + m2_offset);
+ let x = *self.mem.unsafe_get(base + mr_offset);
+ a = mix + *self.mem.unsafe_get(base + m2_offset);
let y = ind!(x) + a + b;
self.mem.unsafe_set(base + mr_offset, y);
self.isaac64();
}
self.cnt -= 1;
- unsafe { *self.rsl.unsafe_ref(self.cnt) }
+ unsafe { *self.rsl.unsafe_get(self.cnt) }
}
}
use std::fmt;
use std::iter;
use std::num;
+use std::slice;
/// Static data containing Unicode ranges for general categories and scripts.
use unicode::regex::{UNICODE_CLASSES, PERLD, PERLS, PERLW};
min = try!(self.parse_uint(inner.as_slice()));
max = Some(min);
} else {
- let pieces: Vec<&str> = inner.as_slice().splitn(',', 1).collect();
+ let pieces: Vec<&str> = inner.as_slice().splitn(1, ',').collect();
let (smin, smax) = (pieces[0], pieces[1]);
if smin.len() == 0 {
return self.err("Max repetitions cannot be specified \
}
fn find_class(classes: NamedClasses, name: &str) -> Option<Vec<(char, char)>> {
- match classes.bsearch(|&(s, _)| s.cmp(&name)) {
- Some(i) => Some(Vec::from_slice(classes[i].val1())),
- None => None,
+ match classes.binary_search(|&(s, _)| s.cmp(&name)) {
+ slice::Found(i) => Some(Vec::from_slice(classes[i].val1())),
+ slice::NotFound(_) => None,
}
}
use std::cmp;
use std::mem;
-use std::slice::MutableVector;
+use std::slice::MutableSlice;
use compile::{
Program,
Match, OneChar, CharClass, Any, EmptyBegin, EmptyEnd, EmptyWordBoundary,
let negate = flags & FLAG_NEGATED > 0;
let casei = flags & FLAG_NOCASE > 0;
let found = ranges.as_slice();
- let found = found.bsearch(|&rc| class_cmp(casei, c, rc));
- let found = found.is_some();
+ let found = found.binary_search(|&rc| class_cmp(casei, c, rc))
+ .found().is_some();
if found ^ negate {
self.add(nlist, pc+1, caps);
}
// Try the common ASCII case before invoking binary search.
match c {
'_' | '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' => true,
- _ => PERLW.bsearch(|&(start, end)| {
+ _ => PERLW.binary_search(|&(start, end)| {
if c >= start && c <= end {
Equal
} else if start > c {
} else {
Less
}
- }).is_some()
+ }).found().is_some()
}
}
use core::iter::Iterator;
use core::collections::Collection;
use core::str::StrSlice;
- use core::slice::{MutableVector, ImmutableVector};
+ use core::slice::{MutableSlice, ImmutableSlice};
use super::{memcmp, memset, memcpy, memmove};
{
let mut cg = basic_codegen_options();
for option in matches.opt_strs("C").move_iter() {
- let mut iter = option.as_slice().splitn('=', 1);
+ let mut iter = option.as_slice().splitn(1, '=');
let key = iter.next().unwrap();
let value = iter.next();
let option_to_lookup = key.replace("-", "_");
let mut externs = HashMap::new();
for arg in matches.opt_strs("extern").iter() {
- let mut parts = arg.as_slice().splitn('=', 1);
+ let mut parts = arg.as_slice().splitn(1, '=');
let name = match parts.next() {
Some(s) => s,
None => early_error("--extern value must not be empty"),
plugin::build::find_plugin_registrar(
sess.diagnostic(), krate)));
- let freevars = time(time_passes, "freevar finding", (), |_|
- freevars::annotate_freevars(&def_map, krate));
+ let (freevars, capture_modes) =
+ time(time_passes, "freevar finding", (), |_|
+ freevars::annotate_freevars(&def_map, krate));
let region_map = time(time_passes, "region resolution", (), |_|
middle::region::resolve_crate(&sess, krate));
let stability_index = time(time_passes, "stability index", (), |_|
stability::Index::build(krate));
- let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
- freevars, region_map, lang_items, stability_index);
+ let ty_cx = ty::mk_ctxt(sess,
+ def_map,
+ named_region_map,
+ ast_map,
+ freevars,
+ capture_modes,
+ region_map,
+ lang_items,
+ stability_index);
// passes are timed inside typeck
typeck::check_crate(&ty_cx, trait_map, krate);
}
fn parse_pretty(sess: &Session, name: &str) -> (PpMode, Option<driver::UserIdentifiedItem>) {
- let mut split = name.splitn('=', 1);
+ let mut split = name.splitn(1, '=');
let first = split.next().unwrap();
let opt_second = split.next();
let first = match first {
let mainfn = (quote_item!(&cx.ext_cx,
pub fn main() {
#![main]
- use std::slice::Vector;
+ use std::slice::Slice;
test::test_main_static(::std::os::args().as_slice(), TESTS);
}
)).unwrap();
_ => return
};
- // stability attributes are promises made across crates; do not
- // check anything for crate-local usage.
- if ast_util::is_local(id) { return }
-
let stability = stability::lookup(cx.tcx, id);
+ let cross_crate = !ast_util::is_local(id);
+
+ // stability attributes are promises made across crates; only
+ // check DEPRECATED for crate-local usage.
let (lint, label) = match stability {
// no stability attributes == Unstable
- None => (UNSTABLE, "unmarked"),
- Some(attr::Stability { level: attr::Unstable, .. }) =>
- (UNSTABLE, "unstable"),
- Some(attr::Stability { level: attr::Experimental, .. }) =>
- (EXPERIMENTAL, "experimental"),
+ None if cross_crate => (UNSTABLE, "unmarked"),
+ Some(attr::Stability { level: attr::Unstable, .. }) if cross_crate =>
+ (UNSTABLE, "unstable"),
+ Some(attr::Stability { level: attr::Experimental, .. }) if cross_crate =>
+ (EXPERIMENTAL, "experimental"),
Some(attr::Stability { level: attr::Deprecated, .. }) =>
- (DEPRECATED, "deprecated"),
+ (DEPRECATED, "deprecated"),
_ => return
};
tag_table_capture_map = 0x53,
tag_table_unboxed_closure_type = 0x54,
tag_table_upvar_borrow_map = 0x55,
+ tag_table_capture_modes = 0x56,
}
static first_astencode_tag: uint = tag_ast as uint;
-static last_astencode_tag: uint = tag_table_upvar_borrow_map as uint;
+static last_astencode_tag: uint = tag_table_capture_modes as uint;
impl astencode_tag {
pub fn from_uint(value : uint) -> Option<astencode_tag> {
let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag;
use metadata::decoder;
use middle::def;
use e = metadata::encoder;
+use middle::freevars::{CaptureMode, freevar_entry};
use middle::freevars;
-use middle::freevars::freevar_entry;
use middle::region;
use metadata::tydecode;
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter,
(*fv).encode(rbml_w).unwrap();
}
+fn encode_capture_mode(rbml_w: &mut Encoder, cm: CaptureMode) {
+ cm.encode(rbml_w).unwrap();
+}
+
trait rbml_decoder_helper {
fn read_freevar_entry(&mut self, xcx: &ExtendedDecodeContext)
-> freevar_entry;
+ fn read_capture_mode(&mut self) -> CaptureMode;
}
impl<'a> rbml_decoder_helper for reader::Decoder<'a> {
let fv: freevar_entry = Decodable::decode(self).unwrap();
fv.tr(xcx)
}
+
+ fn read_capture_mode(&mut self) -> CaptureMode {
+ let cm: CaptureMode = Decodable::decode(self).unwrap();
+ cm
+ }
}
impl tr for freevar_entry {
}
}
+ for &cm in tcx.capture_modes.borrow().find(&id).iter() {
+ rbml_w.tag(c::tag_table_capture_modes, |rbml_w| {
+ rbml_w.id(id);
+ rbml_w.tag(c::tag_table_val, |rbml_w| {
+ encode_capture_mode(rbml_w, *cm);
+ })
+ })
+ }
+
let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
for &pty in tcx.tcache.borrow().find(&lid).iter() {
rbml_w.tag(c::tag_table_tcache, |rbml_w| {
let ub: ty::UpvarBorrow = Decodable::decode(val_dsr).unwrap();
dcx.tcx.upvar_borrow_map.borrow_mut().insert(upvar_id, ub.tr(xcx));
}
+ c::tag_table_capture_modes => {
+ let capture_mode = val_dsr.read_capture_mode();
+ dcx.tcx
+ .capture_modes
+ .borrow_mut()
+ .insert(id, capture_mode);
+ }
c::tag_table_tcache => {
let pty = val_dsr.read_polytype(xcx);
let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
self.bccx, borrow_span, cause,
cmt.clone(), loan_region);
+ debug!("guarantee_valid(): restrictions={:?}", restr);
+
// Create the loan record (if needed).
let loan = match restr {
restrictions::Safe => {
}
mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::ImmBorrow, lt)) |
- mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::UniqueImmBorrow, lt)) |
- mc::cat_deref(cmt_base, _, mc::Implicit(ty::ImmBorrow, lt)) |
- mc::cat_deref(cmt_base, _, mc::Implicit(ty::UniqueImmBorrow, lt)) => {
+ mc::cat_deref(cmt_base, _, mc::Implicit(ty::ImmBorrow, lt)) => {
// R-Deref-Imm-Borrowed
if !self.bccx.is_subregion_of(self.loan_region, lt) {
self.bccx.report(
mc::cat_deref(cmt_base, _, pk) => {
match pk {
mc::BorrowedPtr(ty::MutBorrow, lt) |
- mc::Implicit(ty::MutBorrow, lt) => {
+ mc::BorrowedPtr(ty::UniqueImmBorrow, lt) |
+ mc::Implicit(ty::MutBorrow, lt) |
+ mc::Implicit(ty::UniqueImmBorrow, lt) => {
// R-Deref-Mut-Borrowed
if !self.bccx.is_subregion_of(self.loan_region, lt) {
self.bccx.report(
match tcx.map.get(closure_id) {
ast_map::NodeExpr(expr) => match expr.node {
ast::ExprProc(_decl, block) |
- ast::ExprFnBlock(_decl, block) => { block.id }
+ ast::ExprFnBlock(_, _decl, block) => { block.id }
_ => fail!("encountered non-closure id: {}", closure_id)
},
_ => fail!("encountered non-expr id: {}", closure_id)
self.visit_expr(&**e, cx);
self.visit_block(&**b, Loop);
}
- ast::ExprFnBlock(_, ref b) |
+ ast::ExprFnBlock(_, _, ref b) |
ast::ExprProc(_, ref b) |
- ast::ExprUnboxedFn(_, ref b) => {
+ ast::ExprUnboxedFn(_, _, ref b) => {
self.visit_block(&**b, Closure);
}
ast::ExprBreak(_) => self.require_loop("break", cx, e.span),
ast::ExprForLoop(ref pat, ref head, ref blk, _) => {
// The pattern lives as long as the block.
debug!("walk_expr for loop case: blk id={}", blk.id);
- self.walk_expr(&**head);
+ self.consume_expr(&**head);
- let head_cmt = return_if_err!(self.mc.cat_expr(&**head));
- self.walk_pat(head_cmt, pat.clone());
+ // Fetch the type of the value that the iteration yields to
+ // produce the pattern's categorized mutable type.
+ let pattern_type = ty::node_id_to_type(self.tcx(), pat.id);
+ let pat_cmt = self.mc.cat_rvalue(pat.id,
+ pat.span,
+ ty::ReScope(blk.id),
+ pattern_type);
+ self.walk_pat(pat_cmt, pat.clone());
self.walk_block(&**blk);
}
}
ast::PatIdent(ast::BindByValue(_), _, _) => {
let mode = copy_or_move(typer.tcx(), cmt_pat.ty, PatBindingMove);
+ debug!("walk_pat binding consuming pat");
delegate.consume_pat(pat, cmt_pat, mode);
}
_ => {
use middle::mem_categorization::Typer;
use middle::resolve;
use middle::ty;
-use util::nodemap::{DefIdSet, NodeMap, NodeSet};
+use util::nodemap::{NodeMap, NodeSet};
+use syntax::ast;
use syntax::codemap::Span;
-use syntax::{ast};
-use syntax::visit;
use syntax::visit::Visitor;
+use syntax::visit;
-#[deriving(Show)]
+#[deriving(Clone, Decodable, Encodable, Show)]
pub enum CaptureMode {
/// Copy/move the value from this llvm ValueRef into the environment.
CaptureByValue,
pub type freevar_map = NodeMap<Vec<freevar_entry>>;
-pub type UnboxedClosureList = DefIdSet;
+pub type CaptureModeMap = NodeMap<CaptureMode>;
struct CollectFreevarsVisitor<'a> {
seen: NodeSet,
refs: Vec<freevar_entry>,
def_map: &'a resolve::DefMap,
+ capture_mode_map: &'a mut CaptureModeMap,
}
impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
fn visit_expr(&mut self, expr: &ast::Expr, depth: int) {
match expr.node {
- ast::ExprFnBlock(..) | ast::ExprProc(..) |
- ast::ExprUnboxedFn(..) => {
+ ast::ExprProc(..) => {
+ self.capture_mode_map.insert(expr.id, CaptureByValue);
+ visit::walk_expr(self, expr, depth + 1)
+ }
+ ast::ExprFnBlock(_, _, _) => {
+ // NOTE(stage0): After snapshot, change to:
+ //
+ //let capture_mode = match capture_clause {
+ // ast::CaptureByValue => CaptureByValue,
+ // ast::CaptureByRef => CaptureByRef,
+ //};
+ let capture_mode = CaptureByRef;
+ self.capture_mode_map.insert(expr.id, capture_mode);
+ visit::walk_expr(self, expr, depth + 1)
+ }
+ ast::ExprUnboxedFn(capture_clause, _, _) => {
+ let capture_mode = match capture_clause {
+ ast::CaptureByValue => CaptureByValue,
+ ast::CaptureByRef => CaptureByRef,
+ };
+ self.capture_mode_map.insert(expr.id, capture_mode);
visit::walk_expr(self, expr, depth + 1)
}
ast::ExprPath(..) => {
_ => visit::walk_expr(self, expr, depth)
}
}
-
-
}
// Searches through part of the AST for all references to locals or
// Since we want to be able to collect upvars in some arbitrary piece
// of the AST, we take a walker function that we invoke with a visitor
// in order to start the search.
-fn collect_freevars(def_map: &resolve::DefMap, blk: &ast::Block) -> Vec<freevar_entry> {
+fn collect_freevars(def_map: &resolve::DefMap,
+ blk: &ast::Block,
+ capture_mode_map: &mut CaptureModeMap)
+ -> Vec<freevar_entry> {
let mut v = CollectFreevarsVisitor {
seen: NodeSet::new(),
refs: Vec::new(),
def_map: def_map,
+ capture_mode_map: &mut *capture_mode_map,
};
v.visit_block(blk, 1);
+
v.refs
}
struct AnnotateFreevarsVisitor<'a> {
def_map: &'a resolve::DefMap,
freevars: freevar_map,
+ capture_mode_map: CaptureModeMap,
}
impl<'a> Visitor<()> for AnnotateFreevarsVisitor<'a> {
fn visit_fn(&mut self, fk: &visit::FnKind, fd: &ast::FnDecl,
blk: &ast::Block, s: Span, nid: ast::NodeId, _: ()) {
- let vars = collect_freevars(self.def_map, blk);
+ let vars = collect_freevars(self.def_map,
+ blk,
+ &mut self.capture_mode_map);
self.freevars.insert(nid, vars);
visit::walk_fn(self, fk, fd, blk, s, ());
}
// node of interest rather than building up the free variables in
// one pass. This could be improved upon if it turns out to matter.
pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate)
- -> freevar_map {
+ -> (freevar_map, CaptureModeMap) {
let mut visitor = AnnotateFreevarsVisitor {
def_map: def_map,
freevars: NodeMap::new(),
+ capture_mode_map: NodeMap::new(),
};
visit::walk_crate(&mut visitor, krate, ());
- visitor.freevars
+ let AnnotateFreevarsVisitor {
+ freevars,
+ capture_mode_map,
+ ..
+ } = visitor;
+ (freevars, capture_mode_map)
}
pub fn with_freevars<T>(tcx: &ty::ctxt, fid: ast::NodeId, f: |&[freevar_entry]| -> T) -> T {
}
}
-pub fn get_capture_mode<T: Typer>(tcx: &T, closure_expr_id: ast::NodeId) -> CaptureMode {
- let fn_ty = tcx.node_ty(closure_expr_id).ok().expect("couldn't find closure ty?");
- match ty::ty_closure_store(fn_ty) {
- ty::RegionTraitStore(..) => CaptureByRef,
- ty::UniqTraitStore => CaptureByValue
- }
+pub fn get_capture_mode<T:Typer>(tcx: &T, closure_expr_id: ast::NodeId)
+ -> CaptureMode {
+ tcx.capture_mode(closure_expr_id)
}
self.propagate_through_expr(&**e, succ)
}
- ExprFnBlock(_, ref blk) |
+ ExprFnBlock(_, _, ref blk) |
ExprProc(_, ref blk) |
- ExprUnboxedFn(_, ref blk) => {
+ ExprUnboxedFn(_, _, ref blk) => {
debug!("{} is an ExprFnBlock, ExprProc, or ExprUnboxedFn",
expr_to_string(expr));
#![allow(non_camel_case_types)]
use middle::def;
+use middle::freevars;
use middle::ty;
use middle::typeck;
use util::nodemap::NodeMap;
fn is_method_call(&self, id: ast::NodeId) -> bool;
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<ast::NodeId>;
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow;
+ fn capture_mode(&self, closure_expr_id: ast::NodeId)
+ -> freevars::CaptureMode;
}
impl MutabilityCategory {
visit::walk_expr(self, expr, ());
}
- ExprFnBlock(fn_decl, block) |
+ ExprFnBlock(_, fn_decl, block) |
ExprProc(fn_decl, block) |
- ExprUnboxedFn(fn_decl, block) => {
+ ExprUnboxedFn(_, fn_decl, block) => {
self.resolve_function(FunctionRibKind(expr.id, block.id),
Some(fn_decl), NoTypeParameters,
block);
"Expected struct type, but not ty_struct"),
}
},
- ast::ExprFnBlock(decl, body) => {
+ ast::ExprFnBlock(_, decl, body) => {
if generated_code(body.span) {
return
}
let llalign = llalign_of_min(ccx, llty);
call_memcpy(bcx, dst, src, llsz, llalign as u32);
} else {
- Store(bcx, Load(bcx, src), dst);
+ store_ty(bcx, Load(bcx, src), dst, t);
}
}
p
}
-// Creates and returns space for, or returns the argument representing, the
-// slot where the return value of the function must go.
-pub fn make_return_pointer(fcx: &FunctionContext, output_type: ty::t)
- -> ValueRef {
- if type_of::return_uses_outptr(fcx.ccx, output_type) {
- get_param(fcx.llfn, 0)
+// Creates the alloca slot which holds the pointer to the slot for the final return value
+pub fn make_return_slot_pointer(fcx: &FunctionContext, output_type: ty::t) -> ValueRef {
+ let lloutputtype = type_of::type_of(fcx.ccx, output_type);
+
+ // We create an alloca to hold a pointer of type `output_type`
+ // which will hold the pointer to the right alloca which has the
+ // final ret value
+ if fcx.needs_ret_allocas {
+ // Let's create the stack slot
+ let slot = AllocaFcx(fcx, lloutputtype.ptr_to(), "llretslotptr");
+
+ // and if we're using an out pointer, then store that in our newly made slot
+ if type_of::return_uses_outptr(fcx.ccx, output_type) {
+ let outptr = get_param(fcx.llfn, 0);
+
+ let b = fcx.ccx.builder();
+ b.position_before(fcx.alloca_insert_pt.get().unwrap());
+ b.store(outptr, slot);
+ }
+
+ slot
+
+ // But if there are no nested returns, we skip the indirection and have a single
+ // retslot
} else {
- let lloutputtype = type_of::type_of(fcx.ccx, output_type);
- AllocaFcx(fcx, lloutputtype, "__make_return_pointer")
+ if type_of::return_uses_outptr(fcx.ccx, output_type) {
+ get_param(fcx.llfn, 0)
+ } else {
+ AllocaFcx(fcx, lloutputtype, "sret_slot")
+ }
+ }
+}
+
+struct CheckForNestedReturnsVisitor {
+ found: bool
+}
+
+impl Visitor<bool> for CheckForNestedReturnsVisitor {
+ fn visit_expr(&mut self, e: &ast::Expr, in_return: bool) {
+ match e.node {
+ ast::ExprRet(..) if in_return => {
+ self.found = true;
+ return;
+ }
+ ast::ExprRet(..) => visit::walk_expr(self, e, true),
+ _ => visit::walk_expr(self, e, in_return)
+ }
+ }
+}
+
+fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
+ match tcx.map.find(id) {
+ Some(ast_map::NodeItem(i)) => {
+ match i.node {
+ ast::ItemFn(_, _, _, _, blk) => {
+ let mut explicit = CheckForNestedReturnsVisitor { found: false };
+ let mut implicit = CheckForNestedReturnsVisitor { found: false };
+ visit::walk_item(&mut explicit, &*i, false);
+ visit::walk_expr_opt(&mut implicit, blk.expr, true);
+ explicit.found || implicit.found
+ }
+ _ => tcx.sess.bug("unexpected item variant in has_nested_returns")
+ }
+ }
+ Some(ast_map::NodeTraitMethod(trait_method)) => {
+ match *trait_method {
+ ast::Provided(m) => {
+ match m.node {
+ ast::MethDecl(_, _, _, _, _, _, blk, _) => {
+ let mut explicit = CheckForNestedReturnsVisitor { found: false };
+ let mut implicit = CheckForNestedReturnsVisitor { found: false };
+ visit::walk_method_helper(&mut explicit, &*m, false);
+ visit::walk_expr_opt(&mut implicit, blk.expr, true);
+ explicit.found || implicit.found
+ }
+ ast::MethMac(_) => tcx.sess.bug("unexpanded macro")
+ }
+ }
+ ast::Required(_) => tcx.sess.bug("unexpected variant: required trait method in \
+ has_nested_returns")
+ }
+ }
+ Some(ast_map::NodeMethod(m)) => {
+ match m.node {
+ ast::MethDecl(_, _, _, _, _, _, blk, _) => {
+ let mut explicit = CheckForNestedReturnsVisitor { found: false };
+ let mut implicit = CheckForNestedReturnsVisitor { found: false };
+ visit::walk_method_helper(&mut explicit, &*m, false);
+ visit::walk_expr_opt(&mut implicit, blk.expr, true);
+ explicit.found || implicit.found
+ }
+ ast::MethMac(_) => tcx.sess.bug("unexpanded macro")
+ }
+ }
+ Some(ast_map::NodeExpr(e)) => {
+ match e.node {
+ ast::ExprFnBlock(_, _, blk) |
+ ast::ExprProc(_, blk) |
+ ast::ExprUnboxedFn(_, _, blk) => {
+ let mut explicit = CheckForNestedReturnsVisitor { found: false };
+ let mut implicit = CheckForNestedReturnsVisitor { found: false };
+ visit::walk_expr(&mut explicit, &*e, false);
+ visit::walk_expr_opt(&mut implicit, blk.expr, true);
+ explicit.found || implicit.found
+ }
+ _ => tcx.sess.bug("unexpected expr variant in has_nested_returns")
+ }
+ }
+
+ Some(ast_map::NodeVariant(..)) | Some(ast_map::NodeStructCtor(..)) => false,
+
+ // glue, shims, etc
+ None if id == ast::DUMMY_NODE_ID => false,
+
+ _ => tcx.sess.bug(format!("unexpected variant in has_nested_returns: {}",
+ tcx.map.path_to_string(id)).as_slice())
}
}
output_type: ty::t,
param_substs: &'a param_substs,
sp: Option<Span>,
- block_arena: &'a TypedArena<Block<'a>>,
- handle_items: HandleItemsFlag)
+ block_arena: &'a TypedArena<Block<'a>>)
-> FunctionContext<'a> {
param_substs.validate();
let substd_output_type = output_type.substp(ccx.tcx(), param_substs);
let uses_outptr = type_of::return_uses_outptr(ccx, substd_output_type);
let debug_context = debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl);
+ let nested_returns = has_nested_returns(ccx.tcx(), id);
let mut fcx = FunctionContext {
llfn: llfndecl,
llenv: None,
- llretptr: Cell::new(None),
+ llretslotptr: Cell::new(None),
alloca_insert_pt: Cell::new(None),
llreturn: Cell::new(None),
+ needs_ret_allocas: nested_returns,
personality: Cell::new(None),
caller_expects_out_pointer: uses_outptr,
llargs: RefCell::new(NodeMap::new()),
block_arena: block_arena,
ccx: ccx,
debug_context: debug_context,
- scopes: RefCell::new(Vec::new()),
- handle_items: handle_items,
+ scopes: RefCell::new(Vec::new())
};
if has_env {
if !return_type_is_void(fcx.ccx, substd_output_type) {
// If the function returns nil/bot, there is no real return
- // value, so do not set `llretptr`.
+ // value, so do not set `llretslotptr`.
if !skip_retptr || fcx.caller_expects_out_pointer {
- // Otherwise, we normally allocate the llretptr, unless we
+ // Otherwise, we normally allocate the llretslotptr, unless we
// have been instructed to skip it for immediate return
// values.
- fcx.llretptr.set(Some(make_return_pointer(fcx, substd_output_type)));
+ fcx.llretslotptr.set(Some(make_return_slot_pointer(fcx, substd_output_type)));
}
}
// Builds the return block for a function.
pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) {
- // Return the value if this function immediate; otherwise, return void.
- if fcx.llretptr.get().is_none() || fcx.caller_expects_out_pointer {
+ if fcx.llretslotptr.get().is_none() ||
+ (!fcx.needs_ret_allocas && fcx.caller_expects_out_pointer) {
return RetVoid(ret_cx);
}
- let retptr = Value(fcx.llretptr.get().unwrap());
- let retval = match retptr.get_dominating_store(ret_cx) {
+ let retslot = if fcx.needs_ret_allocas {
+ Load(ret_cx, fcx.llretslotptr.get().unwrap())
+ } else {
+ fcx.llretslotptr.get().unwrap()
+ };
+ let retptr = Value(retslot);
+ match retptr.get_dominating_store(ret_cx) {
// If there's only a single store to the ret slot, we can directly return
// the value that was stored and omit the store and the alloca
Some(s) => {
retptr.erase_from_parent();
}
- if ty::type_is_bool(retty) {
+ let retval = if ty::type_is_bool(retty) {
Trunc(ret_cx, retval, Type::i1(fcx.ccx))
} else {
retval
+ };
+
+ if fcx.caller_expects_out_pointer {
+ store_ty(ret_cx, retval, get_param(fcx.llfn, 0), retty);
+ return RetVoid(ret_cx);
+ } else {
+ return Ret(ret_cx, retval);
}
}
- // Otherwise, load the return value from the ret slot
- None => load_ty(ret_cx, fcx.llretptr.get().unwrap(), retty)
- };
-
- Ret(ret_cx, retval);
+ // Otherwise, copy the return value to the ret slot
+ None => {
+ if fcx.caller_expects_out_pointer {
+ memcpy_ty(ret_cx, get_param(fcx.llfn, 0), retslot, retty);
+ return RetVoid(ret_cx);
+ } else {
+ return Ret(ret_cx, load_ty(ret_cx, retslot, retty));
+ }
+ }
+ }
}
#[deriving(Clone, Eq, PartialEq)]
abi: Abi,
has_env: bool,
is_unboxed_closure: IsUnboxedClosureFlag,
- maybe_load_env: <'a> |&'a Block<'a>| -> &'a Block<'a>,
- handle_items: HandleItemsFlag) {
+ maybe_load_env: <'a> |&'a Block<'a>| -> &'a Block<'a>) {
ccx.stats.n_closures.set(ccx.stats.n_closures.get() + 1);
let _icx = push_ctxt("trans_closure");
output_type,
param_substs,
Some(body.span),
- &arena,
- handle_items);
+ &arena);
let mut bcx = init_function(&fcx, false, output_type);
// cleanup scope for the incoming arguments
// emitting should be enabled.
debuginfo::start_emitting_source_locations(&fcx);
- let dest = match fcx.llretptr.get() {
- Some(e) => {expr::SaveIn(e)}
+ let dest = match fcx.llretslotptr.get() {
+ Some(_) => expr::SaveIn(fcx.get_ret_slot(bcx, block_ty, "iret_slot")),
None => {
- assert!(type_is_zero_size(bcx.ccx(), block_ty))
+ assert!(type_is_zero_size(bcx.ccx(), block_ty));
expr::Ignore
}
};
// (trans_block, trans_expr, et cetera).
bcx = controlflow::trans_block(bcx, body, dest);
+ match dest {
+ expr::SaveIn(slot) if fcx.needs_ret_allocas => {
+ Store(bcx, slot, fcx.llretslotptr.get().unwrap());
+ }
+ _ => {}
+ }
+
match fcx.llreturn.get() {
Some(_) => {
Br(bcx, fcx.return_exit_block());
llfndecl: ValueRef,
param_substs: ¶m_substs,
id: ast::NodeId,
- attrs: &[ast::Attribute],
- handle_items: HandleItemsFlag) {
+ attrs: &[ast::Attribute]) {
let _s = StatRecorder::new(ccx, ccx.tcx.map.path_to_string(id).to_string());
debug!("trans_fn(param_substs={})", param_substs.repr(ccx.tcx()));
let _icx = push_ctxt("trans_fn");
abi,
false,
NotUnboxedClosure,
- |bcx| bcx,
- handle_items);
+ |bcx| bcx);
}
pub fn trans_enum_variant(ccx: &CrateContext,
let arena = TypedArena::new();
let fcx = new_fn_ctxt(ccx, llfndecl, ctor_id, false, result_ty,
- param_substs, None, &arena, TranslateItems);
+ param_substs, None, &arena);
let bcx = init_function(&fcx, false, result_ty);
+ assert!(!fcx.needs_ret_allocas);
+
let arg_tys = ty::ty_fn_args(ctor_ty);
let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice());
if !type_is_zero_size(fcx.ccx, result_ty) {
+ let dest = fcx.get_ret_slot(bcx, result_ty, "eret_slot");
let repr = adt::represent_type(ccx, result_ty);
for (i, arg_datum) in arg_datums.move_iter().enumerate() {
let lldestptr = adt::trans_field_ptr(bcx,
&*repr,
- fcx.llretptr.get().unwrap(),
+ dest,
disr,
i);
arg_datum.store_to(bcx, lldestptr);
}
- adt::trans_set_discr(bcx, &*repr, fcx.llretptr.get().unwrap(), disr);
+ adt::trans_set_discr(bcx, &*repr, dest, disr);
}
finish_fn(&fcx, bcx, result_ty);
llfn,
¶m_substs::empty(),
item.id,
- None,
- TranslateItems);
+ None);
} else {
trans_fn(ccx,
&**decl,
llfn,
¶m_substs::empty(),
item.id,
- item.attrs.as_slice(),
- TranslateItems);
+ item.attrs.as_slice());
}
- } else {
- // Be sure to travel more than just one layer deep to catch nested
- // items in blocks and such.
- let mut v = TransItemVisitor{ ccx: ccx };
- v.visit_block(&**body, ());
}
+
+ // Be sure to travel more than just one layer deep to catch nested
+ // items in blocks and such.
+ let mut v = TransItemVisitor{ ccx: ccx };
+ v.visit_block(&**body, ());
}
ast::ItemImpl(ref generics, _, _, ref ms) => {
meth::trans_impl(ccx, item.ident, ms.as_slice(), generics, item.id);
let return_type = ty::ty_fn_ret(boxed_function_type);
let fcx = new_fn_ctxt(ccx,
llfn,
- -1,
+ ast::DUMMY_NODE_ID,
false,
return_type,
&empty_param_substs,
None,
- &block_arena,
- TranslateItems);
+ &block_arena);
let mut bcx = init_function(&fcx, false, return_type);
// Create the substituted versions of the self type.
for i in range(1, arg_types.len()) {
llshimmedargs.push(get_param(fcx.llfn, fcx.arg_pos(i) as u32));
}
+ assert!(!fcx.needs_ret_allocas);
+ let dest = match fcx.llretslotptr.get() {
+ Some(_) => Some(expr::SaveIn(fcx.get_ret_slot(bcx, return_type, "ret_slot"))),
+ None => None
+ };
bcx = trans_call_inner(bcx,
None,
function_type,
}
},
ArgVals(llshimmedargs.as_slice()),
- match fcx.llretptr.get() {
- None => None,
- Some(llretptr) => Some(expr::SaveIn(llretptr)),
- }).bcx;
+ dest).bcx;
bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope);
finish_fn(&fcx, bcx, return_type);
assert!(abi == synabi::RustIntrinsic);
assert!(dest.is_some());
+ let call_info = call_info.expect("no call info for intrinsic call?");
return intrinsic::trans_intrinsic_call(bcx, node, callee_ty,
arg_cleanup_scope, args,
- dest.unwrap(), substs);
+ dest.unwrap(), substs,
+ call_info);
}
NamedTupleConstructor(substs, disr) => {
assert!(dest.is_some());
ty::ty_fn_abi(fty),
true,
NotUnboxedClosure,
- |bcx| load_environment(bcx, cdata_ty, &freevars, store),
- bcx.fcx.handle_items);
+ |bcx| load_environment(bcx, cdata_ty, &freevars, store));
fill_fn_pair(bcx, dest_addr, llfn, llbox);
bcx
}
ty::ty_fn_abi(function_type),
true,
IsUnboxedClosure,
- |bcx| load_unboxed_closure_environment(bcx, freevars_ptr),
- bcx.fcx.handle_items);
+ |bcx| load_unboxed_closure_environment(bcx, freevars_ptr));
// Don't hoist this to the top of the function. It's perfectly legitimate
// to have a zero-size unboxed closure (in which case dest will be
let arena = TypedArena::new();
let empty_param_substs = param_substs::empty();
- let fcx = new_fn_ctxt(ccx, llfn, -1, true, f.sig.output,
- &empty_param_substs, None, &arena, TranslateItems);
+ let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, true, f.sig.output,
+ &empty_param_substs, None, &arena);
let bcx = init_function(&fcx, true, f.sig.output);
let args = create_datums_for_fn_args(&fcx,
ty::ty_fn_args(closure_ty)
.as_slice());
let mut llargs = Vec::new();
- match fcx.llretptr.get() {
+ match fcx.llretslotptr.get() {
Some(llretptr) => {
+ assert!(!fcx.needs_ret_allocas);
llargs.push(llretptr);
}
None => {}
llargs.extend(args.iter().map(|arg| arg.val));
let retval = Call(bcx, fn_ptr, llargs.as_slice(), None);
- if type_is_zero_size(ccx, f.sig.output) || fcx.llretptr.get().is_some() {
+ if type_is_zero_size(ccx, f.sig.output) || fcx.llretslotptr.get().is_some() {
RetVoid(bcx);
} else {
Ret(bcx, retval);
use llvm::{True, False, Bool};
use mc = middle::mem_categorization;
use middle::def;
+use middle::freevars;
use middle::lang_items::LangItem;
use middle::subst;
use middle::subst::Subst;
+use middle::trans::base;
use middle::trans::build;
use middle::trans::cleanup;
use middle::trans::datum;
use middle::trans::debuginfo;
use middle::trans::type_::Type;
+use middle::trans::type_of;
use middle::ty;
use middle::typeck;
use util::ppaux::Repr;
pub type RvalueDatum = datum::Datum<datum::Rvalue>;
pub type LvalueDatum = datum::Datum<datum::Lvalue>;
-#[deriving(Clone, Eq, PartialEq)]
-pub enum HandleItemsFlag {
- IgnoreItems,
- TranslateItems,
-}
-
// Function context. Every LLVM function we create will have one of
// these.
pub struct FunctionContext<'a> {
// The environment argument in a closure.
pub llenv: Option<ValueRef>,
- // The place to store the return value. If the return type is immediate,
- // this is an alloca in the function. Otherwise, it's the hidden first
- // parameter to the function. After function construction, this should
- // always be Some.
- pub llretptr: Cell<Option<ValueRef>>,
+ // A pointer to where to store the return value. If the return type is
+ // immediate, this points to an alloca in the function. Otherwise, it's a
+ // pointer to the hidden first parameter of the function. After function
+ // construction, this should always be Some.
+ pub llretslotptr: Cell<Option<ValueRef>>,
// These pub elements: "hoisted basic blocks" containing
// administrative activities that have to happen in only one place in
pub alloca_insert_pt: Cell<Option<ValueRef>>,
pub llreturn: Cell<Option<BasicBlockRef>>,
+ // If the function has any nested return's, including something like:
+ // fn foo() -> Option<Foo> { Some(Foo { x: return None }) }, then
+ // we use a separate alloca for each return
+ pub needs_ret_allocas: bool,
+
// The a value alloca'd for calls to upcalls.rust_personality. Used when
// outputting the resume instruction.
pub personality: Cell<Option<ValueRef>>,
// True if the caller expects this fn to use the out pointer to
- // return. Either way, your code should write into llretptr, but if
- // this value is false, llretptr will be a local alloca.
+ // return. Either way, your code should write into the slot llretslotptr
+ // points to, but if this value is false, that slot will be a local alloca.
pub caller_expects_out_pointer: bool,
// Maps arguments to allocas created for them in llallocas.
// Cleanup scopes.
pub scopes: RefCell<Vec<cleanup::CleanupScope<'a>> >,
-
- // How to handle items encountered during translation of this function.
- pub handle_items: HandleItemsFlag,
}
impl<'a> FunctionContext<'a> {
self.llreturn.get().unwrap()
}
+ pub fn get_ret_slot(&self, bcx: &Block, ty: ty::t, name: &str) -> ValueRef {
+ if self.needs_ret_allocas {
+ base::alloca_no_lifetime(bcx, type_of::type_of(bcx.ccx(), ty), name)
+ } else {
+ self.llretslotptr.get().unwrap()
+ }
+ }
+
pub fn new_block(&'a self,
is_lpad: bool,
name: &str,
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
self.tcx().upvar_borrow_map.borrow().get_copy(&upvar_id)
}
+
+ fn capture_mode(&self, closure_expr_id: ast::NodeId)
+ -> freevars::CaptureMode {
+ self.tcx().capture_modes.borrow().get_copy(&closure_expr_id)
+ }
}
pub struct Result<'a> {
debuginfo::create_local_var_metadata(bcx, &**local);
}
}
- ast::DeclItem(ref i) => {
- match fcx.handle_items {
- TranslateItems => trans_item(cx.fcx.ccx, &**i),
- IgnoreItems => {}
- }
- }
+ // Inner items are visited by `trans_item`/`trans_meth`.
+ ast::DeclItem(_) => {},
}
}
ast::StmtMac(..) => cx.tcx().sess.bug("unexpanded macro")
let _icx = push_ctxt("trans_ret");
let fcx = bcx.fcx;
let mut bcx = bcx;
- let dest = match bcx.fcx.llretptr.get() {
- None => expr::Ignore,
- Some(retptr) => expr::SaveIn(retptr),
+ let dest = match (fcx.llretslotptr.get(), e) {
+ (Some(_), Some(e)) => {
+ let ret_ty = expr_ty(bcx, &*e);
+ expr::SaveIn(fcx.get_ret_slot(bcx, ret_ty, "ret_slot"))
+ }
+ _ => expr::Ignore,
};
match e {
Some(x) => {
bcx = expr::trans_into(bcx, &*x, dest);
+ match dest {
+ expr::SaveIn(slot) if fcx.needs_ret_allocas => {
+ Store(bcx, slot, fcx.llretslotptr.get().unwrap());
+ }
+ _ => {}
+ }
}
_ => {}
}
}
ast_map::NodeExpr(ref expr) => {
match expr.node {
- ast::ExprFnBlock(fn_decl, top_level_block) |
+ ast::ExprFnBlock(_, fn_decl, top_level_block) |
ast::ExprProc(fn_decl, top_level_block) |
- ast::ExprUnboxedFn(fn_decl, top_level_block) => {
+ ast::ExprUnboxedFn(_, fn_decl, top_level_block) => {
let name = format!("fn{}", token::gensym("fn"));
let name = token::str_to_ident(name.as_slice());
(name, fn_decl,
})
}
- ast::ExprFnBlock(ref decl, ref block) |
+ ast::ExprFnBlock(_, ref decl, ref block) |
ast::ExprProc(ref decl, ref block) |
- ast::ExprUnboxedFn(ref decl, ref block) => {
+ ast::ExprUnboxedFn(_, ref decl, ref block) => {
with_new_scope(cx,
block.span,
scope_stack,
ast::ExprVec(..) | ast::ExprRepeat(..) => {
tvec::trans_fixed_vstore(bcx, expr, expr, dest)
}
- ast::ExprFnBlock(ref decl, ref body) |
+ ast::ExprFnBlock(_, ref decl, ref body) |
ast::ExprProc(ref decl, ref body) => {
let expr_ty = expr_ty(bcx, expr);
let store = ty::ty_closure_store(expr_ty);
expr_to_string(expr), expr_ty.repr(tcx));
closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest)
}
- ast::ExprUnboxedFn(decl, body) => {
+ ast::ExprUnboxedFn(_, decl, body) => {
closure::trans_unboxed_closure(bcx, &*decl, &*body, expr.id, dest)
}
ast::ExprCall(ref f, ref args) => {
llwrapfn: ValueRef,
param_substs: ¶m_substs,
id: ast::NodeId,
- hash: Option<&str>,
- handle_items: HandleItemsFlag) {
+ hash: Option<&str>) {
let _icx = push_ctxt("foreign::build_foreign_fn");
let fnty = ty::node_id_to_type(ccx.tcx(), id);
unsafe { // unsafe because we call LLVM operations
// Build up the Rust function (`foo0` above).
- let llrustfn = build_rust_fn(ccx, decl, body, param_substs, attrs, id,
- hash, handle_items);
+ let llrustfn = build_rust_fn(ccx, decl, body, param_substs, attrs, id, hash);
// Build up the foreign wrapper (`foo` above).
return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys, mty);
param_substs: ¶m_substs,
attrs: &[ast::Attribute],
id: ast::NodeId,
- hash: Option<&str>,
- handle_items: HandleItemsFlag)
+ hash: Option<&str>)
-> ValueRef {
let _icx = push_ctxt("foreign::foreign::build_rust_fn");
let tcx = ccx.tcx();
let llfn = base::decl_internal_rust_fn(ccx, t, ps.as_slice());
base::set_llvm_fn_attrs(attrs, llfn);
- base::trans_fn(ccx, decl, body, llfn, param_substs, id, [], handle_items);
+ base::trans_fn(ccx, decl, body, llfn, param_substs, id, []);
llfn
}
let arena = TypedArena::new();
let empty_param_substs = param_substs::empty();
- let fcx = new_fn_ctxt(ccx, llfn, -1, false, ty::mk_nil(),
- &empty_param_substs, None, &arena, TranslateItems);
+ let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, false, ty::mk_nil(),
+ &empty_param_substs, None, &arena);
let bcx = init_function(&fcx, false, ty::mk_nil());
if unparameterized {
let llfn = get_item_val(ccx, mth.id);
trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), llfn,
- ¶m_substs::empty(), mth.id, [], TranslateItems);
+ ¶m_substs::empty(), mth.id, []);
}
local_def(mth.id)
}
pub fn trans_intrinsic_call<'a>(mut bcx: &'a Block<'a>, node: ast::NodeId,
callee_ty: ty::t, cleanup_scope: cleanup::CustomScopeIndex,
args: callee::CallArgs, dest: expr::Dest,
- substs: subst::Substs) -> Result<'a> {
+ substs: subst::Substs, call_info: NodeInfo) -> Result<'a> {
let fcx = bcx.fcx;
let ccx = fcx.ccx;
with_overflow_intrinsic(bcx, "llvm.umul.with.overflow.i64", ret_ty,
*llargs.get(0), *llargs.get(1)),
+ (_, "return_address") => {
+ if !fcx.caller_expects_out_pointer {
+ tcx.sess.span_err(call_info.span,
+ "invalid use of `return_address` intrinsic: function \
+ does not use out pointer");
+ C_null(Type::i8p(ccx))
+ } else {
+ PointerCast(bcx, llvm::get_param(fcx.llfn, 0), Type::i8p(ccx))
+ }
+ }
+
// This requires that atomic intrinsics follow a specific naming pattern:
// "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
(_, name) if name.starts_with("atomic_") => {
llfn,
¶m_substs::empty(),
method.id,
- [],
- TranslateItems);
- } else {
- let mut v = TransItemVisitor{ ccx: ccx };
- visit::walk_method_helper(&mut v, &**method, ());
+ []);
}
+ let mut v = TransItemVisitor{ ccx: ccx };
+ visit::walk_method_helper(&mut v, &**method, ());
}
}
if abi != abi::Rust {
foreign::trans_rust_fn_with_foreign_abi(
ccx, &**decl, &**body, [], d, &psubsts, fn_id.node,
- Some(hash.as_slice()), IgnoreItems);
+ Some(hash.as_slice()));
} else {
- trans_fn(ccx, &**decl, &**body, d, &psubsts, fn_id.node, [],
- IgnoreItems);
+ trans_fn(ccx, &**decl, &**body, d, &psubsts, fn_id.node, []);
}
d
ast_map::NodeMethod(mth) => {
let d = mk_lldecl(abi::Rust);
set_llvm_fn_attrs(mth.attrs.as_slice(), d);
- trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), d, &psubsts, mth.id, [],
- IgnoreItems);
+ trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), d, &psubsts, mth.id, []);
d
}
ast_map::NodeTraitMethod(method) => {
let d = mk_lldecl(abi::Rust);
set_llvm_fn_attrs(mth.attrs.as_slice(), d);
trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), d,
- &psubsts, mth.id, [], IgnoreItems);
+ &psubsts, mth.id, []);
d
}
_ => {
sym.as_slice());
let arena = TypedArena::new();
let empty_param_substs = param_substs::empty();
- let fcx = new_fn_ctxt(ccx, llfdecl, -1, false,
+ let fcx = new_fn_ctxt(ccx, llfdecl, ast::DUMMY_NODE_ID, false,
ty::mk_u64(), &empty_param_substs,
- None, &arena, TranslateItems);
+ None, &arena);
let bcx = init_function(&fcx, false, ty::mk_u64());
// we know the return type of llfdecl is an int here, so
let arg = get_param(llfdecl, fcx.arg_pos(0u) as c_uint);
let arg = BitCast(bcx, arg, llptrty);
let ret = adt::trans_get_discr(bcx, &*repr, arg, Some(Type::i64(ccx)));
- Store(bcx, ret, fcx.llretptr.get().unwrap());
+ assert!(!fcx.needs_ret_allocas);
+ let ret_slot = fcx.get_ret_slot(bcx, ty::mk_u64(), "ret_slot");
+ Store(bcx, ret, ret_slot);
match fcx.llreturn.get() {
Some(llreturn) => Br(bcx, llreturn),
None => {}
use middle::const_eval;
use middle::def;
use middle::dependency_format;
+use middle::freevars::CaptureModeMap;
+use middle::freevars;
use middle::lang_items::{FnMutTraitLangItem, OpaqueStructLangItem};
use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem};
-use middle::freevars;
use middle::resolve;
use middle::resolve_lifetime;
-use middle::subst;
-use middle::subst::{Subst, Substs, VecPerParamSpace};
use middle::stability;
+use middle::subst::{Subst, Substs, VecPerParamSpace};
+use middle::subst;
use middle::ty;
use middle::typeck;
use middle::typeck::MethodCall;
/// Maps any item's def-id to its stability index.
pub stability: RefCell<stability::Index>,
+
+ /// Maps closures to their capture clauses.
+ pub capture_modes: RefCell<CaptureModeMap>,
}
pub enum tbox_flag {
named_region_map: resolve_lifetime::NamedRegionMap,
map: ast_map::Map,
freevars: freevars::freevar_map,
+ capture_modes: freevars::CaptureModeMap,
region_maps: middle::region::RegionMaps,
lang_items: middle::lang_items::LanguageItems,
stability: stability::Index)
unboxed_closure_types: RefCell::new(DefIdMap::new()),
node_lint_levels: RefCell::new(HashMap::new()),
transmute_restrictions: RefCell::new(Vec::new()),
- stability: RefCell::new(stability)
+ stability: RefCell::new(stability),
+ capture_modes: RefCell::new(capture_modes),
}
}
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
self.upvar_borrow_map.borrow().get_copy(&upvar_id)
}
+
+ fn capture_mode(&self, closure_expr_id: ast::NodeId)
+ -> freevars::CaptureMode {
+ self.capture_modes.borrow().get_copy(&closure_expr_id)
+ }
}
/// The category of explicit self.
ast::ExprMatch(ref discrim, ref arms) => {
_match::check_match(fcx, expr, &**discrim, arms.as_slice());
}
- ast::ExprFnBlock(ref decl, ref body) => {
+ ast::ExprFnBlock(_, ref decl, ref body) => {
let region = astconv::opt_ast_region_to_region(fcx,
fcx.infcx(),
expr.span,
body.clone(),
expected);
}
- ast::ExprUnboxedFn(ref decl, ref body) => {
+ ast::ExprUnboxedFn(_, ref decl, ref body) => {
check_unboxed_closure(fcx,
expr,
&**decl,
(0, vec!(ty::mk_u64(), ty::mk_u64()),
ty::mk_tup(tcx, vec!(ty::mk_u64(), ty::mk_bool()))),
+ "return_address" => (0, vec![], ty::mk_imm_ptr(tcx, ty::mk_u8())),
+
ref other => {
span_err!(tcx.sess, it.span, E0093,
"unrecognized intrinsic function: `{}`", *other);
fn upvar_borrow(&self, id: ty::UpvarId) -> ty::UpvarBorrow {
self.fcx.inh.upvar_borrow_map.borrow().get_copy(&id)
}
+
+ fn capture_mode(&self, closure_expr_id: ast::NodeId)
+ -> freevars::CaptureMode {
+ self.tcx().capture_modes.borrow().get_copy(&closure_expr_id)
+ }
}
pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
visit::walk_expr(rcx, expr, ());
}
- ast::ExprFnBlock(_, ref body) |
+ ast::ExprFnBlock(_, _, ref body) |
ast::ExprProc(_, ref body) |
- ast::ExprUnboxedFn(_, ref body) => {
+ ast::ExprUnboxedFn(_, _, ref body) => {
check_expr_fn_block(rcx, expr, &**body);
}
MethodCall::expr(e.id));
match e.node {
- ast::ExprFnBlock(ref decl, _) |
+ ast::ExprFnBlock(_, ref decl, _) |
ast::ExprProc(ref decl, _) |
- ast::ExprUnboxedFn(ref decl, _) => {
+ ast::ExprUnboxedFn(_, ref decl, _) => {
for input in decl.inputs.iter() {
let _ = self.visit_node_id(ResolvingExpr(e.span),
input.id);
let lang_items = lang_items::collect_language_items(&krate, &sess);
let resolve::CrateMap { def_map: def_map, .. } =
resolve::resolve_crate(&sess, &lang_items, &krate);
- let freevars_map = freevars::annotate_freevars(&def_map, &krate);
+ let (freevars_map, captures_map) = freevars::annotate_freevars(&def_map,
+ &krate);
let named_region_map = resolve_lifetime::krate(&sess, &krate);
let region_map = region::resolve_crate(&sess, &krate);
let stability_index = stability::Index::build(&krate);
- let tcx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
- freevars_map, region_map, lang_items, stability_index);
+ let tcx = ty::mk_ctxt(sess,
+ def_map,
+ named_region_map,
+ ast_map,
+ freevars_map,
+ captures_map,
+ region_map,
+ lang_items,
+ stability_index);
let infcx = infer::new_infer_ctxt(&tcx);
let env = Env {krate: krate,
tcx: &tcx,
fn parse_externs(matches: &getopts::Matches) -> Result<core::Externs, String> {
let mut externs = HashMap::new();
for arg in matches.opt_strs("extern").iter() {
- let mut parts = arg.as_slice().splitn('=', 1);
+ let mut parts = arg.as_slice().splitn(1, '=');
let name = match parts.next() {
Some(s) => s,
None => {
#![crate_name = "semver"]
#![deprecated = "This is now a cargo package located at: \
https://github.com/rust-lang/semver"]
+#![allow(deprecated)]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
}
}
#[test]
- #[ignore] // FIXME(#15763)
fn test_decode_errors_struct() {
check_err::<DecodeStruct>("[]", ExpectedError("Object".to_string(), "[]".to_string()));
check_err::<DecodeStruct>("{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}",
use iter::Iterator;
use mem;
use option::{Option, Some, None};
-use slice::{ImmutableVector, MutableVector, Vector};
+use slice::{ImmutableSlice, MutableSlice, Slice};
use str::{Str, StrSlice};
use str;
use string::String;
use ptr::RawPtr;
use ptr;
use raw;
-use slice::Vector;
+use slice::Slice;
/// The type representing a foreign chunk of memory
pub struct CVec<T> {
}
}
-impl<T> Vector<T> for CVec<T> {
+impl<T> Slice<T> for CVec<T> {
/// View the stored data as a slice.
fn as_slice<'a>(&'a self) -> &'a [T] {
unsafe {
use prelude::*;
use super::HashSet;
- use slice::ImmutableEqVector;
+ use slice::ImmutablePartialEqSlice;
use collections::Collection;
#[test]
use os;
use path::{Path,GenericPath};
use result::*;
-use slice::{Vector,ImmutableVector};
+use slice::{Slice,ImmutableSlice};
use str;
use string::String;
use vec::Vec;
use ops::Drop;
use option::{Some, None, Option};
use result::{Ok, Err};
-use slice::{ImmutableVector, MutableVector};
+use slice::{ImmutableSlice, MutableSlice};
use slice;
use vec::Vec;
use io;
use option::{None, Option, Some};
use result::{Ok, Err};
-use slice::{bytes, MutableVector, ImmutableVector};
+use slice::{bytes, MutableSlice, ImmutableSlice};
use str::StrSlice;
use super::{Reader, Writer, IoResult};
use vec::Vec;
use result::{Ok, Err};
use io;
use io::{IoError, IoResult, Reader};
-use slice::{ImmutableVector, Vector};
+use slice::{ImmutableSlice, Slice};
use ptr::RawPtr;
/// An iterator that reads a single byte on each iteration,
pub fn u64_from_be_bytes(data: &[u8], start: uint, size: uint) -> u64 {
use ptr::{copy_nonoverlapping_memory};
use mem::from_be64;
- use slice::MutableVector;
+ use slice::MutableSlice;
assert!(size <= 8u);
use result::{Err, Ok};
use rt::rtio::LocalIo;
use rt::rtio;
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use string::String;
use vec::Vec;
use io;
use io::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, IoResult};
use slice;
-use slice::{Vector, ImmutableVector, MutableVector};
+use slice::{Slice, ImmutableSlice, MutableSlice};
use vec::Vec;
static BUF_CAPACITY: uint = 128;
use boxed::Box;
use result::{Ok, Err, Result};
use rt::rtio;
-use slice::{Vector, MutableVector, ImmutableVector};
+use slice::{Slice, MutableSlice, ImmutableSlice};
use str::{Str, StrSlice};
use str;
use string::String;
use iter::Iterator;
use option::{Option, None, Some};
use str::StrSlice;
-use slice::{MutableCloneableVector, ImmutableVector, MutableVector};
+use slice::{MutableCloneableSlice, ImmutableSlice, MutableSlice};
pub type Port = u16;
use collections::MutableSeq;
use io::IoResult;
use iter::Iterator;
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use result::{Ok,Err};
use io::net::addrinfo::get_host_addresses;
use io::net::ip::SocketAddr;
use io::{IoError, ConnectionFailed, InvalidInput};
use io::{Reader, Writer, Listener, Acceptor};
+use io::{standard_error, TimedOut};
use from_str::FromStr;
use kinds::Send;
use option::{None, Some, Option};
use rt::rtio::{IoFactory, LocalIo, RtioSocket, RtioTcpListener};
use rt::rtio::{RtioTcpAcceptor, RtioTcpStream};
use rt::rtio;
+use time::Duration;
/// A structure which represents a TCP stream between a local socket and a
/// remote socket.
}
/// Creates a TCP connection to a remote socket address, timing out after
- /// the specified number of milliseconds.
+ /// the specified duration.
///
/// This is the same as the `connect` method, except that if the timeout
/// specified (in milliseconds) elapses before a connection is made an error
///
/// Note that the `addr` argument may one day be split into a separate host
/// and port, similar to the API seen in `connect`.
+ ///
+ /// If a `timeout` with zero or negative duration is specified then
+ /// the function returns `Err`, with the error kind set to `TimedOut`.
#[experimental = "the timeout argument may eventually change types"]
pub fn connect_timeout(addr: SocketAddr,
- timeout_ms: u64) -> IoResult<TcpStream> {
+ timeout: Duration) -> IoResult<TcpStream> {
+ if timeout <= Duration::milliseconds(0) {
+ return Err(standard_error(TimedOut));
+ }
+
let SocketAddr { ip, port } = addr;
let addr = rtio::SocketAddr { ip: super::to_rtio(ip), port: port };
LocalIo::maybe_raise(|io| {
- io.tcp_connect(addr, Some(timeout_ms)).map(TcpStream::new)
+ io.tcp_connect(addr, Some(timeout.num_milliseconds() as u64)).map(TcpStream::new)
}).map_err(IoError::from_rtio_error)
}
/// # #![allow(unused_must_use)]
/// use std::io::timer;
/// use std::io::TcpStream;
+ /// use std::time::Duration;
///
/// let mut stream = TcpStream::connect("127.0.0.1", 34254).unwrap();
/// let stream2 = stream.clone();
///
/// spawn(proc() {
/// // close this stream after one second
- /// timer::sleep(1000);
+ /// timer::sleep(Duration::seconds(1));
/// let mut stream = stream2;
/// stream.close_read();
/// });
use c_str::ToCStr;
use clone::Clone;
use io::{Listener, Acceptor, Reader, Writer, IoResult, IoError};
+use io::{standard_error, TimedOut};
use kinds::Send;
use boxed::Box;
use rt::rtio::{IoFactory, LocalIo, RtioUnixListener};
use rt::rtio::{RtioUnixAcceptor, RtioPipe};
+use time::Duration;
/// A stream which communicates over a named pipe.
pub struct UnixStream {
///
/// This function is similar to `connect`, except that if `timeout_ms`
/// elapses the function will return an error of kind `TimedOut`.
+ ///
+ /// If a `timeout` with zero or negative duration is specified then
+ /// the function returns `Err`, with the error kind set to `TimedOut`.
#[experimental = "the timeout argument is likely to change types"]
pub fn connect_timeout<P: ToCStr>(path: &P,
- timeout_ms: u64) -> IoResult<UnixStream> {
+ timeout: Duration) -> IoResult<UnixStream> {
+ if timeout <= Duration::milliseconds(0) {
+ return Err(standard_error(TimedOut));
+ }
+
LocalIo::maybe_raise(|io| {
- let s = io.unix_connect(&path.to_c_str(), Some(timeout_ms));
+ let s = io.unix_connect(&path.to_c_str(), Some(timeout.num_milliseconds() as u64));
s.map(|p| UnixStream { obj: p })
}).map_err(IoError::from_rtio_error)
}
iotest!(fn connect_timeout_error() {
let addr = next_test_unix();
- assert!(UnixStream::connect_timeout(&addr, 100).is_err());
+ assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(100)).is_err());
})
iotest!(fn connect_timeout_success() {
let addr = next_test_unix();
let _a = UnixListener::bind(&addr).unwrap().listen().unwrap();
- assert!(UnixStream::connect_timeout(&addr, 100).is_ok());
+ assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(100)).is_ok());
+ })
+
+ iotest!(fn connect_timeout_zero() {
+ let addr = next_test_unix();
+ let _a = UnixListener::bind(&addr).unwrap().listen().unwrap();
+ assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(0)).is_err());
+ })
+
+ iotest!(fn connect_timeout_negative() {
+ let addr = next_test_unix();
+ let _a = UnixListener::bind(&addr).unwrap().listen().unwrap();
+ assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(-1)).is_err());
})
iotest!(fn close_readwrite_smoke() {
Ignored,
/// The specified file descriptor is inherited for the stream which it is
- /// specified for.
+ /// specified for. Ownership of the file descriptor is *not* taken, so the
+ /// caller must clean it up.
InheritFd(libc::c_int),
/// Creates a pipe for the specified file descriptor which will be created
#[cfg(test)]
mod tests {
+ extern crate native;
use io::process::{Command, Process};
use prelude::*;
assert!(!p.wait().unwrap().success());
return
}
- timer::sleep(100);
+ timer::sleep(Duration::milliseconds(100));
}
fail!("never saw the child go away");
})
assert!(Process::kill(id, 0).is_ok());
assert!(Process::kill(id, PleaseExitSignal).is_ok());
})
+
+ iotest!(fn dont_close_fd_on_command_spawn() {
+ use std::rt::rtio::{Truncate, Write};
+ use native::io::file;
+
+ let path = if cfg!(windows) {
+ Path::new("NUL")
+ } else {
+ Path::new("/dev/null")
+ };
+
+ let mut fdes = match file::open(&path.to_c_str(), Truncate, Write) {
+ Ok(f) => f,
+ Err(_) => fail!("failed to open file descriptor"),
+ };
+
+ let mut cmd = pwd_cmd();
+ let _ = cmd.stdout(InheritFd(fdes.fd()));
+ assert!(cmd.status().unwrap().success());
+ assert!(fdes.inner_write("extra write\n".as_bytes()).is_ok());
+ })
}
use boxed::Box;
use result::{Ok, Err};
use rt::rtio::{IoFactory, LocalIo, RtioSignal, Callback};
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use vec::Vec;
/// Signals that can be sent and received
use comm::Empty;
use io::timer;
use super::{Listener, Interrupt};
+ use time::Duration;
fn sigint() {
unsafe {
let mut signal = Listener::new();
signal.register(Interrupt).unwrap();
sigint();
- timer::sleep(10);
+ timer::sleep(Duration::milliseconds(10));
match signal.rx.recv() {
Interrupt => (),
s => fail!("Expected Interrupt, got {:?}", s),
s1.register(Interrupt).unwrap();
s2.register(Interrupt).unwrap();
sigint();
- timer::sleep(10);
+ timer::sleep(Duration::milliseconds(10));
match s1.rx.recv() {
Interrupt => (),
s => fail!("Expected Interrupt, got {:?}", s),
s2.register(Interrupt).unwrap();
s2.unregister(Interrupt);
sigint();
- timer::sleep(10);
+ timer::sleep(Duration::milliseconds(10));
assert_eq!(s2.rx.try_recv(), Err(Empty));
}
}
use rt::local::Local;
use rt::task::Task;
use rt::rtio::{DontClose, IoFactory, LocalIo, RtioFileStream, RtioTTY};
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use str::StrSlice;
use uint;
use io::process::*;
use rt::running_on_valgrind;
use str;
+ use time::Duration;
fn f() $b
*/
+// FIXME: These functions take Durations but only pass ms to the backend impls.
+
use comm::{Receiver, Sender, channel};
+use time::Duration;
use io::{IoResult, IoError};
use kinds::Send;
use boxed::Box;
/// # fn main() {}
/// # fn foo() {
/// use std::io::Timer;
+/// use std::time::Duration;
///
/// let mut timer = Timer::new().unwrap();
-/// timer.sleep(10); // block the task for awhile
+/// timer.sleep(Duration::milliseconds(10)); // block the task for awhile
///
-/// let timeout = timer.oneshot(10);
+/// let timeout = timer.oneshot(Duration::milliseconds(10));
/// // do some work
/// timeout.recv(); // wait for the timeout to expire
///
-/// let periodic = timer.periodic(10);
+/// let periodic = timer.periodic(Duration::milliseconds(10));
/// loop {
/// periodic.recv();
/// // this loop is only executed once every 10ms
/// # fn main() {}
/// # fn foo() {
/// use std::io::timer;
+/// use std::time::Duration;
///
/// // Put this task to sleep for 5 seconds
-/// timer::sleep(5000);
+/// timer::sleep(Duration::seconds(5));
/// # }
/// ```
pub struct Timer {
struct TimerCallback { tx: Sender<()> }
-/// Sleep the current task for `msecs` milliseconds.
-pub fn sleep(msecs: u64) {
+/// Sleep the current task for the specified duration.
+///
+/// When provided a zero or negative `duration`, the function will
+/// return immediately.
+pub fn sleep(duration: Duration) {
let timer = Timer::new();
let mut timer = timer.ok().expect("timer::sleep: could not create a Timer");
- timer.sleep(msecs)
+ timer.sleep(duration)
}
impl Timer {
}).map_err(IoError::from_rtio_error)
}
- /// Blocks the current task for `msecs` milliseconds.
+ /// Blocks the current task for the specified duration.
///
/// Note that this function will cause any other receivers for this timer to
/// be invalidated (the other end will be closed).
- pub fn sleep(&mut self, msecs: u64) {
- self.obj.sleep(msecs);
+ ///
+ /// When provided a zero or negative `duration`, the function will
+ /// return immediately.
+ pub fn sleep(&mut self, duration: Duration) {
+ // Short-circuit the timer backend for 0 duration
+ let ms = in_ms_u64(duration);
+ if ms == 0 { return }
+ self.obj.sleep(ms);
}
/// Creates a oneshot receiver which will have a notification sent when
- /// `msecs` milliseconds has elapsed.
+ /// the specified duration has elapsed.
///
/// This does *not* block the current task, but instead returns immediately.
///
///
/// ```rust
/// use std::io::Timer;
+ /// use std::time::Duration;
///
/// let mut timer = Timer::new().unwrap();
- /// let ten_milliseconds = timer.oneshot(10);
+ /// let ten_milliseconds = timer.oneshot(Duration::milliseconds(10));
///
/// for _ in range(0u, 100) { /* do work */ }
///
///
/// ```rust
/// use std::io::Timer;
+ /// use std::time::Duration;
///
/// // Incorrect, method chaining-style:
- /// let mut five_ms = Timer::new().unwrap().oneshot(5);
+ /// let mut five_ms = Timer::new().unwrap().oneshot(Duration::milliseconds(5));
/// // The timer object was destroyed, so this will always fail:
/// // five_ms.recv()
/// ```
- pub fn oneshot(&mut self, msecs: u64) -> Receiver<()> {
+ ///
+ /// When provided a zero or negative `duration`, the message will
+ /// be sent immediately.
+ pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> {
let (tx, rx) = channel();
- self.obj.oneshot(msecs, box TimerCallback { tx: tx });
+ // Short-circuit the timer backend for 0 duration
+ if in_ms_u64(duration) != 0 {
+ self.obj.oneshot(in_ms_u64(duration), box TimerCallback { tx: tx });
+ } else {
+ tx.send(());
+ }
return rx
}
/// Creates a receiver which will have a continuous stream of notifications
- /// being sent every `msecs` milliseconds.
+ /// being sent each time the specified duration has elapsed.
///
/// This does *not* block the current task, but instead returns
/// immediately. The first notification will not be received immediately,
- /// but rather after `msec` milliseconds have passed.
+ /// but rather after the first duration.
///
/// Note that this invalidates any previous receiver which has been created
/// by this timer, and that the returned receiver will be invalidated once
///
/// ```rust
/// use std::io::Timer;
+ /// use std::time::Duration;
///
/// let mut timer = Timer::new().unwrap();
- /// let ten_milliseconds = timer.periodic(10);
+ /// let ten_milliseconds = timer.periodic(Duration::milliseconds(10));
///
/// for _ in range(0u, 100) { /* do work */ }
///
///
/// ```rust
/// use std::io::Timer;
+ /// use std::time::Duration;
///
/// // Incorrect, method chaining-style.
- /// let mut five_ms = Timer::new().unwrap().periodic(5);
+ /// let mut five_ms = Timer::new().unwrap().periodic(Duration::milliseconds(5));
/// // The timer object was destroyed, so this will always fail:
/// // five_ms.recv()
/// ```
- pub fn periodic(&mut self, msecs: u64) -> Receiver<()> {
+ ///
+ /// When provided a zero or negative `duration`, the messages will
+ /// be sent without delay.
+ pub fn periodic(&mut self, duration: Duration) -> Receiver<()> {
+ let ms = in_ms_u64(duration);
+ // FIXME: The backend implementations don't ever send a message
+ // if given a 0 ms duration. Temporarily using 1ms. It's
+ // not clear what use a 0ms period is anyway...
+ let ms = if ms == 0 { 1 } else { ms };
let (tx, rx) = channel();
- self.obj.period(msecs, box TimerCallback { tx: tx });
+ self.obj.period(ms, box TimerCallback { tx: tx });
return rx
}
}
}
}
+fn in_ms_u64(d: Duration) -> u64 {
+ let ms = d.num_milliseconds();
+ if ms < 0 { return 0 };
+ return ms as u64;
+}
+
#[cfg(test)]
mod test {
iotest!(fn test_io_timer_sleep_simple() {
let mut timer = Timer::new().unwrap();
- timer.sleep(1);
+ timer.sleep(Duration::milliseconds(1));
})
iotest!(fn test_io_timer_sleep_oneshot() {
let mut timer = Timer::new().unwrap();
- timer.oneshot(1).recv();
+ timer.oneshot(Duration::milliseconds(1)).recv();
})
iotest!(fn test_io_timer_sleep_oneshot_forget() {
let mut timer = Timer::new().unwrap();
- timer.oneshot(100000000000);
+ timer.oneshot(Duration::milliseconds(100000000));
})
iotest!(fn oneshot_twice() {
let mut timer = Timer::new().unwrap();
- let rx1 = timer.oneshot(10000);
- let rx = timer.oneshot(1);
+ let rx1 = timer.oneshot(Duration::milliseconds(10000));
+ let rx = timer.oneshot(Duration::milliseconds(1));
rx.recv();
assert_eq!(rx1.recv_opt(), Err(()));
})
iotest!(fn test_io_timer_oneshot_then_sleep() {
let mut timer = Timer::new().unwrap();
- let rx = timer.oneshot(100000000000);
- timer.sleep(1); // this should invalidate rx
+ let rx = timer.oneshot(Duration::milliseconds(100000000));
+ timer.sleep(Duration::milliseconds(1)); // this should invalidate rx
assert_eq!(rx.recv_opt(), Err(()));
})
iotest!(fn test_io_timer_sleep_periodic() {
let mut timer = Timer::new().unwrap();
- let rx = timer.periodic(1);
+ let rx = timer.periodic(Duration::milliseconds(1));
rx.recv();
rx.recv();
rx.recv();
iotest!(fn test_io_timer_sleep_periodic_forget() {
let mut timer = Timer::new().unwrap();
- timer.periodic(100000000000);
+ timer.periodic(Duration::milliseconds(100000000));
})
iotest!(fn test_io_timer_sleep_standalone() {
- sleep(1)
+ sleep(Duration::milliseconds(1))
})
iotest!(fn oneshot() {
let mut timer = Timer::new().unwrap();
- let rx = timer.oneshot(1);
+ let rx = timer.oneshot(Duration::milliseconds(1));
rx.recv();
assert!(rx.recv_opt().is_err());
- let rx = timer.oneshot(1);
+ let rx = timer.oneshot(Duration::milliseconds(1));
rx.recv();
assert!(rx.recv_opt().is_err());
})
iotest!(fn override() {
let mut timer = Timer::new().unwrap();
- let orx = timer.oneshot(100);
- let prx = timer.periodic(100);
- timer.sleep(1);
+ let orx = timer.oneshot(Duration::milliseconds(100));
+ let prx = timer.periodic(Duration::milliseconds(100));
+ timer.sleep(Duration::milliseconds(1));
assert_eq!(orx.recv_opt(), Err(()));
assert_eq!(prx.recv_opt(), Err(()));
- timer.oneshot(1).recv();
+ timer.oneshot(Duration::milliseconds(1)).recv();
})
iotest!(fn period() {
let mut timer = Timer::new().unwrap();
- let rx = timer.periodic(1);
+ let rx = timer.periodic(Duration::milliseconds(1));
rx.recv();
rx.recv();
- let rx2 = timer.periodic(1);
+ let rx2 = timer.periodic(Duration::milliseconds(1));
rx2.recv();
rx2.recv();
})
iotest!(fn sleep() {
let mut timer = Timer::new().unwrap();
- timer.sleep(1);
- timer.sleep(1);
+ timer.sleep(Duration::milliseconds(1));
+ timer.sleep(Duration::milliseconds(1));
})
iotest!(fn oneshot_fail() {
let mut timer = Timer::new().unwrap();
- let _rx = timer.oneshot(1);
+ let _rx = timer.oneshot(Duration::milliseconds(1));
fail!();
} #[should_fail])
iotest!(fn period_fail() {
let mut timer = Timer::new().unwrap();
- let _rx = timer.periodic(1);
+ let _rx = timer.periodic(Duration::milliseconds(1));
fail!();
} #[should_fail])
iotest!(fn closing_channel_during_drop_doesnt_kill_everything() {
// see issue #10375
let mut timer = Timer::new().unwrap();
- let timer_rx = timer.periodic(1000);
+ let timer_rx = timer.periodic(Duration::milliseconds(1000));
spawn(proc() {
let _ = timer_rx.recv_opt();
iotest!(fn reset_doesnt_switch_tasks() {
// similar test to the one above.
let mut timer = Timer::new().unwrap();
- let timer_rx = timer.periodic(1000);
+ let timer_rx = timer.periodic(Duration::milliseconds(1000));
spawn(proc() {
let _ = timer_rx.recv_opt();
});
- timer.oneshot(1);
+ timer.oneshot(Duration::milliseconds(1));
})
iotest!(fn reset_doesnt_switch_tasks2() {
// similar test to the one above.
let mut timer = Timer::new().unwrap();
- let timer_rx = timer.periodic(1000);
+ let timer_rx = timer.periodic(Duration::milliseconds(1000));
spawn(proc() {
let _ = timer_rx.recv_opt();
});
- timer.sleep(1);
+ timer.sleep(Duration::milliseconds(1));
})
iotest!(fn sender_goes_away_oneshot() {
let rx = {
let mut timer = Timer::new().unwrap();
- timer.oneshot(1000)
+ timer.oneshot(Duration::milliseconds(1000))
};
assert_eq!(rx.recv_opt(), Err(()));
})
iotest!(fn sender_goes_away_period() {
let rx = {
let mut timer = Timer::new().unwrap();
- timer.periodic(1000)
+ timer.periodic(Duration::milliseconds(1000))
};
assert_eq!(rx.recv_opt(), Err(()));
})
iotest!(fn receiver_goes_away_oneshot() {
let mut timer1 = Timer::new().unwrap();
- timer1.oneshot(1);
+ timer1.oneshot(Duration::milliseconds(1));
let mut timer2 = Timer::new().unwrap();
// while sleeping, the previous timer should fire and not have its
// callback do something terrible.
- timer2.sleep(2);
+ timer2.sleep(Duration::milliseconds(2));
})
iotest!(fn receiver_goes_away_period() {
let mut timer1 = Timer::new().unwrap();
- timer1.periodic(1);
+ timer1.periodic(Duration::milliseconds(1));
let mut timer2 = Timer::new().unwrap();
// while sleeping, the previous timer should fire and not have its
// callback do something terrible.
- timer2.sleep(2);
+ timer2.sleep(Duration::milliseconds(2));
+ })
+
+ iotest!(fn sleep_zero() {
+ let mut timer = Timer::new().unwrap();
+ timer.sleep(Duration::milliseconds(0));
+ })
+
+ iotest!(fn sleep_negative() {
+ let mut timer = Timer::new().unwrap();
+ timer.sleep(Duration::milliseconds(-1000000));
+ })
+
+ iotest!(fn oneshot_zero() {
+ let mut timer = Timer::new().unwrap();
+ let rx = timer.oneshot(Duration::milliseconds(0));
+ rx.recv();
+ })
+
+ iotest!(fn oneshot_negative() {
+ let mut timer = Timer::new().unwrap();
+ let rx = timer.oneshot(Duration::milliseconds(-1000000));
+ rx.recv();
+ })
+
+ iotest!(fn periodic_zero() {
+ let mut timer = Timer::new().unwrap();
+ let rx = timer.periodic(Duration::milliseconds(0));
+ rx.recv();
+ rx.recv();
+ rx.recv();
+ rx.recv();
})
+
+ iotest!(fn periodic_negative() {
+ let mut timer = Timer::new().unwrap();
+ let rx = timer.periodic(Duration::milliseconds(-1000000));
+ rx.recv();
+ rx.recv();
+ rx.recv();
+ rx.recv();
+ })
+
}
#[cfg(not(test))]
pub mod gc;
+pub mod time;
+
/* Common traits */
pub mod from_str;
use num::{ToStrRadix, FromStrRadix};
use num::strconv;
use option::Option;
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use string::String;
pub use core::i16::{BITS, BYTES, MIN, MAX};
use num::{ToStrRadix, FromStrRadix};
use num::strconv;
use option::Option;
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use string::String;
pub use core::i32::{BITS, BYTES, MIN, MAX};
use num::{ToStrRadix, FromStrRadix};
use num::strconv;
use option::Option;
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use string::String;
pub use core::i64::{BITS, BYTES, MIN, MAX};
use num::{ToStrRadix, FromStrRadix};
use num::strconv;
use option::Option;
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use string::String;
pub use core::i8::{BITS, BYTES, MIN, MAX};
use num::{ToStrRadix, FromStrRadix};
use num::strconv;
use option::Option;
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use string::String;
pub use core::int::{BITS, BYTES, MIN, MAX};
use num;
use ops::{Add, Sub, Mul, Div, Rem, Neg};
use option::{None, Option, Some};
-use slice::{ImmutableVector, MutableVector};
+use slice::{ImmutableSlice, MutableSlice};
use std::cmp::{PartialOrd, PartialEq};
use str::StrSlice;
use string::String;
use num::{ToStrRadix, FromStrRadix};
use num::strconv;
use option::Option;
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use string::String;
pub use core::u16::{BITS, BYTES, MIN, MAX};
use num::{ToStrRadix, FromStrRadix};
use num::strconv;
use option::Option;
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use string::String;
pub use core::u32::{BITS, BYTES, MIN, MAX};
use num::{ToStrRadix, FromStrRadix};
use num::strconv;
use option::Option;
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use string::String;
pub use core::u64::{BITS, BYTES, MIN, MAX};
use num::{ToStrRadix, FromStrRadix};
use num::strconv;
use option::Option;
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use string::String;
pub use core::u8::{BITS, BYTES, MIN, MAX};
use num::{ToStrRadix, FromStrRadix};
use num::strconv;
use option::Option;
-use slice::ImmutableVector;
+use slice::ImmutableSlice;
use string::String;
pub use core::uint::{BITS, BYTES, MIN, MAX};
use ptr::RawPtr;
use ptr;
use result::{Err, Ok, Result};
-use slice::{Vector, ImmutableVector, MutableVector, ImmutableEqVector};
+use slice::{Slice, ImmutableSlice, MutableSlice, ImmutablePartialEqSlice};
use str::{Str, StrSlice, StrAllocating};
use string::String;
use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
use option::{None, Option};
use option;
use os::TMPBUF_SZ;
- use slice::{MutableVector, ImmutableVector};
+ use slice::{MutableSlice, ImmutableSlice};
use string::String;
use str::StrSlice;
use vec::Vec;
use str;
use str::{MaybeOwned, Str, StrSlice};
use string::String;
-use slice::Vector;
-use slice::{ImmutableEqVector, ImmutableVector};
+use slice::Slice;
+use slice::{ImmutablePartialEqSlice, ImmutableSlice};
use vec::Vec;
/// Typedef for POSIX file paths.
use option::{Option, None, Some};
use str::Str;
use str;
-use slice::{CloneableVector, Splits, Vector, VectorVector,
- ImmutableEqVector, ImmutableVector};
+use slice::{CloneableVector, Splits, Slice, VectorVector,
+ ImmutablePartialEqSlice, ImmutableSlice};
use vec::Vec;
use super::{BytesContainer, GenericPath, GenericPathUnsafe};
/// Returns a normalized byte vector representation of a path, by removing all empty
/// components, and unnecessary . and .. components.
- fn normalize<V: Vector<u8>+CloneableVector<u8>>(v: V) -> Vec<u8> {
+ fn normalize<V: Slice<u8>+CloneableVector<u8>>(v: V) -> Vec<u8> {
// borrowck is being very picky
let val = {
let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == SEP_BYTE;
use iter::{AdditiveIterator, DoubleEndedIterator, Extendable, Iterator, Map};
use mem;
use option::{Option, Some, None};
-use slice::{Vector, ImmutableVector};
+use slice::{Slice, ImmutableSlice};
use str::{CharSplits, Str, StrAllocating, StrVector, StrSlice};
use string::String;
use unicode::char::UnicodeChar;
#[doc(no_inline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8};
#[doc(no_inline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12};
#[doc(no_inline)] pub use slice::{CloneableVector, ImmutableCloneableVector};
-#[doc(no_inline)] pub use slice::{MutableCloneableVector, MutableOrdVector};
-#[doc(no_inline)] pub use slice::{ImmutableVector, MutableVector};
-#[doc(no_inline)] pub use slice::{ImmutableEqVector, ImmutableOrdVector};
-#[doc(no_inline)] pub use slice::{Vector, VectorVector};
-#[doc(no_inline)] pub use slice::MutableVectorAllocating;
+#[doc(no_inline)] pub use slice::{MutableCloneableSlice, MutableOrdSlice};
+#[doc(no_inline)] pub use slice::{ImmutableSlice, MutableSlice};
+#[doc(no_inline)] pub use slice::{ImmutablePartialEqSlice, ImmutableOrdSlice};
+#[doc(no_inline)] pub use slice::{Slice, VectorVector};
+#[doc(no_inline)] pub use slice::MutableSliceAllocating;
#[doc(no_inline)] pub use string::String;
#[doc(no_inline)] pub use vec::Vec;
use rand::Rng;
use result::{Ok};
use self::libc::{c_int, size_t};
- use slice::MutableVector;
+ use slice::MutableSlice;
/// A random number generator that retrieves randomness straight from
/// the operating system. Platform sources:
use rt::stack;
use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
use self::libc::types::os::arch::extra::{LONG_PTR};
- use slice::MutableVector;
+ use slice::MutableSlice;
type HCRYPTPROV = LONG_PTR;
pub fn write(w: &mut Writer) -> IoResult<()> {
use iter::{Iterator, range};
use result;
- use slice::{MutableVector};
+ use slice::{MutableSlice};
extern {
fn backtrace(buf: *mut *mut libc::c_void,
use path::GenericPath;
use ptr::RawPtr;
use ptr;
- use slice::{ImmutableVector, MutableVector};
+ use slice::{ImmutableSlice, MutableSlice};
////////////////////////////////////////////////////////////////////////
// libbacktrace.h API
use path::Path;
use result::{Ok, Err};
use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
- use slice::ImmutableVector;
+ use slice::ImmutableSlice;
use str::StrSlice;
use dynamic_lib::DynamicLibrary;
#[test]
fn task_abort_no_kill_runtime() {
use std::io::timer;
+ use time::Duration;
use mem;
let tb = TaskBuilder::new();
let rx = tb.try_future(proc() {});
mem::drop(rx);
- timer::sleep(1000);
+ timer::sleep(Duration::milliseconds(1000));
}
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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.
+
+//! Temporal quantification
+
+#![experimental]
+
+use {fmt, i32};
+use ops::{Add, Sub, Mul, Div, Neg};
+use option::{Option, Some, None};
+use num;
+use num::{CheckedAdd, CheckedMul};
+use result::{Result, Ok, Err};
+
+
+/// `Duration`'s `days` component should have no more than this value.
+static MIN_DAYS: i32 = i32::MIN;
+/// `Duration`'s `days` component should have no less than this value.
+static MAX_DAYS: i32 = i32::MAX;
+
+/// The number of nanoseconds in seconds.
+static NANOS_PER_SEC: i32 = 1_000_000_000;
+/// The number of (non-leap) seconds in days.
+static SECS_PER_DAY: i32 = 86400;
+
+macro_rules! try_opt(
+ ($e:expr) => (match $e { Some(v) => v, None => return None })
+)
+
+
+// FIXME #16466: This could be represented as (i64 seconds, u32 nanos)
+/// ISO 8601 time duration with nanosecond precision.
+/// This also allows for the negative duration; see individual methods for details.
+#[deriving(PartialEq, Eq, PartialOrd, Ord)]
+pub struct Duration {
+ days: i32,
+ secs: u32, // Always < SECS_PER_DAY
+ nanos: u32, // Always < NANOS_PR_SECOND
+}
+
+/// The minimum possible `Duration`.
+pub static MIN: Duration = Duration { days: MIN_DAYS, secs: 0, nanos: 0 };
+/// The maximum possible `Duration`.
+pub static MAX: Duration = Duration { days: MAX_DAYS, secs: SECS_PER_DAY as u32 - 1,
+ nanos: NANOS_PER_SEC as u32 - 1 };
+
+impl Duration {
+ /// Makes a new `Duration` with given number of weeks.
+ /// Equivalent to `Duration::new(weeks * 7, 0, 0)` with overflow checks.
+ ///
+ /// Fails when the duration is out of bounds.
+ #[inline]
+ pub fn weeks(weeks: i32) -> Duration {
+ let days = weeks.checked_mul(&7).expect("Duration::weeks out of bounds");
+ Duration::days(days)
+ }
+
+ /// Makes a new `Duration` with given number of days.
+ /// Equivalent to `Duration::new(days, 0, 0)`.
+ #[inline]
+ pub fn days(days: i32) -> Duration {
+ Duration { days: days, secs: 0, nanos: 0 }
+ }
+
+ /// Makes a new `Duration` with given number of hours.
+ /// Equivalent to `Duration::new(0, hours * 3600, 0)` with overflow checks.
+ #[inline]
+ pub fn hours(hours: i32) -> Duration {
+ let (days, hours) = div_mod_floor(hours, (SECS_PER_DAY / 3600));
+ let secs = hours * 3600;
+ Duration { secs: secs as u32, ..Duration::days(days) }
+ }
+
+ /// Makes a new `Duration` with given number of minutes.
+ /// Equivalent to `Duration::new(0, mins * 60, 0)` with overflow checks.
+ #[inline]
+ pub fn minutes(mins: i32) -> Duration {
+ let (days, mins) = div_mod_floor(mins, (SECS_PER_DAY / 60));
+ let secs = mins * 60;
+ Duration { secs: secs as u32, ..Duration::days(days) }
+ }
+
+ /// Makes a new `Duration` with given number of seconds.
+ /// Equivalent to `Duration::new(0, secs, 0)`.
+ #[inline]
+ pub fn seconds(secs: i32) -> Duration {
+ let (days, secs) = div_mod_floor(secs, SECS_PER_DAY);
+ Duration { secs: secs as u32, ..Duration::days(days) }
+ }
+
+ /// Makes a new `Duration` with given number of milliseconds.
+ /// Equivalent to `Duration::new(0, 0, millis * 1_000_000)` with overflow checks.
+ #[inline]
+ pub fn milliseconds(millis: i32) -> Duration {
+ let (secs, millis) = div_mod_floor(millis, (NANOS_PER_SEC / 1_000_000));
+ let nanos = millis * 1_000_000;
+ Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
+ }
+
+ /// Makes a new `Duration` with given number of microseconds.
+ /// Equivalent to `Duration::new(0, 0, micros * 1_000)` with overflow checks.
+ #[inline]
+ pub fn microseconds(micros: i32) -> Duration {
+ let (secs, micros) = div_mod_floor(micros, (NANOS_PER_SEC / 1_000));
+ let nanos = micros * 1_000;
+ Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
+ }
+
+ /// Makes a new `Duration` with given number of nanoseconds.
+ /// Equivalent to `Duration::new(0, 0, nanos)`.
+ #[inline]
+ pub fn nanoseconds(nanos: i32) -> Duration {
+ let (secs, nanos) = div_mod_floor(nanos, NANOS_PER_SEC);
+ Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
+ }
+
+ /// Returns a tuple of the number of days, (non-leap) seconds and
+ /// nanoseconds in the duration. Note that the number of seconds
+ /// and nanoseconds are always positive, so that for example
+ /// `-Duration::seconds(3)` has -1 days and 86,397 seconds.
+ #[inline]
+ fn to_tuple_64(&self) -> (i64, u32, u32) {
+ (self.days as i64, self.secs, self.nanos)
+ }
+
+ /// Negates the duration and returns a tuple like `to_tuple`.
+ /// This does not overflow and thus is internally used for several methods.
+ fn to_negated_tuple_64(&self) -> (i64, u32, u32) {
+ let mut days = -(self.days as i64);
+ let mut secs = -(self.secs as i32);
+ let mut nanos = -(self.nanos as i32);
+ if nanos < 0 {
+ nanos += NANOS_PER_SEC;
+ secs -= 1;
+ }
+ if secs < 0 {
+ secs += SECS_PER_DAY;
+ days -= 1;
+ }
+ (days, secs as u32, nanos as u32)
+ }
+
+ /// Returns the total number of whole weeks in the duration.
+ #[inline]
+ pub fn num_weeks(&self) -> i32 {
+ self.num_days() / 7
+ }
+
+ /// Returns the total number of whole days in the duration.
+ pub fn num_days(&self) -> i32 {
+ if self.days < 0 {
+ let negated = -*self;
+ -negated.days
+ } else {
+ self.days
+ }
+ }
+
+ /// Returns the total number of whole hours in the duration.
+ #[inline]
+ pub fn num_hours(&self) -> i64 {
+ self.num_seconds() / 3600
+ }
+
+ /// Returns the total number of whole minutes in the duration.
+ #[inline]
+ pub fn num_minutes(&self) -> i64 {
+ self.num_seconds() / 60
+ }
+
+ /// Returns the total number of whole seconds in the duration.
+ pub fn num_seconds(&self) -> i64 {
+ // cannot overflow, 2^32 * 86400 < 2^64
+ fn secs((days, secs, _): (i64, u32, u32)) -> i64 {
+ days as i64 * SECS_PER_DAY as i64 + secs as i64
+ }
+ if self.days < 0 {-secs(self.to_negated_tuple_64())} else {secs(self.to_tuple_64())}
+ }
+
+ /// Returns the total number of whole milliseconds in the duration.
+ pub fn num_milliseconds(&self) -> i64 {
+ // cannot overflow, 2^32 * 86400 * 1000 < 2^64
+ fn millis((days, secs, nanos): (i64, u32, u32)) -> i64 {
+ static MILLIS_PER_SEC: i64 = 1_000;
+ static NANOS_PER_MILLI: i64 = 1_000_000;
+ (days as i64 * MILLIS_PER_SEC * SECS_PER_DAY as i64 +
+ secs as i64 * MILLIS_PER_SEC +
+ nanos as i64 / NANOS_PER_MILLI)
+ }
+ if self.days < 0 {-millis(self.to_negated_tuple_64())} else {millis(self.to_tuple_64())}
+ }
+
+ /// Returns the total number of whole microseconds in the duration,
+ /// or `None` on the overflow (exceeding 2^63 microseconds in either directions).
+ pub fn num_microseconds(&self) -> Option<i64> {
+ fn micros((days, secs, nanos): (i64, u32, u32)) -> Option<i64> {
+ static MICROS_PER_SEC: i64 = 1_000_000;
+ static MICROS_PER_DAY: i64 = MICROS_PER_SEC * SECS_PER_DAY as i64;
+ static NANOS_PER_MICRO: i64 = 1_000;
+ let nmicros = try_opt!((days as i64).checked_mul(&MICROS_PER_DAY));
+ let nmicros = try_opt!(nmicros.checked_add(&(secs as i64 * MICROS_PER_SEC)));
+ let nmicros = try_opt!(nmicros.checked_add(&(nanos as i64 / NANOS_PER_MICRO as i64)));
+ Some(nmicros)
+ }
+ if self.days < 0 {
+ // the final negation won't overflow since we start with positive numbers.
+ micros(self.to_negated_tuple_64()).map(|micros| -micros)
+ } else {
+ micros(self.to_tuple_64())
+ }
+ }
+
+ /// Returns the total number of whole nanoseconds in the duration,
+ /// or `None` on the overflow (exceeding 2^63 nanoseconds in either directions).
+ pub fn num_nanoseconds(&self) -> Option<i64> {
+ fn nanos((days, secs, nanos): (i64, u32, u32)) -> Option<i64> {
+ static NANOS_PER_DAY: i64 = NANOS_PER_SEC as i64 * SECS_PER_DAY as i64;
+ let nnanos = try_opt!((days as i64).checked_mul(&NANOS_PER_DAY));
+ let nnanos = try_opt!(nnanos.checked_add(&(secs as i64 * NANOS_PER_SEC as i64)));
+ let nnanos = try_opt!(nnanos.checked_add(&(nanos as i64)));
+ Some(nnanos)
+ }
+ if self.days < 0 {
+ // the final negation won't overflow since we start with positive numbers.
+ nanos(self.to_negated_tuple_64()).map(|micros| -micros)
+ } else {
+ nanos(self.to_tuple_64())
+ }
+ }
+}
+
+impl num::Bounded for Duration {
+ #[inline] fn min_value() -> Duration { MIN }
+ #[inline] fn max_value() -> Duration { MAX }
+}
+
+impl num::Zero for Duration {
+ #[inline]
+ fn zero() -> Duration {
+ Duration { days: 0, secs: 0, nanos: 0 }
+ }
+
+ #[inline]
+ fn is_zero(&self) -> bool {
+ self.days == 0 && self.secs == 0 && self.nanos == 0
+ }
+}
+
+impl Neg<Duration> for Duration {
+ #[inline]
+ fn neg(&self) -> Duration {
+ let (days, secs, nanos) = self.to_negated_tuple_64();
+ Duration { days: days as i32, secs: secs, nanos: nanos } // FIXME can overflow
+ }
+}
+
+impl Add<Duration,Duration> for Duration {
+ fn add(&self, rhs: &Duration) -> Duration {
+ let mut days = self.days + rhs.days;
+ let mut secs = self.secs + rhs.secs;
+ let mut nanos = self.nanos + rhs.nanos;
+ if nanos >= NANOS_PER_SEC as u32 {
+ nanos -= NANOS_PER_SEC as u32;
+ secs += 1;
+ }
+ if secs >= SECS_PER_DAY as u32 {
+ secs -= SECS_PER_DAY as u32;
+ days += 1;
+ }
+ Duration { days: days, secs: secs, nanos: nanos }
+ }
+}
+
+impl num::CheckedAdd for Duration {
+ fn checked_add(&self, rhs: &Duration) -> Option<Duration> {
+ let mut days = try_opt!(self.days.checked_add(&rhs.days));
+ let mut secs = self.secs + rhs.secs;
+ let mut nanos = self.nanos + rhs.nanos;
+ if nanos >= NANOS_PER_SEC as u32 {
+ nanos -= NANOS_PER_SEC as u32;
+ secs += 1;
+ }
+ if secs >= SECS_PER_DAY as u32 {
+ secs -= SECS_PER_DAY as u32;
+ days = try_opt!(days.checked_add(&1));
+ }
+ Some(Duration { days: days, secs: secs, nanos: nanos })
+ }
+}
+
+impl Sub<Duration,Duration> for Duration {
+ fn sub(&self, rhs: &Duration) -> Duration {
+ let mut days = self.days - rhs.days;
+ let mut secs = self.secs as i32 - rhs.secs as i32;
+ let mut nanos = self.nanos as i32 - rhs.nanos as i32;
+ if nanos < 0 {
+ nanos += NANOS_PER_SEC;
+ secs -= 1;
+ }
+ if secs < 0 {
+ secs += SECS_PER_DAY;
+ days -= 1;
+ }
+ Duration { days: days, secs: secs as u32, nanos: nanos as u32 }
+ }
+}
+
+impl num::CheckedSub for Duration {
+ fn checked_sub(&self, rhs: &Duration) -> Option<Duration> {
+ let mut days = try_opt!(self.days.checked_sub(&rhs.days));
+ let mut secs = self.secs as i32 - rhs.secs as i32;
+ let mut nanos = self.nanos as i32 - rhs.nanos as i32;
+ if nanos < 0 {
+ nanos += NANOS_PER_SEC;
+ secs -= 1;
+ }
+ if secs < 0 {
+ secs += SECS_PER_DAY;
+ days = try_opt!(days.checked_sub(&1));
+ }
+ Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 })
+ }
+}
+
+impl Mul<i32,Duration> for Duration {
+ fn mul(&self, rhs: &i32) -> Duration {
+ /// Given `0 <= y < limit <= 2^30`,
+ /// returns `(h,l)` such that `x * y = h * limit + l` where `0 <= l < limit`.
+ fn mul_i64_u32_limit(x: i64, y: u32, limit: u32) -> (i64,u32) {
+ let y = y as i64;
+ let limit = limit as i64;
+ let (xh, xl) = div_mod_floor_64(x, limit);
+ let (h, l) = (xh * y, xl * y);
+ let (h_, l) = div_rem_64(l, limit);
+ (h + h_, l as u32)
+ }
+
+ let rhs = *rhs as i64;
+ let (secs1, nanos) = mul_i64_u32_limit(rhs, self.nanos, NANOS_PER_SEC as u32);
+ let (days1, secs1) = div_mod_floor_64(secs1, (SECS_PER_DAY as i64));
+ let (days2, secs2) = mul_i64_u32_limit(rhs, self.secs, SECS_PER_DAY as u32);
+ let mut days = self.days as i64 * rhs + days1 + days2;
+ let mut secs = secs1 as u32 + secs2;
+ if secs >= SECS_PER_DAY as u32 {
+ secs -= 1;
+ days += 1;
+ }
+ Duration { days: days as i32, secs: secs, nanos: nanos }
+ }
+}
+
+impl Div<i32,Duration> for Duration {
+ fn div(&self, rhs: &i32) -> Duration {
+ let (rhs, days, secs, nanos) = if *rhs < 0 {
+ let (days, secs, nanos) = self.to_negated_tuple_64();
+ (-(*rhs as i64), days, secs as i64, nanos as i64)
+ } else {
+ (*rhs as i64, self.days as i64, self.secs as i64, self.nanos as i64)
+ };
+
+ let (days, carry) = div_mod_floor_64(days, rhs);
+ let secs = secs + carry * SECS_PER_DAY as i64;
+ let (secs, carry) = div_mod_floor_64(secs, rhs);
+ let nanos = nanos + carry * NANOS_PER_SEC as i64;
+ let nanos = nanos / rhs;
+ Duration { days: days as i32, secs: secs as u32, nanos: nanos as u32 }
+ }
+}
+
+impl fmt::Show for Duration {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let hasdate = self.days != 0;
+ let hastime = (self.secs != 0 || self.nanos != 0) || !hasdate;
+
+ try!(write!(f, "P"));
+ if hasdate {
+ // technically speaking the negative part is not the valid ISO 8601,
+ // but we need to print it anyway.
+ try!(write!(f, "{}D", self.days));
+ }
+ if hastime {
+ if self.nanos == 0 {
+ try!(write!(f, "T{}S", self.secs));
+ } else if self.nanos % 1_000_000 == 0 {
+ try!(write!(f, "T{}.{:03}S", self.secs, self.nanos / 1_000_000));
+ } else if self.nanos % 1_000 == 0 {
+ try!(write!(f, "T{}.{:06}S", self.secs, self.nanos / 1_000));
+ } else {
+ try!(write!(f, "T{}.{:09}S", self.secs, self.nanos));
+ }
+ }
+ Ok(())
+ }
+}
+
+// Copied from libnum
+#[inline]
+fn div_mod_floor(this: i32, other: i32) -> (i32, i32) {
+ (div_floor(this, other), mod_floor(this, other))
+}
+
+#[inline]
+fn div_floor(this: i32, other: i32) -> i32 {
+ match div_rem(this, other) {
+ (d, r) if (r > 0 && other < 0)
+ || (r < 0 && other > 0) => d - 1,
+ (d, _) => d,
+ }
+}
+
+#[inline]
+fn mod_floor(this: i32, other: i32) -> i32 {
+ match this % other {
+ r if (r > 0 && other < 0)
+ || (r < 0 && other > 0) => r + other,
+ r => r,
+ }
+}
+
+#[inline]
+fn div_rem(this: i32, other: i32) -> (i32, i32) {
+ (this / other, this % other)
+}
+
+#[inline]
+fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
+ (div_floor_64(this, other), mod_floor_64(this, other))
+}
+
+#[inline]
+fn div_floor_64(this: i64, other: i64) -> i64 {
+ match div_rem_64(this, other) {
+ (d, r) if (r > 0 && other < 0)
+ || (r < 0 && other > 0) => d - 1,
+ (d, _) => d,
+ }
+}
+
+#[inline]
+fn mod_floor_64(this: i64, other: i64) -> i64 {
+ match this % other {
+ r if (r > 0 && other < 0)
+ || (r < 0 && other > 0) => r + other,
+ r => r,
+ }
+}
+
+#[inline]
+fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
+ (this / other, this % other)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{Duration, MIN_DAYS, MAX_DAYS, MIN, MAX};
+ use {i32, i64};
+ use num::{Zero, CheckedAdd, CheckedSub};
+ use option::{Some, None};
+ use to_string::ToString;
+
+ #[test]
+ fn test_duration() {
+ let d: Duration = Zero::zero();
+ assert_eq!(d, Zero::zero());
+ assert!(Duration::seconds(1) != Zero::zero());
+ assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3));
+ assert_eq!(Duration::seconds(86399) + Duration::seconds(4),
+ Duration::days(1) + Duration::seconds(3));
+ assert_eq!(Duration::days(10) - Duration::seconds(1000), Duration::seconds(863000));
+ assert_eq!(Duration::days(10) - Duration::seconds(1000000), Duration::seconds(-136000));
+ assert_eq!(Duration::days(2) + Duration::seconds(86399) + Duration::nanoseconds(1234567890),
+ Duration::days(3) + Duration::nanoseconds(234567890));
+ assert_eq!(-Duration::days(3), Duration::days(-3));
+ assert_eq!(-(Duration::days(3) + Duration::seconds(70)),
+ Duration::days(-4) + Duration::seconds(86400-70));
+ }
+
+ #[test]
+ fn test_duration_num_days() {
+ let d: Duration = Zero::zero();
+ assert_eq!(d.num_days(), 0);
+ assert_eq!(Duration::days(1).num_days(), 1);
+ assert_eq!(Duration::days(-1).num_days(), -1);
+ assert_eq!(Duration::seconds(86399).num_days(), 0);
+ assert_eq!(Duration::seconds(86401).num_days(), 1);
+ assert_eq!(Duration::seconds(-86399).num_days(), 0);
+ assert_eq!(Duration::seconds(-86401).num_days(), -1);
+ assert_eq!(Duration::days(i32::MAX).num_days(), i32::MAX);
+ assert_eq!(Duration::days(i32::MIN).num_days(), i32::MIN);
+ assert_eq!(MAX.num_days(), MAX_DAYS);
+ assert_eq!(MIN.num_days(), MIN_DAYS);
+ }
+
+ #[test]
+ fn test_duration_num_seconds() {
+ let d: Duration = Zero::zero();
+ assert_eq!(d.num_seconds(), 0);
+ assert_eq!(Duration::seconds(1).num_seconds(), 1);
+ assert_eq!(Duration::seconds(-1).num_seconds(), -1);
+ assert_eq!(Duration::milliseconds(999).num_seconds(), 0);
+ assert_eq!(Duration::milliseconds(1001).num_seconds(), 1);
+ assert_eq!(Duration::milliseconds(-999).num_seconds(), 0);
+ assert_eq!(Duration::milliseconds(-1001).num_seconds(), -1);
+ assert_eq!(Duration::seconds(i32::MAX).num_seconds(), i32::MAX as i64);
+ assert_eq!(Duration::seconds(i32::MIN).num_seconds(), i32::MIN as i64);
+ assert_eq!(MAX.num_seconds(), (MAX_DAYS as i64 + 1) * 86400 - 1);
+ assert_eq!(MIN.num_seconds(), MIN_DAYS as i64 * 86400);
+ }
+
+ #[test]
+ fn test_duration_num_milliseconds() {
+ let d: Duration = Zero::zero();
+ assert_eq!(d.num_milliseconds(), 0);
+ assert_eq!(Duration::milliseconds(1).num_milliseconds(), 1);
+ assert_eq!(Duration::milliseconds(-1).num_milliseconds(), -1);
+ assert_eq!(Duration::microseconds(999).num_milliseconds(), 0);
+ assert_eq!(Duration::microseconds(1001).num_milliseconds(), 1);
+ assert_eq!(Duration::microseconds(-999).num_milliseconds(), 0);
+ assert_eq!(Duration::microseconds(-1001).num_milliseconds(), -1);
+ assert_eq!(Duration::milliseconds(i32::MAX).num_milliseconds(), i32::MAX as i64);
+ assert_eq!(Duration::milliseconds(i32::MIN).num_milliseconds(), i32::MIN as i64);
+ assert_eq!(MAX.num_milliseconds(), (MAX_DAYS as i64 + 1) * 86400_000 - 1);
+ assert_eq!(MIN.num_milliseconds(), MIN_DAYS as i64 * 86400_000);
+ }
+
+ #[test]
+ fn test_duration_num_microseconds() {
+ let d: Duration = Zero::zero();
+ assert_eq!(d.num_microseconds(), Some(0));
+ assert_eq!(Duration::microseconds(1).num_microseconds(), Some(1));
+ assert_eq!(Duration::microseconds(-1).num_microseconds(), Some(-1));
+ assert_eq!(Duration::nanoseconds(999).num_microseconds(), Some(0));
+ assert_eq!(Duration::nanoseconds(1001).num_microseconds(), Some(1));
+ assert_eq!(Duration::nanoseconds(-999).num_microseconds(), Some(0));
+ assert_eq!(Duration::nanoseconds(-1001).num_microseconds(), Some(-1));
+ assert_eq!(Duration::microseconds(i32::MAX).num_microseconds(), Some(i32::MAX as i64));
+ assert_eq!(Duration::microseconds(i32::MIN).num_microseconds(), Some(i32::MIN as i64));
+ assert_eq!(MAX.num_microseconds(), None);
+ assert_eq!(MIN.num_microseconds(), None);
+
+ // overflow checks
+ static MICROS_PER_DAY: i64 = 86400_000_000;
+ assert_eq!(Duration::days((i64::MAX / MICROS_PER_DAY) as i32).num_microseconds(),
+ Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY));
+ assert_eq!(Duration::days((i64::MIN / MICROS_PER_DAY) as i32).num_microseconds(),
+ Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY));
+ assert_eq!(Duration::days((i64::MAX / MICROS_PER_DAY + 1) as i32).num_microseconds(), None);
+ assert_eq!(Duration::days((i64::MIN / MICROS_PER_DAY - 1) as i32).num_microseconds(), None);
+ }
+
+ #[test]
+ fn test_duration_num_nanoseconds() {
+ let d: Duration = Zero::zero();
+ assert_eq!(d.num_nanoseconds(), Some(0));
+ assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1));
+ assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1));
+ assert_eq!(Duration::nanoseconds(i32::MAX).num_nanoseconds(), Some(i32::MAX as i64));
+ assert_eq!(Duration::nanoseconds(i32::MIN).num_nanoseconds(), Some(i32::MIN as i64));
+ assert_eq!(MAX.num_nanoseconds(), None);
+ assert_eq!(MIN.num_nanoseconds(), None);
+
+ // overflow checks
+ static NANOS_PER_DAY: i64 = 86400_000_000_000;
+ assert_eq!(Duration::days((i64::MAX / NANOS_PER_DAY) as i32).num_nanoseconds(),
+ Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY));
+ assert_eq!(Duration::days((i64::MIN / NANOS_PER_DAY) as i32).num_nanoseconds(),
+ Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY));
+ assert_eq!(Duration::days((i64::MAX / NANOS_PER_DAY + 1) as i32).num_nanoseconds(), None);
+ assert_eq!(Duration::days((i64::MIN / NANOS_PER_DAY - 1) as i32).num_nanoseconds(), None);
+ }
+
+ #[test]
+ fn test_duration_checked_ops() {
+ assert_eq!(Duration::days(MAX_DAYS).checked_add(&Duration::seconds(86399)),
+ Some(Duration::days(MAX_DAYS - 1) + Duration::seconds(86400+86399)));
+ assert!(Duration::days(MAX_DAYS).checked_add(&Duration::seconds(86400)).is_none());
+
+ assert_eq!(Duration::days(MIN_DAYS).checked_sub(&Duration::seconds(0)),
+ Some(Duration::days(MIN_DAYS)));
+ assert!(Duration::days(MIN_DAYS).checked_sub(&Duration::seconds(1)).is_none());
+ }
+
+ #[test]
+ fn test_duration_mul() {
+ let d: Duration = Zero::zero();
+ assert_eq!(d * i32::MAX, d);
+ assert_eq!(d * i32::MIN, d);
+ assert_eq!(Duration::nanoseconds(1) * 0, Zero::zero());
+ assert_eq!(Duration::nanoseconds(1) * 1, Duration::nanoseconds(1));
+ assert_eq!(Duration::nanoseconds(1) * 1_000_000_000, Duration::seconds(1));
+ assert_eq!(Duration::nanoseconds(1) * -1_000_000_000, -Duration::seconds(1));
+ assert_eq!(-Duration::nanoseconds(1) * 1_000_000_000, -Duration::seconds(1));
+ assert_eq!(Duration::nanoseconds(30) * 333_333_333,
+ Duration::seconds(10) - Duration::nanoseconds(10));
+ assert_eq!((Duration::nanoseconds(1) + Duration::seconds(1) + Duration::days(1)) * 3,
+ Duration::nanoseconds(3) + Duration::seconds(3) + Duration::days(3));
+ }
+
+ #[test]
+ fn test_duration_div() {
+ let d: Duration = Zero::zero();
+ assert_eq!(d / i32::MAX, d);
+ assert_eq!(d / i32::MIN, d);
+ assert_eq!(Duration::nanoseconds(123_456_789) / 1, Duration::nanoseconds(123_456_789));
+ assert_eq!(Duration::nanoseconds(123_456_789) / -1, -Duration::nanoseconds(123_456_789));
+ assert_eq!(-Duration::nanoseconds(123_456_789) / -1, Duration::nanoseconds(123_456_789));
+ assert_eq!(-Duration::nanoseconds(123_456_789) / 1, -Duration::nanoseconds(123_456_789));
+ }
+
+ #[test]
+ fn test_duration_fmt() {
+ let d: Duration = Zero::zero();
+ assert_eq!(d.to_string(), "PT0S".to_string());
+ assert_eq!(Duration::days(42).to_string(), "P42D".to_string());
+ assert_eq!(Duration::days(-42).to_string(), "P-42D".to_string());
+ assert_eq!(Duration::seconds(42).to_string(), "PT42S".to_string());
+ assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S".to_string());
+ assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S".to_string());
+ assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S".to_string());
+ assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(),
+ "P7DT6.543S".to_string());
+
+ // the format specifier should have no effect on `Duration`
+ assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)),
+ "P1DT2.345S".to_string());
+ }
+}
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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.
+
+//! Temporal quantification.
+
+pub use self::duration::Duration;
+
+pub mod duration;
//! }
//! ```
+#![allow(deprecated)]
+
use core::prelude::*;
use alloc::boxed::Box;
*/
#![allow(missing_doc)]
+#![allow(deprecated)]
#![deprecated = "This type is replaced by having a pair of channels. This type \
is not fully composable with other channels in terms of \
or possible semantics on a duplex stream. It will be removed \
//!
//! ```no_run
//! use std::io::timer::Timer;
+//! use std::time::Duration;
//!
//! let (tx, rx) = channel::<int>();
//! let mut timer = Timer::new().unwrap();
-//! let timeout = timer.oneshot(10000);
+//! let timeout = timer.oneshot(Duration::seconds(10));
//!
//! loop {
//! select! {
//!
//! ```no_run
//! use std::io::timer::Timer;
+//! use std::time::Duration;
//!
//! let (tx, rx) = channel::<int>();
//! let mut timer = Timer::new().unwrap();
//!
//! loop {
-//! let timeout = timer.oneshot(5000);
+//! let timeout = timer.oneshot(Duration::seconds(5));
//!
//! select! {
//! val = rx.recv() => println!("Received {}", val),
pub fn as_str<'a>(&'a self) -> &'a str {
self.name.as_str()
}
+
+ pub fn encode_with_hygiene(&self) -> String {
+ format!("\x00name_{:u},ctxt_{:u}\x00",
+ self.name.uint(),
+ self.ctxt)
+ }
}
impl Show for Ident {
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
ExprLoop(P<Block>, Option<Ident>),
ExprMatch(Gc<Expr>, Vec<Arm>),
- ExprFnBlock(P<FnDecl>, P<Block>),
+ ExprFnBlock(CaptureClause, P<FnDecl>, P<Block>),
ExprProc(P<FnDecl>, P<Block>),
- ExprUnboxedFn(P<FnDecl>, P<Block>),
+ ExprUnboxedFn(CaptureClause, P<FnDecl>, P<Block>),
ExprBlock(P<Block>),
ExprAssign(Gc<Expr>, Gc<Expr>),
ExprParen(Gc<Expr>)
}
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub enum CaptureClause {
+ CaptureByValue,
+ CaptureByRef,
+}
+
/// When the main rust parser encounters a syntax-extension invocation, it
/// parses the arguments to the invocation as a token-tree. This is a very
/// loose structure, such that all sorts of different AST-fragments can
},
ast_map::NodeMethod(ref m) => method(&**m),
ast_map::NodeExpr(ref e) => match e.node {
- ast::ExprFnBlock(ref decl, ref block) =>
+ ast::ExprFnBlock(_, ref decl, ref block) =>
closure(ClosureParts::new(*decl, *block, e.id, e.span)),
ast::ExprProc(ref decl, ref block) =>
closure(ClosureParts::new(*decl, *block, e.id, e.span)),
impl FromStr for CrateId {
fn from_str(s: &str) -> Option<CrateId> {
- let pieces: Vec<&str> = s.splitn('#', 1).collect();
+ let pieces: Vec<&str> = s.splitn(1, '#').collect();
let path = pieces.get(0).to_string();
if path.as_slice().starts_with("/") || path.as_slice().ends_with("/") ||
}
let path_pieces: Vec<&str> = path.as_slice()
- .rsplitn('/', 1)
+ .rsplitn(1, '/')
.collect();
let inferred_name = *path_pieces.get(0);
(inferred_name.to_string(), None)
} else {
let hash_pieces: Vec<&str> = pieces.get(1)
- .splitn(':', 1)
+ .splitn(1, ':')
.collect();
let (hash_name, hash_version) = if hash_pieces.len() == 1 {
("", *hash_pieces.get(0))
fn lambda_fn_decl(&self, span: Span,
fn_decl: P<ast::FnDecl>, blk: P<ast::Block>) -> Gc<ast::Expr> {
- self.expr(span, ast::ExprFnBlock(fn_decl, blk))
+ self.expr(span, ast::ExprFnBlock(ast::CaptureByRef, fn_decl, blk))
}
fn lambda(&self, span: Span, ids: Vec<ast::Ident> , blk: P<ast::Block>) -> Gc<ast::Expr> {
let fn_decl = self.fn_decl(
ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(),
self.ty_infer(span));
- self.expr(span, ast::ExprFnBlock(fn_decl, blk))
+ self.expr(span, ast::ExprFnBlock(ast::CaptureByRef, fn_decl, blk))
}
fn lambda0(&self, span: Span, blk: P<ast::Block>) -> Gc<ast::Expr> {
self.lambda(span, Vec::new(), blk)
fld.cx.expr(e.span, ast::ExprForLoop(pat, head, body, opt_ident))
}
- ast::ExprFnBlock(fn_decl, block) => {
+ ast::ExprFnBlock(capture_clause, fn_decl, block) => {
let (rewritten_fn_decl, rewritten_block)
= expand_and_rename_fn_decl_and_block(&*fn_decl, block, fld);
- let new_node = ast::ExprFnBlock(rewritten_fn_decl, rewritten_block);
+ let new_node = ast::ExprFnBlock(capture_clause,
+ rewritten_fn_decl,
+ rewritten_block);
box(GC) ast::Expr{id:e.id, node: new_node, span: fld.new_span(e.span)}
}
fn to_source(&self) -> String;
}
+ // FIXME (Issue #16472): This should go away after ToToken impls
+ // are revised to go directly to token-trees.
+ trait ToSourceWithHygiene : ToSource {
+ // Takes a thing and generates a string containing rust code
+ // for it, encoding Idents as special byte sequences to
+ // maintain hygiene across serialization and deserialization.
+ fn to_source_with_hygiene(&self) -> String;
+ }
+
macro_rules! impl_to_source(
(Gc<$t:ty>, $pp:ident) => (
impl ToSource for Gc<$t> {
pprust::$pp(&**self)
}
}
+ impl ToSourceWithHygiene for Gc<$t> {
+ fn to_source_with_hygiene(&self) -> String {
+ pprust::with_hygiene::$pp(&**self)
+ }
+ }
);
($t:ty, $pp:ident) => (
impl ToSource for $t {
pprust::$pp(self)
}
}
+ impl ToSourceWithHygiene for $t {
+ fn to_source_with_hygiene(&self) -> String {
+ pprust::with_hygiene::$pp(self)
+ }
+ }
);
)
.to_string()
}
+ fn slice_to_source_with_hygiene<'a, T: ToSourceWithHygiene>(
+ sep: &'static str, xs: &'a [T]) -> String {
+ xs.iter()
+ .map(|i| i.to_source_with_hygiene())
+ .collect::<Vec<String>>()
+ .connect(sep)
+ .to_string()
+ }
+
macro_rules! impl_to_source_slice(
($t:ty, $sep:expr) => (
impl<'a> ToSource for &'a [$t] {
slice_to_source($sep, *self)
}
}
+
+ impl<'a> ToSourceWithHygiene for &'a [$t] {
+ fn to_source_with_hygiene(&self) -> String {
+ slice_to_source_with_hygiene($sep, *self)
+ }
+ }
)
)
}
}
+ impl ToSourceWithHygiene for ast::Ident {
+ fn to_source_with_hygiene(&self) -> String {
+ self.encode_with_hygiene()
+ }
+ }
+
impl_to_source!(ast::Ty, ty_to_string)
impl_to_source!(ast::Block, block_to_string)
impl_to_source!(ast::Arg, arg_to_string)
pprust::attribute_to_string(&dummy_spanned(*self))
}
}
+ impl ToSourceWithHygiene for ast::Attribute_ {
+ fn to_source_with_hygiene(&self) -> String {
+ self.to_source()
+ }
+ }
impl<'a> ToSource for &'a str {
fn to_source(&self) -> String {
pprust::lit_to_string(&lit)
}
}
+ impl<'a> ToSourceWithHygiene for &'a str {
+ fn to_source_with_hygiene(&self) -> String {
+ self.to_source()
+ }
+ }
impl ToSource for () {
fn to_source(&self) -> String {
"()".to_string()
}
}
+ impl ToSourceWithHygiene for () {
+ fn to_source_with_hygiene(&self) -> String {
+ self.to_source()
+ }
+ }
impl ToSource for bool {
fn to_source(&self) -> String {
pprust::lit_to_string(&lit)
}
}
+ impl ToSourceWithHygiene for bool {
+ fn to_source_with_hygiene(&self) -> String {
+ self.to_source()
+ }
+ }
impl ToSource for char {
fn to_source(&self) -> String {
pprust::lit_to_string(&lit)
}
}
+ impl ToSourceWithHygiene for char {
+ fn to_source_with_hygiene(&self) -> String {
+ self.to_source()
+ }
+ }
macro_rules! impl_to_source_int(
(signed, $t:ty, $tag:ident) => (
pprust::lit_to_string(&dummy_spanned(lit))
}
}
+ impl ToSourceWithHygiene for $t {
+ fn to_source_with_hygiene(&self) -> String {
+ self.to_source()
+ }
+ }
);
(unsigned, $t:ty, $tag:ident) => (
impl ToSource for $t {
pprust::lit_to_string(&dummy_spanned(lit))
}
}
+ impl ToSourceWithHygiene for $t {
+ fn to_source_with_hygiene(&self) -> String {
+ self.to_source()
+ }
+ }
);
)
($t:ty) => (
impl ToTokens for $t {
fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- cx.parse_tts(self.to_source())
+ cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
}
}
)
($t:ty) => (
impl<'a> ToTokens for $t {
fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- cx.parse_tts(self.to_source())
+ cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
}
}
)
fn parse_item(&self, s: String) -> Gc<ast::Item>;
fn parse_expr(&self, s: String) -> Gc<ast::Expr>;
fn parse_stmt(&self, s: String) -> Gc<ast::Stmt>;
- fn parse_tts(&self, s: String) -> Vec<ast::TokenTree> ;
+ fn parse_tts(&self, s: String) -> Vec<ast::TokenTree>;
+ }
+
+ trait ExtParseUtilsWithHygiene {
+ // FIXME (Issue #16472): This should go away after ToToken impls
+ // are revised to go directly to token-trees.
+ fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree>;
}
impl<'a> ExtParseUtils for ExtCtxt<'a> {
}
}
+ impl<'a> ExtParseUtilsWithHygiene for ExtCtxt<'a> {
+
+ fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree> {
+ use parse::with_hygiene::parse_tts_from_source_str;
+ parse_tts_from_source_str("<quote expansion>".to_string(),
+ s,
+ self.cfg(),
+ self.parse_sess())
+ }
+
+ }
+
}
pub fn expand_quote_tokens(cx: &mut ExtCtxt,
ExprMatch(folder.fold_expr(expr),
arms.iter().map(|x| folder.fold_arm(x)).collect())
}
- ExprFnBlock(ref decl, ref body) => {
- ExprFnBlock(folder.fold_fn_decl(&**decl),
+ ExprFnBlock(capture_clause, ref decl, ref body) => {
+ ExprFnBlock(capture_clause,
+ folder.fold_fn_decl(&**decl),
folder.fold_block(body.clone()))
}
ExprProc(ref decl, ref body) => {
ExprProc(folder.fold_fn_decl(&**decl),
folder.fold_block(body.clone()))
}
- ExprUnboxedFn(ref decl, ref body) => {
- ExprUnboxedFn(folder.fold_fn_decl(&**decl),
+ ExprUnboxedFn(capture_clause, ref decl, ref body) => {
+ ExprUnboxedFn(capture_clause,
+ folder.fold_fn_decl(&**decl),
folder.fold_block(*body))
}
ExprBlock(ref blk) => ExprBlock(folder.fold_block(*blk)),
use parse::token::{str_to_ident};
use std::char;
+use std::fmt;
use std::mem::replace;
+use std::num;
use std::rc::Rc;
use std::str;
/* cached: */
pub peek_tok: token::Token,
pub peek_span: Span,
+
+ // FIXME (Issue #16472): This field should go away after ToToken impls
+ // are revised to go directly to token-trees.
+ /// Is \x00<name>,<ctxt>\x00 is interpreted as encoded ast::Ident?
+ read_embedded_ident: bool,
}
impl<'a> Reader for StringReader<'a> {
}
}
+// FIXME (Issue #16472): This function should go away after
+// ToToken impls are revised to go directly to token-trees.
+pub fn make_reader_with_embedded_idents<'b>(span_diagnostic: &'b SpanHandler,
+ filemap: Rc<codemap::FileMap>)
+ -> StringReader<'b> {
+ let mut sr = StringReader::new_raw(span_diagnostic, filemap);
+ sr.read_embedded_ident = true;
+ sr.advance_token();
+ sr
+}
+
impl<'a> StringReader<'a> {
/// For comments.rs, which hackily pokes into pos and curr
pub fn new_raw<'b>(span_diagnostic: &'b SpanHandler,
/* dummy values; not read */
peek_tok: token::EOF,
peek_span: codemap::DUMMY_SP,
+ read_embedded_ident: false,
};
sr.bump();
sr
})
}
+ // FIXME (Issue #16472): The scan_embedded_hygienic_ident function
+ // should go away after we revise the syntax::ext::quote::ToToken
+ // impls to go directly to token-trees instead of thing -> string
+ // -> token-trees. (The function is currently used to resolve
+ // Issues #15750 and #15962.)
+ //
+ // Since this function is only used for certain internal macros,
+ // and the functionality it provides is not exposed to end user
+ // programs, pnkfelix deliberately chose to write it in a way that
+ // favors rustc debugging effectiveness over runtime efficiency.
+
+ /// Scan through input of form \x00name_NNNNNN,ctxt_CCCCCCC\x00
+ /// where: `NNNNNN` is a string of characters forming an integer
+ /// (the name) and `CCCCCCC` is a string of characters forming an
+ /// integer (the ctxt), separate by a comma and delimited by a
+ /// `\x00` marker.
+ #[inline(never)]
+ fn scan_embedded_hygienic_ident(&mut self) -> ast::Ident {
+ fn bump_expecting_char<'a,D:fmt::Show>(r: &mut StringReader<'a>,
+ c: char,
+ described_c: D,
+ where: &str) {
+ match r.curr {
+ Some(r_c) if r_c == c => r.bump(),
+ Some(r_c) => fail!("expected {}, hit {}, {}", described_c, r_c, where),
+ None => fail!("expected {}, hit EOF, {}", described_c, where),
+ }
+ }
+
+ let where = "while scanning embedded hygienic ident";
+
+ // skip over the leading `\x00`
+ bump_expecting_char(self, '\x00', "nul-byte", where);
+
+ // skip over the "name_"
+ for c in "name_".chars() {
+ bump_expecting_char(self, c, c, where);
+ }
+
+ let start_bpos = self.last_pos;
+ let base = 10;
+
+ // find the integer representing the name
+ self.scan_digits(base);
+ let encoded_name : u32 = self.with_str_from(start_bpos, |s| {
+ num::from_str_radix(s, 10).unwrap_or_else(|| {
+ fail!("expected digits representing a name, got `{}`, {}, range [{},{}]",
+ s, where, start_bpos, self.last_pos);
+ })
+ });
+
+ // skip over the `,`
+ bump_expecting_char(self, ',', "comma", where);
+
+ // skip over the "ctxt_"
+ for c in "ctxt_".chars() {
+ bump_expecting_char(self, c, c, where);
+ }
+
+ // find the integer representing the ctxt
+ let start_bpos = self.last_pos;
+ self.scan_digits(base);
+ let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| {
+ num::from_str_radix(s, 10).unwrap_or_else(|| {
+ fail!("expected digits representing a ctxt, got `{}`, {}", s, where);
+ })
+ });
+
+ // skip over the `\x00`
+ bump_expecting_char(self, '\x00', "nul-byte", where);
+
+ ast::Ident { name: ast::Name(encoded_name),
+ ctxt: encoded_ctxt, }
+ }
+
/// Scan through any digits (base `radix`) or underscores, and return how
/// many digits there were.
fn scan_digits(&mut self, radix: uint) -> uint {
return self.scan_number(c.unwrap());
}
+ if self.read_embedded_ident {
+ match (c.unwrap(), self.nextch(), self.nextnextch()) {
+ ('\x00', Some('n'), Some('a')) => {
+ let ast_ident = self.scan_embedded_hygienic_ident();
+ let is_mod_name = self.curr_is(':') && self.nextch_is(':');
+ return token::IDENT(ast_ident, is_mod_name);
+ }
+ _ => {}
+ }
+ }
+
match c.expect("next_token_inner called at EOF") {
// One-byte tokens.
';' => { self.bump(); return token::SEMI; }
maybe_aborted(p.parse_stmt(attrs),p)
}
+// Note: keep in sync with `with_hygiene::parse_tts_from_source_str`
+// until #16472 is resolved.
pub fn parse_tts_from_source_str(name: String,
source: String,
cfg: ast::CrateConfig,
maybe_aborted(p.parse_all_token_trees(),p)
}
+// Note: keep in sync with `with_hygiene::new_parser_from_source_str`
+// until #16472 is resolved.
// Create a new parser from a source string
pub fn new_parser_from_source_str<'a>(sess: &'a ParseSess,
cfg: ast::CrateConfig,
p
}
+// Note: keep this in sync with `with_hygiene::filemap_to_parser` until
+// #16472 is resolved.
/// Given a filemap and config, return a parser
pub fn filemap_to_parser<'a>(sess: &'a ParseSess,
filemap: Rc<FileMap>,
sess.span_diagnostic.cm.new_filemap(path, source)
}
+// Note: keep this in sync with `with_hygiene::filemap_to_tts` (apart
+// from the StringReader constructor), until #16472 is resolved.
/// Given a filemap, produce a sequence of token-trees
pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
-> Vec<ast::TokenTree> {
Parser::new(sess, cfg, box trdr)
}
+// FIXME (Issue #16472): The `with_hygiene` mod should go away after
+// ToToken impls are revised to go directly to token-trees.
+pub mod with_hygiene {
+ use ast;
+ use codemap::FileMap;
+ use parse::parser::Parser;
+ use std::rc::Rc;
+ use super::ParseSess;
+ use super::{maybe_aborted, string_to_filemap, tts_to_parser};
+
+ // Note: keep this in sync with `super::parse_tts_from_source_str` until
+ // #16472 is resolved.
+ pub fn parse_tts_from_source_str(name: String,
+ source: String,
+ cfg: ast::CrateConfig,
+ sess: &ParseSess) -> Vec<ast::TokenTree> {
+ let mut p = new_parser_from_source_str(
+ sess,
+ cfg,
+ name,
+ source
+ );
+ p.quote_depth += 1u;
+ // right now this is re-creating the token trees from ... token trees.
+ maybe_aborted(p.parse_all_token_trees(),p)
+ }
+
+ // Note: keep this in sync with `super::new_parser_from_source_str` until
+ // #16472 is resolved.
+ // Create a new parser from a source string
+ fn new_parser_from_source_str<'a>(sess: &'a ParseSess,
+ cfg: ast::CrateConfig,
+ name: String,
+ source: String) -> Parser<'a> {
+ filemap_to_parser(sess, string_to_filemap(sess, source, name), cfg)
+ }
+
+ // Note: keep this in sync with `super::filemap_to_parserr` until
+ // #16472 is resolved.
+ /// Given a filemap and config, return a parser
+ fn filemap_to_parser<'a>(sess: &'a ParseSess,
+ filemap: Rc<FileMap>,
+ cfg: ast::CrateConfig) -> Parser<'a> {
+ tts_to_parser(sess, filemap_to_tts(sess, filemap), cfg)
+ }
+
+ // Note: keep this in sync with `super::filemap_to_tts` until
+ // #16472 is resolved.
+ /// Given a filemap, produce a sequence of token-trees
+ fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
+ -> Vec<ast::TokenTree> {
+ // it appears to me that the cfg doesn't matter here... indeed,
+ // parsing tt's probably shouldn't require a parser at all.
+ use make_reader = super::lexer::make_reader_with_embedded_idents;
+ let cfg = Vec::new();
+ let srdr = make_reader(&sess.span_diagnostic, filemap);
+ let mut p1 = Parser::new(sess, cfg, box srdr);
+ p1.parse_all_token_trees()
+ }
+}
+
/// Abort if necessary
pub fn maybe_aborted<T>(result: T, mut p: Parser) -> T {
p.abort_if_errors();
use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
use ast::{BiBitAnd, BiBitOr, BiBitXor, Block};
use ast::{BlockCheckMode, UnBox};
+use ast::{CaptureByRef, CaptureByValue, CaptureClause};
use ast::{Crate, CrateConfig, Decl, DeclItem};
use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf};
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
ExprBlock(blk));
},
token::BINOP(token::OR) | token::OROR => {
- return self.parse_lambda_expr();
+ return self.parse_lambda_expr(CaptureByValue);
},
// FIXME #13626: Should be able to stick in
// token::SELF_KEYWORD_NAME
hi = self.last_span.hi;
},
_ => {
+ if self.eat_keyword(keywords::Ref) {
+ return self.parse_lambda_expr(CaptureByRef);
+ }
if self.eat_keyword(keywords::Proc) {
let decl = self.parse_proc_decl();
let body = self.parse_expr();
}
// `|args| expr`
- pub fn parse_lambda_expr(&mut self) -> Gc<Expr> {
+ pub fn parse_lambda_expr(&mut self, capture_clause: CaptureClause)
+ -> Gc<Expr> {
let lo = self.span.lo;
let (decl, is_unboxed) = self.parse_fn_block_decl();
let body = self.parse_expr();
});
if is_unboxed {
- self.mk_expr(lo, body.span.hi, ExprUnboxedFn(decl, fakeblock))
+ self.mk_expr(lo,
+ body.span.hi,
+ ExprUnboxedFn(capture_clause, decl, fakeblock))
} else {
- self.mk_expr(lo, body.span.hi, ExprFnBlock(decl, fakeblock))
+ self.mk_expr(lo,
+ body.span.hi,
+ ExprFnBlock(capture_clause, decl, fakeblock))
}
}
}
},
_ => {
- if !enum_path.global && enum_path.segments.len() == 1 {
+ if !enum_path.global &&
+ enum_path.segments.len() == 1 &&
+ enum_path.segments
+ .get(0)
+ .lifetimes
+ .len() == 0 &&
+ enum_path.segments
+ .get(0)
+ .types
+ .len() == 0 {
// it could still be either an enum
// or an identifier pattern, resolve
// will sort it out:
literals: Option<Vec<comments::Literal> >,
cur_cmnt_and_lit: CurrentCommentAndLiteral,
boxes: Vec<pp::Breaks>,
- ann: &'a PpAnn
+ ann: &'a PpAnn,
+ encode_idents_with_hygiene: bool,
}
pub fn rust_printer(writer: Box<io::Writer>) -> State<'static> {
cur_lit: 0
},
boxes: Vec::new(),
- ann: ann
+ ann: ann,
+ encode_idents_with_hygiene: false,
}
}
cur_lit: 0
},
boxes: Vec::new(),
- ann: ann
+ ann: ann,
+ encode_idents_with_hygiene: false,
}
}
}
}
}
+// FIXME (Issue #16472): the thing_to_string_impls macro should go away
+// after we revise the syntax::ext::quote::ToToken impls to go directly
+// to token-trees instea of thing -> string -> token-trees.
+
+macro_rules! thing_to_string_impls {
+ ($to_string:ident) => {
+
pub fn ty_to_string(ty: &ast::Ty) -> String {
- to_string(|s| s.print_type(ty))
+ $to_string(|s| s.print_type(ty))
}
pub fn pat_to_string(pat: &ast::Pat) -> String {
- to_string(|s| s.print_pat(pat))
+ $to_string(|s| s.print_pat(pat))
}
pub fn arm_to_string(arm: &ast::Arm) -> String {
- to_string(|s| s.print_arm(arm))
+ $to_string(|s| s.print_arm(arm))
}
pub fn expr_to_string(e: &ast::Expr) -> String {
- to_string(|s| s.print_expr(e))
+ $to_string(|s| s.print_expr(e))
}
pub fn lifetime_to_string(e: &ast::Lifetime) -> String {
- to_string(|s| s.print_lifetime(e))
+ $to_string(|s| s.print_lifetime(e))
}
pub fn tt_to_string(tt: &ast::TokenTree) -> String {
- to_string(|s| s.print_tt(tt))
+ $to_string(|s| s.print_tt(tt))
}
pub fn tts_to_string(tts: &[ast::TokenTree]) -> String {
- to_string(|s| s.print_tts(tts))
+ $to_string(|s| s.print_tts(tts))
}
pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
- to_string(|s| s.print_stmt(stmt))
+ $to_string(|s| s.print_stmt(stmt))
}
pub fn item_to_string(i: &ast::Item) -> String {
- to_string(|s| s.print_item(i))
+ $to_string(|s| s.print_item(i))
}
pub fn generics_to_string(generics: &ast::Generics) -> String {
- to_string(|s| s.print_generics(generics))
+ $to_string(|s| s.print_generics(generics))
}
pub fn ty_method_to_string(p: &ast::TypeMethod) -> String {
- to_string(|s| s.print_ty_method(p))
+ $to_string(|s| s.print_ty_method(p))
}
pub fn method_to_string(p: &ast::Method) -> String {
- to_string(|s| s.print_method(p))
+ $to_string(|s| s.print_method(p))
}
pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
- to_string(|s| s.print_fn_block_args(p, false))
+ $to_string(|s| s.print_fn_block_args(p, false))
}
pub fn path_to_string(p: &ast::Path) -> String {
- to_string(|s| s.print_path(p, false))
+ $to_string(|s| s.print_path(p, false))
}
pub fn ident_to_string(id: &ast::Ident) -> String {
- to_string(|s| s.print_ident(*id))
+ $to_string(|s| s.print_ident(*id))
}
pub fn fun_to_string(decl: &ast::FnDecl, fn_style: ast::FnStyle, name: ast::Ident,
opt_explicit_self: Option<ast::ExplicitSelf_>,
generics: &ast::Generics) -> String {
- to_string(|s| {
+ $to_string(|s| {
try!(s.print_fn(decl, Some(fn_style), abi::Rust,
name, generics, opt_explicit_self, ast::Inherited));
try!(s.end()); // Close the head box
}
pub fn block_to_string(blk: &ast::Block) -> String {
- to_string(|s| {
+ $to_string(|s| {
// containing cbox, will be closed by print-block at }
try!(s.cbox(indent_unit));
// head-ibox, will be closed by print-block after {
}
pub fn meta_item_to_string(mi: &ast::MetaItem) -> String {
- to_string(|s| s.print_meta_item(mi))
+ $to_string(|s| s.print_meta_item(mi))
}
pub fn attribute_to_string(attr: &ast::Attribute) -> String {
- to_string(|s| s.print_attribute(attr))
+ $to_string(|s| s.print_attribute(attr))
}
pub fn lit_to_string(l: &ast::Lit) -> String {
- to_string(|s| s.print_literal(l))
+ $to_string(|s| s.print_literal(l))
}
pub fn explicit_self_to_string(explicit_self: ast::ExplicitSelf_) -> String {
- to_string(|s| s.print_explicit_self(explicit_self, ast::MutImmutable).map(|_| {}))
+ $to_string(|s| s.print_explicit_self(explicit_self, ast::MutImmutable).map(|_| {}))
}
pub fn variant_to_string(var: &ast::Variant) -> String {
- to_string(|s| s.print_variant(var))
+ $to_string(|s| s.print_variant(var))
}
pub fn arg_to_string(arg: &ast::Arg) -> String {
- to_string(|s| s.print_arg(arg))
+ $to_string(|s| s.print_arg(arg))
}
pub fn mac_to_string(arg: &ast::Mac) -> String {
- to_string(|s| s.print_mac(arg))
+ $to_string(|s| s.print_mac(arg))
+}
+
+} }
+
+thing_to_string_impls!(to_string)
+
+// FIXME (Issue #16472): the whole `with_hygiene` mod should go away
+// after we revise the syntax::ext::quote::ToToken impls to go directly
+// to token-trees instea of thing -> string -> token-trees.
+
+pub mod with_hygiene {
+ use abi;
+ use ast;
+ use std::io::IoResult;
+ use super::indent_unit;
+
+ // This function is the trick that all the rest of the routines
+ // hang on.
+ pub fn to_string_hyg(f: |&mut super::State| -> IoResult<()>) -> String {
+ super::to_string(|s| {
+ s.encode_idents_with_hygiene = true;
+ f(s)
+ })
+ }
+
+ thing_to_string_impls!(to_string_hyg)
}
pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> String {
}
try!(self.bclose_(expr.span, indent_unit));
}
- ast::ExprFnBlock(ref decl, ref body) => {
+ ast::ExprFnBlock(capture_clause, ref decl, ref body) => {
+ try!(self.print_capture_clause(capture_clause));
+
// in do/for blocks we don't want to show an empty
// argument list, but at this point we don't know which
// we are inside.
// empty box to satisfy the close.
try!(self.ibox(0));
}
- ast::ExprUnboxedFn(ref decl, ref body) => {
+ ast::ExprUnboxedFn(capture_clause, ref decl, ref body) => {
+ try!(self.print_capture_clause(capture_clause));
+
// in do/for blocks we don't want to show an empty
// argument list, but at this point we don't know which
// we are inside.
}
pub fn print_ident(&mut self, ident: ast::Ident) -> IoResult<()> {
- word(&mut self.s, token::get_ident(ident).get())
+ if self.encode_idents_with_hygiene {
+ let encoded = ident.encode_with_hygiene();
+ word(&mut self.s, encoded.as_slice())
+ } else {
+ word(&mut self.s, token::get_ident(ident).get())
+ }
}
pub fn print_name(&mut self, name: ast::Name) -> IoResult<()> {
self.maybe_print_comment(decl.output.span.lo)
}
+ pub fn print_capture_clause(&mut self, capture_clause: ast::CaptureClause)
+ -> IoResult<()> {
+ match capture_clause {
+ ast::CaptureByValue => Ok(()),
+ ast::CaptureByRef => self.word_space("ref"),
+ }
+ }
+
pub fn print_proc_args(&mut self, decl: &ast::FnDecl) -> IoResult<()> {
try!(word(&mut self.s, "proc"));
try!(word(&mut self.s, "("));
visitor.visit_arm(arm, env.clone())
}
}
- ExprFnBlock(ref function_declaration, ref body) => {
+ ExprFnBlock(_, ref function_declaration, ref body) => {
visitor.visit_fn(&FkFnBlock,
&**function_declaration,
&**body,
expression.id,
env.clone())
}
- ExprUnboxedFn(ref function_declaration, ref body) => {
+ ExprUnboxedFn(_, ref function_declaration, ref body) => {
visitor.visit_fn(&FkFnBlock,
&**function_declaration,
&**body,
use core::cmp::{Equal, Less, Greater};
use core::option::{Option, Some, None};
-use core::slice::ImmutableVector;
+use core::slice;
+use core::slice::ImmutableSlice;
use tables::normalization::{canonical_table, compatibility_table, composition_table};
fn bsearch_table<T>(c: char, r: &'static [(char, &'static [T])]) -> Option<&'static [T]> {
- match r.bsearch(|&(val, _)| {
+ match r.binary_search(|&(val, _)| {
if c == val { Equal }
else if val < c { Less }
else { Greater }
}) {
- Some(idx) => {
+ slice::Found(idx) => {
let (_, result) = r[idx];
Some(result)
}
- None => None
+ slice::NotFound(_) => None
}
}
match bsearch_table(a, composition_table) {
None => None,
Some(candidates) => {
- match candidates.bsearch(|&(val, _)| {
+ match candidates.binary_search(|&(val, _)| {
if b == val { Equal }
else if val < b { Less }
else { Greater }
}) {
- Some(idx) => {
+ slice::Found(idx) => {
let (_, result) = candidates[idx];
Some(result)
}
- None => None
+ slice::NotFound(_) => None
}
}
}
fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
use core::cmp::{Equal, Less, Greater};
- use core::slice::ImmutableVector;
- use core::option::None;
- r.bsearch(|&(lo,hi)| {
+ use core::slice::ImmutableSlice;
+ r.binary_search(|&(lo,hi)| {
if lo <= c && c <= hi { Equal }
else if hi < c { Less }
else { Greater }
- }) != None
+ }).found().is_some()
}
pub mod general_category {
fn bsearch_range_value_table(c: char, r: &'static [(char, char, u8)]) -> u8 {
- use core::option::{Some, None};
use core::cmp::{Equal, Less, Greater};
- use core::slice::ImmutableVector;
- match r.bsearch(|&(lo, hi, _)| {
+ use core::slice::ImmutableSlice;
+ use core::slice;
+ match r.binary_search(|&(lo, hi, _)| {
if lo <= c && c <= hi { Equal }
else if hi < c { Less }
else { Greater }
}) {
- Some(idx) => {
+ slice::Found(idx) => {
let (_, _, result) = r[idx];
result
}
- None => 0
+ slice::NotFound(_) => 0
}
}
pub mod conversions {
use core::cmp::{Equal, Less, Greater};
- use core::slice::ImmutableVector;
+ use core::slice::ImmutableSlice;
use core::tuple::Tuple2;
use core::option::{Option, Some, None};
+ use core::slice;
pub fn to_lower(c: char) -> char {
match bsearch_case_table(c, LuLl_table) {
}
fn bsearch_case_table(c: char, table: &'static [(char, char)]) -> Option<uint> {
- table.bsearch(|&(key, _)| {
+ match table.binary_search(|&(key, _)| {
if c == key { Equal }
else if key < c { Less }
else { Greater }
- })
+ }) {
+ slice::Found(i) => Some(i),
+ slice::NotFound(_) => None,
+ }
}
static LuLl_table: &'static [(char, char)] = &[
pub mod charwidth {
use core::option::{Option, Some, None};
- use core::slice::ImmutableVector;
+ use core::slice::ImmutableSlice;
+ use core::slice;
fn bsearch_range_value_table(c: char, is_cjk: bool, r: &'static [(char, char, u8, u8)]) -> u8 {
use core::cmp::{Equal, Less, Greater};
- match r.bsearch(|&(lo, hi, _, _)| {
+ match r.binary_search(|&(lo, hi, _, _)| {
if lo <= c && c <= hi { Equal }
else if hi < c { Less }
else { Greater }
}) {
- Some(idx) => {
+ slice::Found(idx) => {
let (_, _, r_ncjk, r_cjk) = r[idx];
if is_cjk { r_cjk } else { r_ncjk }
}
- None => 1
+ slice::NotFound(_) => 1
}
}
}
pub mod grapheme {
- use core::option::{Some, None};
- use core::slice::ImmutableVector;
+ use core::slice::ImmutableSlice;
+ use core::slice;
#[allow(non_camel_case_types)]
#[deriving(Clone)]
fn bsearch_range_value_table(c: char, r: &'static [(char, char, GraphemeCat)]) -> GraphemeCat {
use core::cmp::{Equal, Less, Greater};
- match r.bsearch(|&(lo, hi, _)| {
+ match r.binary_search(|&(lo, hi, _)| {
if lo <= c && c <= hi { Equal }
else if hi < c { Less }
else { Greater }
}) {
- Some(idx) => {
+ slice::Found(idx) => {
let (_, _, cat) = r[idx];
cat
}
- None => GC_Any
+ slice::NotFound(_) => GC_Any
}
}
#![crate_name = "url"]
#![deprecated="This is being removed. Use rust-url instead. http://servo.github.io/rust-url/"]
+#![allow(deprecated)]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
}
fn split_char_first(s: &str, c: char) -> (&str, &str) {
- let mut iter = s.splitn(c, 1);
+ let mut iter = s.splitn(1, c);
match (iter.next(), iter.next()) {
(Some(a), Some(b)) => (a, b),
#![crate_name = "uuid"]
#![deprecated = "This is now a cargo package located at: \
https://github.com/rust-lang/uuid"]
+#![allow(deprecated)]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_macro("make_a_1", expand_make_a_1);
+ reg.register_macro("forged_ident", expand_forged_ident);
reg.register_syntax_extension(
token::intern("into_foo"),
ItemModifier(expand_into_foo));
}
}
+fn expand_forged_ident(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult> {
+ use syntax::ext::quote::rt::*;
+
+ if !tts.is_empty() {
+ cx.span_fatal(sp, "forged_ident takes no arguments");
+ }
+
+ // Most of this is modelled after the expansion of the `quote_expr!`
+ // macro ...
+ let parse_sess = cx.parse_sess();
+ let cfg = cx.cfg();
+
+ // ... except this is where we inject a forged identifier,
+ // and deliberately do not call `cx.parse_tts_with_hygiene`
+ // (because we are testing that this will be *rejected*
+ // by the default parser).
+
+ let expr = {
+ let tt = cx.parse_tts("\x00name_2,ctxt_0\x00".to_string());
+ let mut parser = new_parser_from_tts(parse_sess, cfg, tt);
+ parser.parse_expr()
+ };
+ MacExpr::new(expr)
+}
+
pub fn foo() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:macro_crate_test.rs
+// ignore-stage1
+// ignore-android
+// error-pattern: unknown start of token: \x00
+
+// Issue #15750 and #15962 : this test is checking that the standard
+// parser rejects embedded idents. pnkfelix did not want to attempt
+// to make a test file that itself used the embedded ident input form,
+// since he worrid that would be difficult to work with in many text
+// editors, so instead he made a macro that expands into the embedded
+// ident form.
+
+#![feature(phase)]
+
+#[phase(plugin)]
+extern crate macro_crate_test;
+
+fn main() {
+ let x = 0;
+ assert_eq!(3, forged_ident!());
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo {
+ x: int,
+}
+
+pub fn main() {
+ let mut this = &mut Foo {
+ x: 1,
+ };
+ let r = || {
+ let p = &this.x;
+ &mut this.x; //~ ERROR cannot borrow
+ };
+ r()
+}
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Issue #16205.
+
+struct Foo {
+ a: [Box<int>, ..3],
+}
+
+fn main() {
+ let mut y = 1i;
+ let x = Some(&mut y);
+ for &a in x.iter() { //~ ERROR cannot move out
+ }
+
+ let f = Foo {
+ a: [box 3, box 4, box 5],
+ };
+ for &a in f.a.iter() { //~ ERROR cannot move out
+ }
+
+ let x = Some(box 1i);
+ for &a in x.iter() { //~ ERROR cannot move out
+ }
+}
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(warnings)]
+#![feature(intrinsics)]
+
+extern "rust-intrinsic" {
+ fn return_address() -> *const u8;
+}
+
+unsafe fn f() {
+ let _ = return_address();
+ //~^ ERROR invalid use of `return_address` intrinsic: function does not use out pointer
+}
+
+unsafe fn g() -> int {
+ let _ = return_address();
+ //~^ ERROR invalid use of `return_address` intrinsic: function does not use out pointer
+ 0
+}
+
+fn main() {}
+
+
pub struct LockedTupleStruct(int);
fn test() {
- // None of the following should generate errors, because
- // stability attributes now have meaning only *across* crates,
- // not within a single crate.
+ // Only the deprecated cases of the following should generate
+ // errors, because other stability attributes now have meaning
+ // only *across* crates, not within a single crate.
let foo = MethodTester;
- deprecated();
- foo.method_deprecated();
- foo.trait_deprecated();
+ deprecated(); //~ ERROR use of deprecated item
+ foo.method_deprecated(); //~ ERROR use of deprecated item
+ foo.trait_deprecated(); //~ ERROR use of deprecated item
- deprecated_text();
- foo.method_deprecated_text();
- foo.trait_deprecated_text();
+ deprecated_text(); //~ ERROR use of deprecated item: text
+ foo.method_deprecated_text(); //~ ERROR use of deprecated item: text
+ foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
experimental();
foo.method_experimental();
foo.method_locked_text();
foo.trait_locked_text();
-
- let _ = DeprecatedStruct { i: 0 };
+ let _ = DeprecatedStruct { i: 0 }; //~ ERROR use of deprecated item
let _ = ExperimentalStruct { i: 0 };
let _ = UnstableStruct { i: 0 };
let _ = UnmarkedStruct { i: 0 };
let _ = FrozenStruct { i: 0 };
let _ = LockedStruct { i: 0 };
- let _ = DeprecatedUnitStruct;
+ let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item
let _ = ExperimentalUnitStruct;
let _ = UnstableUnitStruct;
let _ = UnmarkedUnitStruct;
let _ = FrozenUnitStruct;
let _ = LockedUnitStruct;
- let _ = DeprecatedVariant;
+ let _ = DeprecatedVariant; //~ ERROR use of deprecated item
let _ = ExperimentalVariant;
let _ = UnstableVariant;
let _ = UnmarkedVariant;
let _ = FrozenVariant;
let _ = LockedVariant;
- let _ = DeprecatedTupleStruct (1);
+ let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item
let _ = ExperimentalTupleStruct (1);
let _ = UnstableTupleStruct (1);
let _ = UnmarkedTupleStruct (1);
}
fn test_method_param<F: Trait>(foo: F) {
- foo.trait_deprecated();
- foo.trait_deprecated_text();
+ foo.trait_deprecated(); //~ ERROR use of deprecated item
+ foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
foo.trait_experimental();
foo.trait_experimental_text();
foo.trait_unstable();
}
fn test_method_object(foo: &Trait) {
- foo.trait_deprecated();
- foo.trait_deprecated_text();
+ foo.trait_deprecated(); //~ ERROR use of deprecated item
+ foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
foo.trait_experimental();
foo.trait_experimental_text();
foo.trait_unstable();
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ match Some("foo") {
+ None::<int> => {} //~ ERROR mismatched types
+ Some(_) => {}
+ }
+}
+
--- /dev/null
+-include ../tools.mk
+
+# Issue #15750, #15962 : This test ensures that our special embedded
+# ident syntax hack is not treated as legitimate input by the lexer in
+# normal mode.
+#
+# It is modelled after the `unicode-input/` test, since we need to
+# create files with syntax that can trip up normal text editting tools
+# (namely text with embedded nul-bytes).
+
+# This test attempts to run rustc itself from the compiled binary; but
+# that means that you need to set the LD_LIBRARY_PATH for rustc itself
+# while running create_and_compile, and that won't work for stage1.
+
+# FIXME ignore windows
+ifndef IS_WINDOWS
+ifeq ($(RUST_BUILD_STAGE),1)
+DOTEST=
+else
+DOTEST=dotest
+endif
+endif
+
+all: $(DOTEST)
+
+dotest:
+ $(RUSTC) create_and_compile.rs
+ $(call RUN,create_and_compile) "$(RUSTC)" "$(TMPDIR)"
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::os;
+use std::io::{File, Command};
+
+// creates broken.rs, which has the Ident \x00name_0,ctxt_0\x00
+// embedded within it, and then attempts to compile broken.rs with the
+// provided `rustc`
+
+fn main() {
+ let args = os::args();
+ let rustc = args[1].as_slice();
+ let tmpdir = Path::new(args[2].as_slice());
+
+ let main_file = tmpdir.join("broken.rs");
+ let _ = File::create(&main_file).unwrap()
+ .write_str("pub fn main() {
+ let \x00name_0,ctxt_0\x00 = 3i;
+ println!(\"{}\", \x00name_0,ctxt_0\x00);
+ }");
+
+ // rustc is passed to us with --out-dir and -L etc., so we
+ // can't exec it directly
+ let result = Command::new("sh")
+ .arg("-c")
+ .arg(format!("{} {}",
+ rustc,
+ main_file.as_str()
+ .unwrap()).as_slice())
+ .output().unwrap();
+ let err = String::from_utf8_lossy(result.error.as_slice());
+
+ // positive test so that this test will be updated when the
+ // compiler changes.
+ assert!(err.as_slice().contains("unknown start of token"))
+}
mkdir -p $(A1) $(A2) $(A3)
$(RUSTC) --crate-type=rlib crateA1.rs
mv $(TMPDIR)/$(call RLIB_GLOB,crateA) $(A1)
- $(RUSTC) --crate-type=rlib -L$(A1) crateB.rs
+ $(RUSTC) --crate-type=rlib -L $(A1) crateB.rs
$(RUSTC) --crate-type=rlib crateA2.rs
mv $(TMPDIR)/$(call RLIB_GLOB,crateA) $(A2)
$(RUSTC) --crate-type=rlib crateA3.rs
mv $(TMPDIR)/$(call RLIB_GLOB,crateA) $(A3)
# Ensure crateC fails to compile since A1 is "missing" and A2/A3 hashes do not match
- $(RUSTC) -L$(A2) -L$(A3) crateC.rs >$(LOG) 2>&1 || true
+ $(RUSTC) -L $(A2) -L $(A3) crateC.rs >$(LOG) 2>&1 || true
grep "error: found possibly newer version of crate \`crateA\` which \`crateB\` depends on" $(LOG)
grep "note: perhaps this crate needs to be recompiled?" $(LOG)
grep "note: crate \`crateA\` path #1:" $(LOG)
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn each<T>(x: &[T], f: |&T|) {
+ for val in x.iter() {
+ f(val)
+ }
+}
+
+fn main() {
+ let mut sum = 0u;
+ let elems = [ 1u, 2, 3, 4, 5 ];
+ each(elems, ref |val| sum += *val);
+ assert_eq!(sum, 15);
+}
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-test
+//
+// This is ignored because it depends on #16122.
+
+#![feature(overloaded_calls, unboxed_closures)]
+
+fn each<'a,T,F:|&mut: &'a T|>(x: &'a [T], mut f: F) {
+ for val in x.iter() {
+ f(val)
+ }
+}
+
+fn main() {
+ let mut sum = 0u;
+ let elems = [ 1u, 2, 3, 4, 5 ];
+ each(elems, ref |&mut: val: &uint| sum += *val);
+ assert_eq!(sum, 15);
+}
+
extern crate rustuv;
use std::io::{Process, Command};
+use std::time::Duration;
macro_rules! succeed( ($e:expr) => (
match $e { Ok(..) => {}, Err(e) => fail!("failure: {}", e) }
// Don't let this test time out, this should be quick
let (tx, rx1) = channel();
let mut t = timer::Timer::new().unwrap();
- let rx2 = t.oneshot(1000);
+ let rx2 = t.oneshot(Duration::milliseconds(1000));
spawn(proc() {
select! {
() = rx2.recv() => unsafe { libc::exit(1) },
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn main() {
+ use std::f64;
+ let x = "NaN".to_string();
+ assert_eq!(format!("{}", f64::NAN), x);
+ assert_eq!(format!("{:e}", f64::NAN), x);
+ assert_eq!(format!("{:E}", f64::NAN), x);
+}
+
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(intrinsics)]
+
+use std::ptr;
+
+struct Point {
+ x: f32,
+ y: f32,
+ z: f32,
+}
+
+extern "rust-intrinsic" {
+ fn return_address() -> *const u8;
+}
+
+fn f(result: &mut uint) -> Point {
+ unsafe {
+ *result = return_address() as uint;
+ Point {
+ x: 1.0,
+ y: 2.0,
+ z: 3.0,
+ }
+ }
+
+}
+
+fn main() {
+ let mut intrinsic_reported_address = 0;
+ let pt = f(&mut intrinsic_reported_address);
+ let actual_address = &pt as *const Point as uint;
+ assert_eq!(intrinsic_reported_address, actual_address);
+}
+
extern crate green;
extern crate rustuv;
+use std::time::Duration;
+
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
green::start(argc, argv, rustuv::event_loop, main)
fn customtask() {
let mut timer = std::io::timer::Timer::new().unwrap();
- let periodic = timer.periodic(10);
+ let periodic = timer.periodic(Duration::milliseconds(10));
periodic.recv();
}
extern crate native;
use std::io::timer;
+use std::time::Duration;
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
}
fn main() {
- timer::sleep(250);
+ timer::sleep(Duration::milliseconds(250));
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+#[deriving(PartialEq, Show)]
+struct Bar {
+ x: int
+}
+impl Drop for Bar {
+ fn drop(&mut self) {
+ assert_eq!(self.x, 22);
+ }
+}
+
+#[deriving(PartialEq, Show)]
+struct Foo {
+ x: Bar,
+ a: int
+}
+
+fn foo() -> Result<Foo, int> {
+ return Ok(Foo {
+ x: Bar { x: 22 },
+ a: return Err(32)
+ });
+}
+
+fn baz() -> Result<Foo, int> {
+ Ok(Foo {
+ x: Bar { x: 22 },
+ a: return Err(32)
+ })
+}
+
+// explicit immediate return
+fn aa() -> int {
+ return 3;
+}
+
+// implicit immediate return
+fn bb() -> int {
+ 3
+}
+
+// implicit outptr return
+fn cc() -> Result<int, int> {
+ Ok(3)
+}
+
+// explicit outptr return
+fn dd() -> Result<int, int> {
+ return Ok(3);
+}
+
+trait A {
+ fn aaa(self) -> int {
+ 3
+ }
+ fn bbb(self) -> int {
+ return 3;
+ }
+ fn ccc(self) -> Result<int, int> {
+ Ok(3)
+ }
+ fn ddd(self) -> Result<int, int> {
+ return Ok(3);
+ }
+}
+
+impl A for int {}
+
+fn main() {
+ assert_eq!(foo(), Err(32));
+ assert_eq!(baz(), Err(32));
+
+ assert_eq!(aa(), 3);
+ assert_eq!(bb(), 3);
+ assert_eq!(cc().unwrap(), 3);
+ assert_eq!(dd().unwrap(), 3);
+
+ let i = box 32i as Box<A>;
+ assert_eq!(i.aaa(), 3);
+ let i = box 32i as Box<A>;
+ assert_eq!(i.bbb(), 3);
+ let i = box 32i as Box<A>;
+ assert_eq!(i.ccc().unwrap(), 3);
+ let i = box 32i as Box<A>;
+ assert_eq!(i.ddd().unwrap(), 3);
+}
use std::comm;
use std::io::timer::Timer;
+use std::time::Duration;
pub fn main() {
let (tx, rx) = channel();
spawn(proc (){
let mut timer = Timer::new().unwrap();
- timer.sleep(10);
+ timer.sleep(Duration::milliseconds(10));
tx.send(());
});
loop {
use std::io::net::tcp::*;
use std::io::test::*;
use std::io;
+ use std::time::Duration;
fn f() $b
let mut v = Vec::new();
for _ in range(0u, 10000) {
- match TcpStream::connect_timeout(addr, 100) {
+ match TcpStream::connect_timeout(addr, Duration::milliseconds(100)) {
Ok(e) => v.push(e),
Err(ref e) if e.kind == io::TimedOut => return,
Err(e) => fail!("other error: {}", e),
let port = addr.port;
let _l = TcpListener::bind(host.as_slice(), port).unwrap().listen();
- assert!(TcpStream::connect_timeout(addr, 1000).is_ok());
+ assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(1000)).is_ok());
})
iotest!(fn timeout_error() {
let addr = next_test_ip4();
- assert!(TcpStream::connect_timeout(addr, 1000).is_err());
+ assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(1000)).is_err());
})
+
+ iotest!(fn connect_timeout_zero() {
+ let addr = next_test_ip4();
+ assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(0)).is_err());
+ })
+
+ iotest!(fn connect_timeout_negative() {
+ let addr = next_test_ip4();
+ assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(-1)).is_err());
+ })
+
use std::io::net::tcp::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::task::TaskBuilder;
+use std::time::Duration;
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
// This test has a chance to time out, try to not let it time out
spawn(proc() {
use std::io::timer;
- timer::sleep(30 * 1000);
+ timer::sleep(Duration::milliseconds(30 * 1000));
println!("timed out!");
unsafe { libc::exit(1) }
});