Merge remote-tracking branch 'original/incoming' into incoming

Conflicts:
	src/libstd/json.rs
	src/libstd/sort.rs
This commit is contained in:
Simon BD 2012-10-03 21:47:09 -05:00
commit efcd2385ea
378 changed files with 11486 additions and 8500 deletions

View file

@ -17,6 +17,7 @@ Ben Striegel <ben.striegel@gmail.com>
Benjamin Herr <ben@0x539.de>
Benjamin Jackman <ben@jackman.biz>
Benjamin Kircher <benjamin.kircher@gmail.com>
Benjamin Peterson <benjamin@python.org>
Brendan Eich <brendan@mozilla.org>
Brian Anderson <banderson@mozilla.com>
Brian J. Burg <burg@cs.washington.edu>
@ -66,6 +67,7 @@ Kevin Atkinson <kevina@cs.utah.edu>
Kevin Cantu <me@kevincantu.org>
Lennart Kudling
Lindsey Kuper <lindsey@rockstargirl.org>
Luca Bruno <lucab@debian.org>
Magnus Auvinen <magnus.auvinen@gmail.com>
Margaret Meyerhofer <mmeyerho@andrew.cmu.edu>
Marijn Haverbeke <marijnh@gmail.com>
@ -76,6 +78,7 @@ Michael Bebenita <mbebenita@mozilla.com>
Michael Sullivan <sully@msully.net>
Niko Matsakis <niko@alum.mit.edu>
Or Brostovski <tohava@gmail.com>
Orphée Lafond-Lummis <o@orftz.com>
Patrick Walton <pwalton@mozilla.com>
Patrik Kårlin <patrik.karlin@gmail.com>
Paul Stansifer <paul.stansifer@gmail.com>

View file

@ -357,6 +357,15 @@ EXTRAFLAGS_STAGE$(1) = $$(RUSTFLAGS_STAGE$(1))
CFGFLAG$(1)_T_$(2)_H_$(3) = stage$(1)
# Pass --cfg stage0 only for the build->host part of stage0;
# if you're building a cross config, the host->* parts are
# effectively stage1, since it uses the just-built stage0.
ifeq ($(1),0)
ifneq ($(strip $(CFG_HOST_TRIPLE)),$(strip $(3)))
CFGFLAG$(1)_T_$(2)_H_$(3) = stage1
endif
endif
STAGE$(1)_T_$(2)_H_$(3) := \
$$(Q)$$(call CFG_RUN_TARG,$(1), \
$$(CFG_VALGRIND_COMPILE$(1)) \
@ -528,8 +537,8 @@ endif
ifneq ($(findstring install,$(MAKECMDGOALS)),)
ifdef DESTDIR
CFG_INFO := $(info cfg: setting CFG_PREFIX via DESTDIR, $(DESTDIR))
CFG_PREFIX:=$(DESTDIR)
CFG_INFO := $(info cfg: setting CFG_PREFIX via DESTDIR, $(DESTDIR)/$(CFG_PREFIX))
CFG_PREFIX:=$(DESTDIR)/$(CFG_PREFIX)
export CFG_PREFIX
endif

View file

@ -1,5 +1,5 @@
Version 0.4 (September 2012)
----------------------------
Version 0.4 (October 2012)
--------------------------
* ~1500 changes, numerous bugfixes
@ -8,13 +8,14 @@ Version 0.4 (September 2012)
* Keyword removal: 'again', 'import', 'check', 'new', 'owned', 'send',
'of', 'with', 'to', 'class'.
* Classes are replaced with simpler structs
* Method self types
* Explicit method self types
* `ret` became `return` and `alt` became `match`
* `import` is now `use`; `use is now `extern mod`
* `extern mod { ... }` is now `extern { ... }`
* `use mod` is the recommended way to import modules
* `pub` and `priv` replace deprecated export lists
* The syntax of `match` pattern arms now uses fat arrow (=>)
* `main` no longer accepts an args vector; use `os::args` instead
* Semantics
* Trait implementations are now coherent, ala Haskell typeclasses
@ -25,15 +26,13 @@ Version 0.4 (September 2012)
* Typestate was removed
* Resolution rewritten to be more reliable
* Support for 'dual-mode' data structures (freezing and thawing)
* Last-use analysis is only used for warnings now. Moves must be explicit
for lvalues (TODO: confirm)
* Libraries
* Most binary operators can now be overloaded via the traits in
`core::ops'
* `std::net::url` for representing URLs
* Sendable hash maps in `core::send_map`
* `core::task' gained a (currently very unsafe) task-local storage API
* `core::task' gained a (currently unsafe) task-local storage API
* Concurrency
* An efficient new intertask communication primitive called the pipe,
@ -52,8 +51,7 @@ Version 0.4 (September 2012)
* Extensive architectural improvements to rustc
* Begun a transition away from buggy C++-based reflection (shape) code to
Rust-based (visitor) code
* Hash functions improved across the codebase (TODO: need details)
* New lint checks (TODO: which?)
* All hash functions and tables converted to secure, randomized SipHash
Version 0.3 (July 2012)
------------------------

View file

@ -1,9 +1,11 @@
body {
padding: 1em;
margin: 0;
margin-bottom: 4em;
font-family: "Helvetica Neue", Helvetica, sans-serif;
background-color: white;
color: black;
line-height: 1.6em;
}
body {
@ -12,12 +14,16 @@ body {
}
h1 {
font-size: 22pt;
font-size: 20pt;
margin-top: 2em;
border-bottom: 2px solid silver;
border-bottom: 1px solid silver;
line-height: 1.6em;
}
h2 { font-size: 17pt; }
h3 { font-size: 14pt; }
h2 {
font-size: 15pt;
margin-top: 2em;
}
h3 { font-size: 13pt; }
pre {
margin: 1.1em 0;
@ -27,7 +33,7 @@ pre {
a, a:visited, a:link {
text-decoration: none;
color: #00438a;
color: rgb(0, 105, 214);
}
h1 a:link, h1 a:visited, h2 a:link, h2 a:visited,
@ -54,20 +60,12 @@ h3 a:link, h3 a:visited { color: black; }
.cm-s-default span.cm-tag {color: #170;}
.cm-s-default span.cm-attribute {color: #00c;}
h1.title {
background-image: url('http://www.rust-lang.org/logos/rust-logo-32x32-blk.png');
background-repeat: no-repeat;
background-position: right;
}
#versioninfo {
position: fixed;
bottom: 0px;
right: 0px;
background-color: white;
border-left: solid 1px black;
border-top: solid 1px black;
padding: 0.5em;
}
@ -99,3 +97,8 @@ td {
#TOC ul ul {
display: none;
}
#TOC ul {
list-style: none;
padding-left: 0px;
}

View file

@ -15,17 +15,16 @@ provides three kinds of material:
This document does not serve as a tutorial introduction to the
language. Background familiarity with the language is assumed. A separate
tutorial document is available at <http://doc.rust-lang.org/doc/tutorial.html>
to help acquire such background familiarity.
[tutorial] document is available to help acquire such background familiarity.
This document also does not serve as a reference to the core or standard
This document also does not serve as a reference to the [core] or [standard]
libraries included in the language distribution. Those libraries are
documented separately by extracting documentation attributes from their
source code. Formatted documentation can be found at the following
locations:
source code.
- Core library: <http://doc.rust-lang.org/doc/core>
- Standard library: <http://doc.rust-lang.org/doc/std>
[tutorial]: tutorial.html
[core]: core/index.html
[standard]: std/index.html
## Disclaimer
@ -42,14 +41,17 @@ If you have suggestions to make, please try to focus them on *reductions* to
the language: possible features that can be combined or omitted. We aim to
keep the size and complexity of the language under control.
**Note on grammar:** The grammar for Rust given in this document is rough and
very incomplete; only a modest number of sections have accompanying grammar
rules. Formalizing the grammar accepted by the Rust parser is ongoing work,
but future versions of this document will contain a complete
grammar. Moreover, we hope that this grammar will be extracted and verified
as LL(1) by an automated grammar-analysis tool, and further tested against the
Rust sources. Preliminary versions of this automation exist, but are not yet
complete.
> **Note:** This manual is very out of date. The best source of Rust
> documentation is currently the tutorial.
> **Note:** The grammar for Rust given in this document is rough and
> very incomplete; only a modest number of sections have accompanying grammar
> rules. Formalizing the grammar accepted by the Rust parser is ongoing work,
> but future versions of this document will contain a complete
> grammar. Moreover, we hope that this grammar will be extracted and verified
> as LL(1) by an automated grammar-analysis tool, and further tested against the
> Rust sources. Preliminary versions of this automation exist, but are not yet
> complete.
# Notation
@ -118,19 +120,16 @@ production. See [tokens](#tokens) for more information.
## Input format
Rust input is interpreted as a sequence of Unicode codepoints encoded in
UTF-8. No normalization is performed during input processing. Most Rust
grammar rules are defined in terms of printable ASCII-range codepoints, but
a small number are defined in terms of Unicode properties or explicit
codepoint lists. ^[Surrogate definitions for the special Unicode productions
are provided to the grammar verifier, restricted to ASCII range, when
verifying the grammar in this document.]
Rust input is interpreted as a sequence of Unicode codepoints encoded in UTF-8,
normalized to Unicode normalization form NFKC.
Most Rust grammar rules are defined in terms of printable ASCII-range codepoints,
but a small number are defined in terms of Unicode properties or explicit codepoint lists.
^[Substitute definitions for the special Unicode productions are provided to the grammar verifier, restricted to ASCII range, when verifying the grammar in this document.]
## Special Unicode Productions
The following productions in the Rust grammar are defined in terms of
Unicode properties: `ident`, `non_null`, `non_star`, `non_eol`, `non_slash`,
`non_single_quote` and `non_double_quote`.
The following productions in the Rust grammar are defined in terms of Unicode properties:
`ident`, `non_null`, `non_star`, `non_eol`, `non_slash`, `non_single_quote` and `non_double_quote`.
### Identifiers
@ -203,26 +202,26 @@ grammar as double-quoted strings. Other tokens have exact rules given.
The keywords in [crate files](#crate-files) are the following strings:
~~~~~~~~ {.keyword}
export use mod
mod priv pub use
~~~~~~~~
The keywords in [source files](#source-files) are the following strings:
~~~~~~~~ {.keyword}
again assert
as assert
break
check const copy
drop
else enum export extern
const copy
do drop
else enum extern
fail false fn for
if impl
let log loop
match mod mut
pure
return
struct
match mod move mut
priv pub pure
ref return
self static struct
true trait type
unsafe
unsafe use
while
~~~~~~~~
@ -619,7 +618,7 @@ or a *configuration* in Mesa.] A crate file describes:
and copyright. These are used for linking, versioning and distributing
crates.
* The source-file and directory modules that make up the crate.
* Any `use`, `extern mod` or `export` [view items](#view-items) that apply to
* Any `use` or `extern mod` [view items](#view-items) that apply to
the anonymous module at the top-level of the crate's module tree.
An example of a crate file:
@ -767,7 +766,7 @@ mod math {
#### View items
~~~~~~~~ {.ebnf .gram}
view_item : extern_mod_decl | use_decl | export_decl ;
view_item : extern_mod_decl | use_decl ;
~~~~~~~~
A view item manages the namespace of a module; it does not define new items
@ -776,7 +775,6 @@ view item:
* [extern mod declarations](#extern-mod-declarations)
* [use declarations](#use-declarations)
* [export declarations](#export-declarations)
##### Extern mod declarations
@ -786,9 +784,8 @@ link_attrs : link_attr [ ',' link_attrs ] + ;
link_attr : ident '=' literal ;
~~~~~~~~
An _extern mod declaration_ specifies a dependency on an external crate. The
external crate is then imported into the declaring scope as the `ident`
provided in the `extern_mod_decl`.
An _extern mod declaration_ specifies a dependency on an external crate.
The external crate is then bound into the declaring scope as the `ident` provided in the `extern_mod_decl`.
The external crate is resolved to a specific `soname` at compile time, and a
runtime linkage requirement to that `soname` is passed to the linker for
@ -828,16 +825,16 @@ linkage-dependency with external crates. Linkage dependencies are
independently declared with
[`extern mod` declarations](#extern-mod-declarations).
Imports support a number of "convenience" notations:
Use declarations support a number of "convenience" notations:
* Importing as a different name than the imported name, using the
* Rebinding the target name as a new local name, using the
syntax `use x = p::q::r;`.
* Importing a list of paths differing only in final element, using
the glob-like brace syntax `use a::b::{c,d,e,f};`
* Importing all paths matching a given prefix, using the glob-like
asterisk syntax `use a::b::*;`
* Simultaneously binding a list of paths differing only in final element,
using the glob-like brace syntax `use a::b::{c,d,e,f};`
* Binding all paths matching a given prefix,
using the glob-like asterisk syntax `use a::b::*;`
An example of imports:
An example of `use` declarations:
~~~~
use foo = core::info;
@ -858,82 +855,11 @@ fn main() {
}
~~~~
##### Export declarations
~~~~~~~~ {.ebnf .gram}
export_decl : "export" ident [ ',' ident ] *
| "export" ident "::{}"
| "export" ident '{' ident [ ',' ident ] * '}' ;
~~~~~~~~
An _export declaration_ restricts the set of local names within a module that
can be accessed from code outside the module. By default, all _local items_ in
a module are exported; imported paths are not automatically re-exported by
default. If a module contains an explicit `export` declaration, this
declaration replaces the default export with the export specified.
An example of an export:
~~~~~~~~
pub mod foo {
#[legacy_exports];
export primary;
fn primary() {
helper(1, 2);
helper(3, 4);
}
fn helper(x: int, y: int) {
...
}
}
fn main() {
foo::primary(); // Will compile.
}
~~~~~~~~
If, instead of calling `foo::primary` in main, you were to call `foo::helper`
then it would fail to compile:
~~~~~~~~{.ignore}
foo::helper(2,3) // ERROR: will not compile.
~~~~~~~~
Multiple names may be exported from a single export declaration:
~~~~~~~~
mod foo {
export primary, secondary;
fn primary() {
helper(1, 2);
helper(3, 4);
}
fn secondary() {
...
}
fn helper(x: int, y: int) {
...
}
}
~~~~~~~~
When exporting the name of an `enum` type `t`, by default, the module does
*not* implicitly export any of `t`'s constructors. For example:
~~~~~~~~
mod foo {
export t;
enum t {a, b, c}
}
~~~~~~~~
Here, `foo` imports `t`, but not `a`, `b`, and `c`.
Like items, `use` declarations are private to the containing module, by default.
Also like items, a `use` declaration can be public, if qualified by the `pub` keyword.
A public `use` declaration can therefore be used to _redirect_ some public name to a different target definition,
even a definition with a private canonical path, inside a different module.
If a sequence of such redirections form a cycle or cannot be unambiguously resolved, they represent a compile-time error.
### Functions
@ -1076,7 +1002,7 @@ pure fn pure_length<T>(ls: List<T>) -> uint {
Despite its name, `pure_foldl` is a `fn`, not a `pure fn`, because there is no
way in Rust to specify that the higher-order function argument `f` is a pure
function. So, to use `foldl` in a pure list length function that a pure function
could then use, we must use an `unchecked` block wrapped around the call to
could then use, we must use an `unsafe` block wrapped around the call to
`pure_foldl` in the definition of `pure_length`.
#### Generic functions
@ -1092,7 +1018,7 @@ fn iter<T>(seq: ~[T], f: fn(T)) {
}
fn map<T, U>(seq: ~[T], f: fn(T) -> U) -> ~[U] {
let mut acc = ~[];
for seq.each |elt| { vec::push(acc, f(elt)); }
for seq.each |elt| { acc.push(f(elt)); }
acc
}
~~~~
@ -1300,14 +1226,6 @@ impl circle: shape {
}
~~~~
This defines an implementation named `circle_shape` of trait
`shape` for type `circle`. The name of the implementation is the name
by which it is imported and exported, but has no further significance.
It may be omitted to default to the name of the trait that was
implemented. Implementation names do not conflict the way other names
do: multiple implementations with the same name may exist in a scope at
the same time.
It is possible to define an implementation without referring to a
trait. The methods in such an implementation can only be used
statically (as direct calls on the values of the type that the

View file

@ -4,7 +4,7 @@
Borrowed pointers are one of the more flexible and powerful tools
available in Rust. A borrowed pointer can be used to point anywhere:
into the shared and exchange heaps, into the stack, and even into the
into the managed and exchange heaps, into the stack, and even into the
interior of another data structure. With regard to flexibility, it is
comparable to a C pointer or C++ reference. However, unlike C and C++,
the Rust compiler includes special checks that ensure that borrowed
@ -29,10 +29,10 @@ a limit duration. Borrowed pointers never claim any kind of ownership
over the data that they point at: instead, they are used for cases
where you like to make use of data for a short time.
As an example, consider a simple record type `point`:
As an example, consider a simple struct type `Point`:
~~~
type point = {x: float, y: float};
struct Point {x: float, y: float}
~~~
We can use this simple definition to allocate points in many ways. For
@ -40,10 +40,10 @@ example, in this code, each of these three local variables contains a
point, but allocated in a different place:
~~~
# type point = {x: float, y: float};
let on_the_stack : point = {x: 3.0, y: 4.0};
let shared_box : @point = @{x: 5.0, y: 1.0};
let unique_box : ~point = ~{x: 7.0, y: 9.0};
# struct Point {x: float, y: float}
let on_the_stack : Point = Point {x: 3.0, y: 4.0};
let shared_box : @Point = @Point {x: 5.0, y: 1.0};
let unique_box : ~Point = ~Point {x: 7.0, y: 9.0};
~~~
Suppose we wanted to write a procedure that computed the distance
@ -59,9 +59,9 @@ define a function that takes the points by pointer. We can use
borrowed pointers to do this:
~~~
# type point = {x: float, y: float};
# struct Point {x: float, y: float}
# fn sqrt(f: float) -> float { 0f }
fn compute_distance(p1: &point, p2: &point) -> float {
fn compute_distance(p1: &Point, p2: &Point) -> float {
let x_d = p1.x - p2.x;
let y_d = p1.y - p2.y;
sqrt(x_d * x_d + y_d * y_d)
@ -71,26 +71,26 @@ fn compute_distance(p1: &point, p2: &point) -> float {
Now we can call `compute_distance()` in various ways:
~~~
# type point = {x: float, y: float};
# let on_the_stack : point = {x: 3.0, y: 4.0};
# let shared_box : @point = @{x: 5.0, y: 1.0};
# let unique_box : ~point = ~{x: 7.0, y: 9.0};
# fn compute_distance(p1: &point, p2: &point) -> float { 0f }
# struct Point {x: float, y: float}
# let on_the_stack : Point = Point{x: 3.0, y: 4.0};
# let shared_box : @Point = @Point{x: 5.0, y: 1.0};
# let unique_box : ~Point = ~Point{x: 7.0, y: 9.0};
# fn compute_distance(p1: &Point, p2: &Point) -> float { 0f }
compute_distance(&on_the_stack, shared_box);
compute_distance(shared_box, unique_box);
~~~
Here the `&` operator is used to take the address of the variable
`on_the_stack`; this is because `on_the_stack` has the type `point`
(that is, a record value) and we have to take its address to get a
`on_the_stack`; this is because `on_the_stack` has the type `Point`
(that is, a struct value) and we have to take its address to get a
value. We also call this _borrowing_ the local variable
`on_the_stack`, because we are created an alias: that is, another
route to the same data.
In the case of the boxes `shared_box` and `unique_box`, however, no
explicit action is necessary. The compiler will automatically convert
a box like `@point` or `~point` to a borrowed pointer like
`&point`. This is another form of borrowing; in this case, the
a box like `@Point` or `~Point` to a borrowed pointer like
`&Point`. This is another form of borrowing; in this case, the
contents of the shared/unique box is being lent out.
Whenever a value is borrowed, there are some limitations on what you
@ -108,8 +108,8 @@ it again.
In the previous example, the value `on_the_stack` was defined like so:
~~~
# type point = {x: float, y: float};
let on_the_stack : point = {x: 3.0, y: 4.0};
# struct Point {x: float, y: float}
let on_the_stack: Point = Point {x: 3.0, y: 4.0};
~~~
This results in a by-value variable. As a consequence, we had to
@ -118,20 +118,20 @@ pointer. Sometimes however it is more convenient to move the &
operator into the definition of `on_the_stack`:
~~~
# type point = {x: float, y: float};
let on_the_stack2 : &point = &{x: 3.0, y: 4.0};
# struct Point {x: float, y: float}
let on_the_stack2: &Point = &Point {x: 3.0, y: 4.0};
~~~
Applying `&` to an rvalue (non-assignable location) is just a convenient
shorthand for creating a temporary and taking its address:
~~~
# type point = {x: float, y: float};
let tmp = {x: 3.0, y: 4.0};
let on_the_stack2 : &point = &tmp;
# struct Point {x: float, y: float}
let tmp = Point {x: 3.0, y: 4.0};
let on_the_stack2 : &Point = &tmp;
~~~
Taking the address of fields
# Taking the address of fields
As in C, the `&` operator is not limited to taking the address of
local variables. It can also be used to take the address of fields or
@ -139,39 +139,45 @@ individual array elements. For example, consider this type definition
for `rectangle`:
~~~
type point = {x: float, y: float}; // as before
type size = {w: float, h: float}; // as before
type rectangle = {origin: point, size: size};
struct Point {x: float, y: float} // as before
struct Size {w: float, h: float} // as before
struct Rectangle {origin: Point, size: Size}
~~~
Now again I can define rectangles in a few different ways:
~~~
let rect_stack = &{origin: {x: 1f, y: 2f}, size: {w: 3f, h: 4f}};
let rect_shared = @{origin: {x: 3f, y: 4f}, size: {w: 3f, h: 4f}};
let rect_unique = ~{origin: {x: 5f, y: 6f}, size: {w: 3f, h: 4f}};
# struct Point {x: float, y: float}
# struct Size {w: float, h: float} // as before
# struct Rectangle {origin: Point, size: Size}
let rect_stack = &Rectangle {origin: Point {x: 1f, y: 2f},
size: Size {w: 3f, h: 4f}};
let rect_managed = @Rectangle {origin: Point {x: 3f, y: 4f},
size: Size {w: 3f, h: 4f}};
let rect_unique = ~Rectangle {origin: Point {x: 5f, y: 6f},
size: Size {w: 3f, h: 4f}};
~~~
In each case I can use the `&` operator to extact out individual
subcomponents. For example, I could write:
~~~
# type point = {x: float, y: float};
# type size = {w: float, h: float}; // as before
# type rectangle = {origin: point, size: size};
# let rect_stack = &{origin: {x: 1f, y: 2f}, size: {w: 3f, h: 4f}};
# let rect_shared = @{origin: {x: 3f, y: 4f}, size: {w: 3f, h: 4f}};
# let rect_unique = ~{origin: {x: 5f, y: 6f}, size: {w: 3f, h: 4f}};
# fn compute_distance(p1: &point, p2: &point) -> float { 0f }
compute_distance(&rect_stack.origin, &rect_shared.origin);
# struct Point {x: float, y: float} // as before
# struct Size {w: float, h: float} // as before
# struct Rectangle {origin: Point, size: Size}
# let rect_stack = &{origin: Point {x: 1f, y: 2f}, size: Size {w: 3f, h: 4f}};
# let rect_managed = @{origin: Point {x: 3f, y: 4f}, size: Size {w: 3f, h: 4f}};
# let rect_unique = ~{origin: Point {x: 5f, y: 6f}, size: Size {w: 3f, h: 4f}};
# fn compute_distance(p1: &Point, p2: &Point) -> float { 0f }
compute_distance(&rect_stack.origin, &rect_managed.origin);
~~~
which would borrow the field `origin` from the rectangle on the stack
from the shared box and then compute the distance between them.
from the managed box and then compute the distance between them.
# Borrowing shared boxes and rooting
# Borrowing managed boxes and rooting
Weve seen a few examples so far where heap boxes (both shared and
Weve seen a few examples so far where heap boxes (both managed and
unique) are borrowed. Up till this point, weve glossed over issues of
safety. As stated in the introduction, at runtime a borrowed pointer
is simply a pointer, nothing more. Therefore, if we wish to avoid the
@ -192,8 +198,9 @@ relatively easy, such as when taking the address of a local variable
or a field that is stored on the stack:
~~~
struct X { f: int }
fn example1() {
let mut x = {f: 3};
let mut x = X { f: 3 };
let y = &mut x.f; // -+ L
... // |
} // -+
@ -207,8 +214,9 @@ The situation gets more complex when borrowing data that resides in
heap boxes:
~~~
# struct X { f: int }
fn example2() {
let mut x = @{f: 3};
let mut x = @X { f: 3 };
let y = &x.f; // -+ L
... // |
} // -+
@ -218,20 +226,21 @@ In this example, the value `x` is in fact a heap box, and `y` is
therefore a pointer into that heap box. Again the lifetime of `y` will
be L, the remainder of the function body. But there is a crucial
difference: suppose `x` were reassigned during the lifetime L? If
were not careful, that could mean that the shared box would become
were not careful, that could mean that the managed box would become
unrooted and therefore be subject to garbage collection
> ***Note:***In our current implementation, the garbage collector is
> implemented using reference counting and cycle detection.
For this reason, whenever the interior of a shared box stored in a
For this reason, whenever the interior of a managed box stored in a
mutable location is borrowed, the compiler will insert a temporary
that ensures that the shared box remains live for the entire
that ensures that the managed box remains live for the entire
lifetime. So, the above example would be compiled as:
~~~
# struct X { f: int }
fn example2() {
let mut x = @{f: 3};
let mut x = @X {f: 3};
let x1 = x;
let y = &x1.f; // -+ L
... // |
@ -239,19 +248,19 @@ fn example2() {
~~~
Now if `x` is reassigned, the pointer `y` will still remain valid. This
process is called “rooting”.
process is called *rooting*.
# Borrowing unique boxes
The previous example demonstrated `rooting`, the process by which the
compiler ensures that shared boxes remain live for the duration of a
The previous example demonstrated *rooting*, the process by which the
compiler ensures that managed boxes remain live for the duration of a
borrow. Unfortunately, rooting does not work if the data being
borrowed is a unique box, as it is not possible to have two references
to a unique box.
For unique boxes, therefore, the compiler will only allow a borrow `if
For unique boxes, therefore, the compiler will only allow a borrow *if
the compiler can guarantee that the unique box will not be reassigned
or moved for the lifetime of the pointer`. This does not necessarily
or moved for the lifetime of the pointer*. This does not necessarily
mean that the unique box is stored in immutable memory. For example,
the following function is legal:
@ -283,7 +292,7 @@ rejected by the compiler):
~~~ {.xfail-test}
fn example3() -> int {
let mut x = ~{f: 3};
let mut x = ~X {f: 3};
let y = &x.f;
x = ~{f: 4}; // Error reported here.
*y
@ -325,15 +334,18 @@ which has been freed.
In fact, the compiler can apply this same kind of reasoning can be
applied to any memory which is _(uniquely) owned by the stack
frame_. So we could modify the previous example to introduce
additional unique pointers and records, and the compiler will still be
additional unique pointers and structs, and the compiler will still be
able to detect possible mutations:
~~~ {.xfail-test}
fn example3() -> int {
let mut x = ~{mut f: ~{g: 3}};
struct R { g: int }
struct S { mut f: ~R }
let mut x = ~S {mut f: ~R {g: 3}};
let y = &x.f.g;
x = ~{mut f: ~{g: 4}}; // Error reported here.
x.f = ~{g: 5}; // Error reported here.
x = ~S {mut f: ~R {g: 4}}; // Error reported here.
x.f = ~R {g: 5}; // Error reported here.
*y
}
~~~
@ -346,17 +358,20 @@ Things get tricker when the unique box is not uniquely owned by the
stack frame (or when the compiler doesnt know who the owner
is). Consider a program like this:
~~~ {.xfail-test}
fn example5a(x: @{mut f: ~{g: int}} ...) -> int {
~~~
struct R { g: int }
struct S { mut f: ~R }
fn example5a(x: @S ...) -> int {
let y = &x.f.g; // Error reported here.
...
# return 0;
}
~~~
Here the heap looks something like:
~~~ {.notrust}
Stack Shared Heap Exchange Heap
Stack Managed Heap Exchange Heap
x +------+ +-------------+ +------+
| @... | ----> | mut f: ~... | --+-> | g: 3 |
@ -368,7 +383,7 @@ Here the heap looks something like:
In this case, the owning reference to the value being borrowed is in
fact `x.f`. Moreover, `x.f` is both mutable and aliasable. Aliasable
means that it is possible that there are other pointers to that same
shared box, so even if the compiler were to prevent `x.f` from being
managed box, so even if the compiler were to prevent `x.f` from being
mutated, the field might still be changed through some alias of
`x`. Therefore, to be safe, the compiler only accepts pure actions
during the lifetime of `y`. Well have a final example on purity but
@ -379,7 +394,9 @@ unique found in aliasable memory is to ensure that it is stored within
unique fields, as in the following example:
~~~
fn example5b(x: @{f: ~{g: int}}) -> int {
struct R { g: int }
struct S { f: ~R }
fn example5b(x: @S) -> int {
let y = &x.f.g;
...
# return 0;
@ -394,21 +411,32 @@ If you do have a unique box in a mutable field, and you wish to borrow
it, one option is to use the swap operator to bring that unique box
onto your stack:
~~~ {.xfail-test}
fn example5c(x: @{mut f: ~int}) -> int {
let mut v = ~0;
~~~
struct R { g: int }
struct S { mut f: ~R }
fn example5c(x: @S) -> int {
let mut v = ~R {g: 0};
v <-> x.f; // Swap v and x.f
let y = &v;
...
{ // Block constrains the scope of `y`:
let y = &v.g;
...
}
x.f <- v; // Replace x.f
...
# return 0;
}
~~~
Of course, this has the side effect of modifying your shared box for
the duration of the borrow, so it works best when you know that you
wont be accessing that same box again.
Of course, this has the side effect of modifying your managed box for
the duration of the borrow, so it only works when you know that you
wont be accessing that same box for the duration of the loan. Note
also that sometimes it is necessary to introduce additional blocks to
constrain the scope of the loan. In this example, the borrowed
pointer `y` would still be in scope when you moved the value `v` back
into `x.f`, and hence moving `v` would be considered illegal. You
cannot move values if they are outstanding loans which are still
valid. By introducing the block, the scope of `y` is restricted and so
the move is legal.
# Borrowing and enums
@ -422,11 +450,11 @@ As an example, lets look at the following `shape` type that can
represent both rectangles and circles:
~~~
type point = {x: float, y: float}; // as before
type size = {w: float, h: float}; // as before
enum shape {
circle(point, float), // origin, radius
rectangle(point, size) // upper-left, dimensions
struct Point {x: float, y: float}; // as before
struct Size {w: float, h: float}; // as before
enum Shape {
Circle(Point, float), // origin, radius
Rectangle(Point, Size) // upper-left, dimensions
}
~~~
@ -435,17 +463,17 @@ function takes a borrowed pointer to a shape to avoid the need of
copying them.
~~~
# type point = {x: float, y: float}; // as before
# type size = {w: float, h: float}; // as before
# enum shape {
# circle(point, float), // origin, radius
# rectangle(point, size) // upper-left, dimensions
# struct Point {x: float, y: float}; // as before
# struct Size {w: float, h: float}; // as before
# enum Shape {
# Circle(Point, float), // origin, radius
# Rectangle(Point, Size) // upper-left, dimensions
# }
# const tau: float = 6.28f;
fn compute_area(shape: &shape) -> float {
fn compute_area(shape: &Shape) -> float {
match *shape {
circle(_, radius) => 0.5 * tau * radius * radius,
rectangle(_, ref size) => size.w * size.h
Circle(_, radius) => 0.5 * tau * radius * radius,
Rectangle(_, ref size) => size.w * size.h
}
}
~~~
@ -504,75 +532,82 @@ Stack Memory
~~~
As you can see, the `size` pointer would not be pointing at a `float` and
not a record. This is not good.
not a struct. This is not good.
So, in fact, for every `ref` binding, the compiler will impose the
same rules as the ones we saw for borrowing the interior of a unique
box: it must be able to guarantee that the enum will not be
overwritten for the duration of the borrow. In fact, the example I
gave earlier would be considered safe. This is because the shape
pointer has type `&shape`, which means “borrowed pointer to immutable
pointer has type `&Shape`, which means “borrowed pointer to immutable
memory containing a shape”. If however the type of that pointer were
`&const shape` or `&mut shape`, then the ref binding would not be
`&const Shape` or `&mut Shape`, then the ref binding would not be
permitted. Just as with unique boxes, the compiler will permit ref
bindings into data owned by the stack frame even if it is mutable, but
otherwise it requires that the data reside in immutable memory.
> ***Note:*** Right now, all pattern bindings are by-reference. We
> expect this to change so that copies are the default and references
> must be noted explicitly.
> ***Note:*** Right now, pattern bindings not explicitly annotated
> with `ref` or `copy` use a special mode of "implicit by reference".
> This is changing as soon as we finish updating all the existing code
> in the compiler that relies on the current settings.
# Returning borrowed pointers
So far, all of the examples weve looked at use borrowed pointers in a
“downward” direction. That is, the borrowed pointer is created and
then used during the method or code block which created it. In some
cases, it is also possible to return borrowed pointers to the caller,
but as well see this is more limited.
then used during the method or code block which created it. It is also
possible to return borrowed pointers to the caller, but as we'll see
this requires some explicit annotation.
For example, we could write a subroutine like this:
~~~ {.xfail-test}
type point = {x: float, y: float};
fn get_x(p: &point) -> &float { &p.x }
~~~
struct Point {x: float, y: float}
fn get_x(p: &r/Point) -> &r/float { &p.x }
~~~
Here, the function `get_x()` returns a pointer into the structure it was
given. Youll note that _both_ the parameter and the return value are
borrowed pointers; this is important. In general, it is only possible
to return borrowed pointers if they are derived from a borrowed
pointer which was given as input to the procedure.
given. The type of the parameter (`&r/Point`) and return type (`&r/float`) both
make use of a new syntactic form that we have not seen so far. Here the identifier `r`
serves as an explicit name for the lifetime of the pointer. So in effect
this function is declaring that it takes in a pointer with lifetime `r` and returns
a pointer with that same lifetime.
In the example, `get_x()` took a borrowed pointer to a `point` as
input. In general, for all borrowed pointers that appear in the
signature of a function (such as the parameter and return types), the
compiler assigns the same symbolic lifetime L (we will see later that
there are ways to differentiate the lifetimes of different parameters
if that should be necessary). This means that, from the compilers
point of view, `get_x()` takes and returns two pointers with the same
lifetime. Now, unlike other lifetimes, this lifetime is a bit
abstract: it doesnt refer to a specific expression within `get_x()`,
but rather to some expression within the caller. This is called a
_lifetime parameter_, because the lifetime L is effectively defined by
the caller to `get_x()`, just as the value for the parameter `p` is
defined by the caller.
In general, it is only possible to return borrowed pointers if they
are derived from a borrowed pointer which was given as input to the
procedure. In that case, they will always have the same lifetime as
one of the parameters; named lifetimes are used to indicate which
parameter that is.
In any case, whatever the lifetime L is, the pointer produced by
In the examples before, function parameter types did not include a
lifetime name. In this case, the compiler simply creates a new,
anonymous name, meaning that the parameter is assumed to have a
distinct lifetime from all other parameters.
Named lifetimes that appear in function signatures are conceptually
the same as the other lifetimes we've seen before, but they are a bit
abstract: they dont refer to a specific expression within `get_x()`,
but rather to some expression within the *caller of `get_x()`*. The
lifetime `r` is actually a kind of *lifetime parameter*: it is defined
by the caller to `get_x()`, just as the value for the parameter `p` is
defined by that caller.
In any case, whatever the lifetime `r` is, the pointer produced by
`&p.x` always has the same lifetime as `p` itself, as a pointer to a
field of a record is valid as long as the record is valid. Therefore,
field of a struct is valid as long as the struct is valid. Therefore,
the compiler is satisfied with the function `get_x()`.
To drill in this point, lets look at a variation on the example, this
time one which does not compile:
~~~ {.xfail-test}
type point = {x: float, y: float};
fn get_x_sh(p: @point) -> &float {
struct Point {x: float, y: float}
fn get_x_sh(p: @Point) -> &float {
&p.x // Error reported here
}
~~~
Here, the function `get_x_sh()` takes a shared box as input and
Here, the function `get_x_sh()` takes a managed box as input and
returns a borrowed pointer. As before, the lifetime of the borrowed
pointer that will be returned is a parameter (specified by the
caller). That means that effectively `get_x_sh()` is promising to
@ -582,121 +617,114 @@ promised to return a pointer that was valid for as long as the pointer
it was given.
Within `get_x_sh()`, we see the expression `&p.x` which takes the
address of a field of a shared box. This implies that the compiler
address of a field of a managed box. This implies that the compiler
must guarantee that, so long as the resulting pointer is valid, the
shared box will not be reclaimed by the garbage collector. But recall
that get_x_sh() also promised to return a pointer that was valid for
managed box will not be reclaimed by the garbage collector. But recall
that `get_x_sh()` also promised to return a pointer that was valid for
as long as the caller wanted it to be. Clearly, `get_x_sh()` is not in
a position to make both of these guarantees; in fact, it cannot
guarantee that the pointer will remain valid at all once it returns,
as the parameter `p` may or may not be live in the caller. Therefore,
the compiler will report an error here.
In general, if you borrow a shared (or unique) box to create a
In general, if you borrow a managed (or unique) box to create a
borrowed pointer, the pointer will only be valid within the function
and cannot be returned. Generally, the only way to return borrowed
pointers is to take borrowed pointers as input.
and cannot be returned. This is why the typical way to return borrowed
pointers is to take borrowed pointers as input (the only other case in
which it can be legal to return a borrowed pointer is if the pointer
points at a static constant).
# Named lifetimes
So far we have always used the notation `&T` for a borrowed
pointer. However, sometimes if a function takes many parameters, it is
useful to be able to group those parameters by lifetime. For example,
consider this function:
Let's look at named lifetimes in more detail. In effect, the use of
named lifetimes allows you to group parameters by lifetime. For
example, consider this function:
~~~ {.xfail-test}
# type point = {x: float, y: float}; // as before
# type size = {w: float, h: float}; // as before
# enum shape {
# circle(point, float), // origin, radius
# rectangle(point, size) // upper-left, dimensions
~~~
# struct Point {x: float, y: float}; // as before
# struct Size {w: float, h: float}; // as before
# enum Shape {
# Circle(Point, float), // origin, radius
# Rectangle(Point, Size) // upper-left, dimensions
# }
# fn compute_area(shape: &shape) -> float { 0f }
fn select<T>(shape: &shape, threshold: float,
a: &T, b: &T) -> &T {
# fn compute_area(shape: &Shape) -> float { 0f }
fn select<T>(shape: &r/Shape, threshold: float,
a: &r/T, b: &r/T) -> &r/T {
if compute_area(shape) > threshold {a} else {b}
}
~~~
This function takes three borrowed pointers. Because of the way that
the system works, each will be assigned the same lifetime: the default
lifetime parameter. In practice, this means that, in the caller, the
lifetime of the returned value will be the intersection of the
lifetime of the three region parameters. This may be overloy
conservative, as in this example:
This function takes three borrowed pointers and assigns each the same
lifetime `r`. In practice, this means that, in the caller, the
lifetime `r` will be the *intersection of the lifetime of the three
region parameters*. This may be overly conservative, as in this
example:
~~~ {.xfail-test}
# type point = {x: float, y: float}; // as before
# type size = {w: float, h: float}; // as before
# enum shape {
# circle(point, float), // origin, radius
# rectangle(point, size) // upper-left, dimensions
~~~
# struct Point {x: float, y: float}; // as before
# struct Size {w: float, h: float}; // as before
# enum Shape {
# Circle(Point, float), // origin, radius
# Rectangle(Point, Size) // upper-left, dimensions
# }
# fn compute_area(shape: &shape) -> float { 0f }
# fn select<T>(shape: &shape, threshold: float,
# a: &T, b: &T) -> &T {
# fn compute_area(shape: &Shape) -> float { 0f }
# fn select<T>(shape: &Shape, threshold: float,
# a: &r/T, b: &r/T) -> &r/T {
# if compute_area(shape) > threshold {a} else {b}
# }
// -+ L
fn select_based_on_unit_circle<T>( // |-+ B
threshold: float, a: &T, b: &T) -> &T { // | |
// | |
let shape = circle({x: 0, y: 0}, 1); // | |
select(&shape, threshold, a, b) // | |
} // |-+
// -+
// -+ r
fn select_based_on_unit_circle<T>( // |-+ B
threshold: float, a: &r/T, b: &r/T) -> &r/T { // | |
// | |
let shape = Circle(Point {x: 0., y: 0.}, 1.); // | |
select(&shape, threshold, a, b) // | |
} // |-+
// -+
~~~
In this call to `select()`, the lifetime of the first parameter shape
is B, the function body. Both of the second two parameters `a` and `b`
share the same lifetime, L, which is the lifetime parameter of
share the same lifetime, `r`, which is a lifetime parameter of
`select_based_on_unit_circle()`. The caller will infer the
intersection of these three lifetimes as the lifetime of the returned
intersection of these two lifetimes as the lifetime of the returned
value, and hence the return value of `shape()` will be assigned a
return value of B. This will in turn lead to a compilation error,
because `select_based_on_unit_circle()` is supposed to return a value
with the lifetime L.
lifetime of B. This will in turn lead to a compilation error, because
`select_based_on_unit_circle()` is supposed to return a value with the
lifetime `r`.
To address this, we could modify the definition of `select()` to
To address this, we can modify the definition of `select()` to
distinguish the lifetime of the first parameter from the lifetime of
the latter two. After all, the first parameter is not being
returned. To do so, we make use of the notation `&lt/T`, which is a
borrowed pointer with an explicit lifetime. This effectively creates a
second lifetime parameter for the function; named lifetime parameters
do not need to be declared, you just use them. Here is how the new
`select()` might look:
returned. Here is how the new `select()` might look:
~~~ {.xfail-test}
# type point = {x: float, y: float}; // as before
# type size = {w: float, h: float}; // as before
# enum shape {
# circle(point, float), // origin, radius
# rectangle(point, size) // upper-left, dimensions
~~~
# struct Point {x: float, y: float}; // as before
# struct Size {w: float, h: float}; // as before
# enum Shape {
# Circle(Point, float), // origin, radius
# Rectangle(Point, Size) // upper-left, dimensions
# }
# fn compute_area(shape: &shape) -> float { 0f }
fn select<T>(shape: &tmp/shape, threshold: float,
a: &T, b: &T) -> &T {
# fn compute_area(shape: &Shape) -> float { 0f }
fn select<T>(shape: &tmp/Shape, threshold: float,
a: &r/T, b: &r/T) -> &r/T {
if compute_area(shape) > threshold {a} else {b}
}
~~~
Here you can see the lifetime of shape is now being called `tmp`. The
parameters `a`, `b`, and the return value all remain with the default
lifetime parameter.
parameters `a`, `b`, and the return value are all given the lifetime
`r`. However, since the lifetime `tmp` is not returned, it would be shorter
to just omit the named lifetime for `shape` altogether:
You could also write `select()` using all named lifetime parameters,
which might look like:
~~~ {.xfail-test}
# type point = {x: float, y: float}; // as before
# type size = {w: float, h: float}; // as before
# enum shape {
# circle(point, float), // origin, radius
# rectangle(point, size) // upper-left, dimensions
~~~
# struct Point {x: float, y: float}; // as before
# struct Size {w: float, h: float}; // as before
# enum Shape {
# Circle(Point, float), // origin, radius
# Rectangle(Point, Size) // upper-left, dimensions
# }
# fn compute_area(shape: &shape) -> float { 0f }
fn select<T>(shape: &tmp/shape, threshold: float,
# fn compute_area(shape: &Shape) -> float { 0f }
fn select<T>(shape: &Shape, threshold: float,
a: &r/T, b: &r/T) -> &r/T {
if compute_area(shape) > threshold {a} else {b}
}
@ -721,7 +749,9 @@ a unique box found in an aliasable, mutable location, only now weve
replaced the `...` with some specific code:
~~~
fn example5a(x: @{mut f: ~{g: int}} ...) -> int {
struct R { g: int }
struct S { mut f: ~R }
fn example5a(x: @S ...) -> int {
let y = &x.f.g; // Unsafe
*y + 1
}
@ -739,9 +769,11 @@ fn add_one(x: &int) -> int { *x + 1 }
We can now update `example5a()` to use `add_one()`:
~~~ {.xfail-test}
# fn add_one(x: &int) -> int { *x + 1 }
fn example5a(x: @{mut f: ~{g: int}} ...) -> int {
~~~
# struct R { g: int }
# struct S { mut f: ~R }
# pure fn add_one(x: &int) -> int { *x + 1 }
fn example5a(x: @S ...) -> int {
let y = &x.f.g;
add_one(y) // Error reported here
}
@ -763,4 +795,4 @@ With this change, the modified version of `example5a()` will again compile.
So there you have it. A (relatively) brief tour of borrowed pointer
system. For more details, I refer to the (yet to be written) reference
document on borrowed pointers, which will explain the full notation
and give more examples.
and give more examples.

View file

@ -1,4 +1,6 @@
# Interacting with foreign code
% Rust Foreign Function Interface Tutorial
# Introduction
One of Rust's aims, as a system programming language, is to
interoperate well with C code.
@ -38,7 +40,7 @@ fn main(args: ~[~str]) {
}
~~~~
## Foreign modules
# Foreign modules
Before we can call `SHA1`, we have to declare it. That is what this
part of the program is responsible for:
@ -68,7 +70,7 @@ extern mod something {
}
~~~~
## Foreign calling conventions
# Foreign calling conventions
Most foreign code will be C code, which usually uses the `cdecl` calling
convention, so that is what Rust uses by default when calling foreign
@ -88,7 +90,7 @@ The `"abi"` attribute applies to a foreign module (it can not be applied
to a single function within a module), and must be either `"cdecl"`
or `"stdcall"`. Other conventions may be defined in the future.
## Unsafe pointers
# Unsafe pointers
The foreign `SHA1` function is declared to take three arguments, and
return a pointer.
@ -118,7 +120,7 @@ caution—unlike Rust's other pointer types, unsafe pointers are
completely unmanaged, so they might point at invalid memory, or be
null pointers.
## Unsafe blocks
# Unsafe blocks
The `sha1` function is the most obscure part of the program.
@ -159,7 +161,7 @@ unsafe fn kaboom() { ~"I'm harmless!"; }
This function can only be called from an unsafe block or another
unsafe function.
## Pointer fiddling
# Pointer fiddling
The standard library defines a number of helper functions for dealing
with unsafe data, casting between types, and generally subverting
@ -202,10 +204,10 @@ unsafe pointer that was returned by `SHA1`. SHA1 digests are always
twenty bytes long, so we can pass `20u` for the length of the new
vector.
## Passing structures
# Passing structures
C functions often take pointers to structs as arguments. Since Rust
records are binary-compatible with C structs, Rust programs can call
structs are binary-compatible with C structs, Rust programs can call
such functions directly.
This program uses the POSIX function `gettimeofday` to get a
@ -215,15 +217,21 @@ microsecond-resolution timer.
extern mod std;
use libc::c_ulonglong;
type timeval = {mut tv_sec: c_ulonglong,
mut tv_usec: c_ulonglong};
struct timeval {
mut tv_sec: c_ulonglong,
mut tv_usec: c_ulonglong
}
#[nolink]
extern mod lib_c {
fn gettimeofday(tv: *timeval, tz: *()) -> i32;
}
fn unix_time_in_microseconds() -> u64 unsafe {
let x = {mut tv_sec: 0 as c_ulonglong, mut tv_usec: 0 as c_ulonglong};
lib_c::gettimeofday(ptr::addr_of(x), ptr::null());
let x = timeval {
mut tv_sec: 0 as c_ulonglong,
mut tv_usec: 0 as c_ulonglong
};
lib_c::gettimeofday(ptr::addr_of(&x), ptr::null());
return (x.tv_sec as u64) * 1000_000_u64 + (x.tv_usec as u64);
}
@ -234,8 +242,8 @@ The `#[nolink]` attribute indicates that there's no foreign library to
link in. The standard C library is already linked with Rust programs.
A `timeval`, in C, is a struct with two 32-bit integers. Thus, we
define a record type with the same contents, and declare
`gettimeofday` to take a pointer to such a record.
define a struct type with the same contents, and declare
`gettimeofday` to take a pointer to such a struct.
The second argument to `gettimeofday` (the time zone) is not used by
this program, so it simply declares it to be a pointer to the nil

View file

@ -1,4 +1,6 @@
# Macros
% Rust Macros Tutorial
# Introduction
Functions are the programmer's primary tool of abstraction, but there are
cases in which they are insufficient, because the programmer wants to
@ -50,7 +52,7 @@ early_return!(input_2 special_b);
Macros are defined in pattern-matching style:
## Invocation syntax
# Invocation syntax
On the left-hand-side of the `=>` is the macro invocation syntax. It is
free-form, excepting the following rules:
@ -69,7 +71,7 @@ rules of tokenization apply,
So `($x:ident => (($e:expr)))`, though excessively fancy, would create a macro
that could be invoked like `my_macro!(i=>(( 2+2 )))`.
## Transcription syntax
# Transcription syntax
The right-hand side of the `=>` follows the same rules as the left-hand side,
except that `$` need only be followed by the name of the syntactic fragment
@ -80,9 +82,9 @@ an expression; currently, user-defined macros can only be invoked in
expression position (even though `macro_rules!` itself can be in item
position).
## Multiplicity
# Multiplicity
### Invocation
## Invocation
Going back to the motivating example, suppose that we wanted each invocation
of `early_return` to potentially accept multiple "special" identifiers. The

View file

@ -1,52 +1,165 @@
% Tasks and communication in Rust
% Rust Tasks and Communication Tutorial
Rust supports a system of lightweight tasks, similar to what is found
in Erlang or other actor systems. Rust tasks communicate via messages
and do not share data. However, it is possible to send data without
copying it by making use of [the exchange heap](#unique-boxes), which
allow the sending task to release ownership of a value, so that the
receiving task can keep on using it.
# Introduction
> ***Note:*** As Rust evolves, we expect the task API to grow and
> change somewhat. The tutorial documents the API as it exists today.
The Rust language is designed from the ground up to support pervasive
and safe concurrency through lightweight, memory-isolated tasks and
message passing.
# Spawning a task
Rust tasks are not the same as traditional threads - they are what are
often referred to as _green threads_, cooperatively scheduled by the
Rust runtime onto a small number of operating system threads. Being
significantly cheaper to create than traditional threads, Rust can
create hundreds of thousands of concurrent tasks on a typical 32-bit
system.
Spawning a task is done using the various spawn functions in the
module `task`. Let's begin with the simplest one, `task::spawn()`:
Tasks provide failure isolation and recovery. When an exception occurs
in rust code (either by calling `fail` explicitly or by otherwise performing
an invalid operation) the entire task is destroyed - there is no way
to `catch` an exception as in other languages. Instead tasks may monitor
each other to detect when failure has occurred.
Rust tasks have dynamically sized stacks. When a task is first created
it starts off with a small amount of stack (currently in the low
thousands of bytes, depending on platform) and more stack is acquired as
needed. A Rust task will never run off the end of the stack as is
possible in many other languages, but they do have a stack budget, and
if a Rust task exceeds its stack budget then it will fail safely.
Tasks make use of Rust's type system to provide strong memory safety
guarantees, disallowing shared mutable state. Communication between
tasks is facilitated by the transfer of _owned_ data through the
global _exchange heap_.
This tutorial will explain the basics of tasks and communication in Rust,
explore some typical patterns in concurrent Rust code, and finally
discuss some of the more exotic synchronization types in the standard
library.
## A note about the libraries
While Rust's type system provides the building blocks needed for safe
and efficient tasks, all of the task functionality itself is implemented
in the core and standard libraries, which are still under development
and do not always present a consistent interface.
In particular, there are currently two independent modules that provide
a message passing interface to Rust code: `core::comm` and `core::pipes`.
`core::comm` is an older, less efficient system that is being phased out
in favor of `pipes`. At some point the existing `core::comm` API will
be romoved and the user-facing portions of `core::pipes` will be moved
to `core::comm`. In this tutorial we will discuss `pipes` and ignore
the `comm` API.
For your reference, these are the standard modules involved in Rust
concurrency at the moment.
* [`core::task`] - All code relating to tasks and task scheduling
* [`core::comm`] - The deprecated message passing API
* [`core::pipes`] - The new message passing infrastructure and API
* [`std::comm`] - Higher level messaging types based on `core::pipes`
* [`std::sync`] - More exotic synchronization tools, including locks
* [`std::arc`] - The ARC type, for safely sharing immutable data
* [`std::par`] - Some basic tools for implementing parallel algorithms
[`core::task`]: core/task.html
[`core::comm`]: core/comm.html
[`core::pipes`]: core/pipes.html
[`std::comm`]: std/comm.html
[`std::sync`]: std/sync.html
[`std::arc`]: std/arc.html
[`std::par`]: std/par.html
# Basics
The programming interface for creating and managing tasks is contained
in the `task` module of the `core` library, making it available to all
Rust code by default. At it's simplest, creating a task is a matter of
calling the `spawn` function, passing a closure to run in the new
task.
~~~~
# use io::println;
use task::spawn;
use io::println;
let some_value = 22;
// Print something profound in a different task using a named function
fn print_message() { println("I am running in a different task!"); }
spawn(print_message);
// Print something more profound in a different task using a lambda expression
spawn( || println("I am also running in a different task!") );
// The canonical way to spawn is using `do` notation
do spawn {
println(~"This executes in the child task.");
println(fmt!("%d", some_value));
println("I too am running in a different task!");
}
~~~~
The argument to `task::spawn()` is a [unique
closure](#unique-closures) of type `fn~()`, meaning that it takes no
arguments and generates no return value. The effect of `task::spawn()`
is to fire up a child task that will execute the closure in parallel
with the creator.
In Rust, there is nothing special about creating tasks - the language
itself doesn't know what a 'task' is. Instead, Rust provides in the
type system all the tools necessary to implement safe concurrency,
_owned types_ in particular, and leaves the dirty work up to the
core library.
# Communication
The `spawn` function has a very simple type signature: `fn spawn(f:
~fn())`. Because it accepts only owned closures, and owned closures
contained only owned data, `spawn` can safely move the entire closure
and all its associated state into an entirely different task for
execution. Like any closure, the function passed to spawn may capture
an environment that it carries across tasks.
Now that we have spawned a child task, it would be nice if we could
communicate with it. This is done using *pipes*. Pipes are simply a
pair of endpoints, with one for sending messages and another for
receiving messages. The easiest way to create a pipe is to use
`pipes::stream`. Imagine we wish to perform two expensive
computations in parallel. We might write something like:
~~~
# use io::println;
# use task::spawn;
# fn generate_task_number() -> int { 0 }
// Generate some state locally
let child_task_number = generate_task_number();
do spawn {
// Capture it in the remote task
println(fmt!("I am child number %d", child_task_number));
}
~~~
By default tasks will be multiplexed across the available cores, running
in parallel, thus on a multicore machine, running the following code
should interleave the output in vaguely random order.
~~~
# use io::print;
# use task::spawn;
for int::range(0, 20) |child_task_number| {
do spawn {
print(fmt!("I am child number %d\n", child_task_number));
}
}
~~~
## Communication
Now that we have spawned a new task, it would be nice if we could
communicate with it. Recall that Rust does not have shared mutable
state, so one task may not manipulate variables owned by another task.
Instead we use *pipes*.
Pipes are simply a pair of endpoints, with one for sending messages
and another for receiving messages. Pipes are low-level communication
building-blocks and so come in a variety of forms, appropriate for
different use cases, but there are just a few varieties that are most
commonly used, which we will cover presently.
The simplest way to create a pipe is to use the `pipes::stream`
function to create a `(Chan, Port)` pair. In Rust parlance a 'channel'
is a sending endpoint of a pipe, and a 'port' is the recieving
endpoint. Consider the following example of performing two calculations
concurrently.
~~~~
use task::spawn;
use pipes::{stream, Port, Chan};
let (chan, port) = stream();
let (chan, port): (Chan<int>, Port<int>) = stream();
do spawn {
let result = some_expensive_computation();
@ -55,43 +168,45 @@ do spawn {
some_other_expensive_computation();
let result = port.recv();
# fn some_expensive_computation() -> int { 42 }
# fn some_other_expensive_computation() {}
~~~~
Let's walk through this code line-by-line. The first line creates a
stream for sending and receiving integers:
Let's examine this example in detail. The `let` statement first creates a
stream for sending and receiving integers (recall that `let` can be
used for destructuring patterns, in this case separating a tuple into
its component parts).
~~~~ {.ignore}
# use pipes::stream;
let (chan, port) = stream();
~~~~
# use pipes::{stream, Chan, Port};
let (chan, port): (Chan<int>, Port<int>) = stream();
~~~~
This port is where we will receive the message from the child task
once it is complete. The channel will be used by the child to send a
message to the port. The next statement actually spawns the child:
The channel will be used by the child task to send data to the parent task,
which will wait to recieve the data on the port. The next statement
spawns the child task.
~~~~
# use task::{spawn};
# use comm::{Port, Chan};
# use task::spawn;
# use pipes::{stream, Port, Chan};
# fn some_expensive_computation() -> int { 42 }
# let port = Port();
# let chan = port.chan();
# let (chan, port) = stream();
do spawn {
let result = some_expensive_computation();
chan.send(result);
}
~~~~
This child will perform the expensive computation send the result
over the channel. (Under the hood, `chan` was captured by the
closure that forms the body of the child task. This capture is
allowed because channels are sendable.)
Notice that `chan` was transferred to the child task implicitly by
capturing it in the task closure. Both `Chan` and `Port` are sendable
types and may be captured into tasks or otherwise transferred between
them. In the example, the child task performs an expensive computation
then sends the result over the captured channel.
Finally, the parent continues by performing
some other expensive computation and then waiting for the child's result
to arrive on the port:
Finally, the parent continues by performing some other expensive
computation and then waiting for the child's result to arrive on the
port:
~~~~
# use pipes::{stream, Port, Chan};
@ -102,7 +217,248 @@ some_other_expensive_computation();
let result = port.recv();
~~~~
# Creating a task with a bi-directional communication path
The `Port` and `Chan` pair created by `stream` enable efficient
communication between a single sender and a single receiver, but
multiple senders cannot use a single `Chan`, nor can multiple
receivers use a single `Port`. What if our example needed to perform
multiple computations across a number of tasks? The following cannot
be written:
~~~ {.xfail-test}
# use task::{spawn};
# use pipes::{stream, Port, Chan};
# fn some_expensive_computation() -> int { 42 }
let (chan, port) = stream();
do spawn {
chan.send(some_expensive_computation());
}
// ERROR! The previous spawn statement already owns the channel,
// so the compiler will not allow it to be captured again
do spawn {
chan.send(some_expensive_computation());
}
~~~
Instead we can use a `SharedChan`, a type that allows a single
`Chan` to be shared by multiple senders.
~~~
# use task::spawn;
use pipes::{stream, SharedChan};
let (chan, port) = stream();
let chan = SharedChan(move chan);
for uint::range(0, 3) |init_val| {
// Create a new channel handle to distribute to the child task
let child_chan = chan.clone();
do spawn {
child_chan.send(some_expensive_computation(init_val));
}
}
let result = port.recv() + port.recv() + port.recv();
# fn some_expensive_computation(_i: uint) -> int { 42 }
~~~
Here we transfer ownership of the channel into a new `SharedChan`
value. Like `Chan`, `SharedChan` is a non-copyable, owned type
(sometimes also referred to as an 'affine' or 'linear' type). Unlike
`Chan` though, `SharedChan` may be duplicated with the `clone()`
method. A cloned `SharedChan` produces a new handle to the same
channel, allowing multiple tasks to send data to a single port.
Between `spawn`, `stream` and `SharedChan` we have enough tools
to implement many useful concurrency patterns.
Note that the above `SharedChan` example is somewhat contrived since
you could also simply use three `stream` pairs, but it serves to
illustrate the point. For reference, written with multiple streams it
might look like the example below.
~~~
# use task::spawn;
# use pipes::{stream, Port, Chan};
// Create a vector of ports, one for each child task
let ports = do vec::from_fn(3) |init_val| {
let (chan, port) = stream();
do spawn {
chan.send(some_expensive_computation(init_val));
}
port
};
// Wait on each port, accumulating the results
let result = ports.foldl(0, |accum, port| *accum + port.recv() );
# fn some_expensive_computation(_i: uint) -> int { 42 }
~~~
# TODO
# Handling task failure
Rust has a built-in mechanism for raising exceptions, written `fail`
(or `fail ~"reason"`, or sometimes `assert expr`), and it causes the
task to unwind its stack, running destructors and freeing memory along
the way, and then exit itself. Unlike C++, exceptions in Rust are
unrecoverable within a single task - once a task fails there is no way
to "catch" the exception.
All tasks are, by default, _linked_ to each other, meaning their fate
is interwined, and if one fails so do all of them.
~~~
# use task::spawn;
# fn do_some_work() { loop { task::yield() } }
# do task::try {
// Create a child task that fails
do spawn { fail }
// This will also fail because the task we spawned failed
do_some_work();
# };
~~~
While it isn't possible for a task to recover from failure,
tasks may be notified when _other_ tasks fail. The simplest way
of handling task failure is with the `try` function, which is
similar to spawn, but immediately blocks waiting for the child
task to finish.
~~~
# fn some_condition() -> bool { false }
# fn calculate_result() -> int { 0 }
let result: Result<int, ()> = do task::try {
if some_condition() {
calculate_result()
} else {
fail ~"oops!";
}
};
assert result.is_err();
~~~
Unlike `spawn`, the function spawned using `try` may return a value,
which `try` will dutifully propagate back to the caller in a [`Result`]
enum. If the child task terminates successfully, `try` will
return an `Ok` result; if the child task fails, `try` will return
an `Error` result.
[`Result`]: core/result.html
> ***Note:*** A failed task does not currently produce a useful error
> value (all error results from `try` are equal to `Err(())`). In the
> future it may be possible for tasks to intercept the value passed to
> `fail`.
TODO: Need discussion of `future_result` in order to make failure
modes useful.
But not all failure is created equal. In some cases you might need to
abort the entire program (perhaps you're writing an assert which, if
it trips, indicates an unrecoverable logic error); in other cases you
might want to contain the failure at a certain boundary (perhaps a
small piece of input from the outside world, which you happen to be
processing in parallel, is malformed and its processing task can't
proceed). Hence the need for different _linked failure modes_.
## Failure modes
By default, task failure is _bidirectionally linked_, which means if
either task dies, it kills the other one.
~~~
# fn sleep_forever() { loop { task::yield() } }
# do task::try {
do task::spawn {
do task::spawn {
fail; // All three tasks will die.
}
sleep_forever(); // Will get woken up by force, then fail
}
sleep_forever(); // Will get woken up by force, then fail
# };
~~~
If you want parent tasks to kill their children, but not for a child
task's failure to kill the parent, you can call
`task::spawn_supervised` for _unidirectionally linked_ failure. The
function `task::try`, which we saw previously, uses `spawn_supervised`
internally, with additional logic to wait for the child task to finish
before returning. Hence:
~~~
# use pipes::{stream, Chan, Port};
# use task::{spawn, try};
# fn sleep_forever() { loop { task::yield() } }
# do task::try {
let (sender, receiver): (Chan<int>, Port<int>) = stream();
do spawn { // Bidirectionally linked
// Wait for the supervised child task to exist.
let message = receiver.recv();
// Kill both it and the parent task.
assert message != 42;
}
do try { // Unidirectionally linked
sender.send(42);
sleep_forever(); // Will get woken up by force
}
// Flow never reaches here -- parent task was killed too.
# };
~~~
Supervised failure is useful in any situation where one task manages
multiple fallible child tasks, and the parent task can recover
if any child files. On the other hand, if the _parent_ (supervisor) fails
then there is nothing the children can do to recover, so they should
also fail.
Supervised task failure propagates across multiple generations even if
an intermediate generation has already exited:
~~~
# fn sleep_forever() { loop { task::yield() } }
# fn wait_for_a_while() { for 1000.times { task::yield() } }
# do task::try::<int> {
do task::spawn_supervised {
do task::spawn_supervised {
sleep_forever(); // Will get woken up by force, then fail
}
// Intermediate task immediately exits
}
wait_for_a_while();
fail; // Will kill grandchild even if child has already exited
# };
~~~
Finally, tasks can be configured to not propagate failure to each
other at all, using `task::spawn_unlinked` for _isolated failure_.
~~~
# fn random() -> int { 100 }
# fn sleep_for(i: int) { for i.times { task::yield() } }
# do task::try::<()> {
let (time1, time2) = (random(), random());
do task::spawn_unlinked {
sleep_for(time2); // Won't get forced awake
fail;
}
sleep_for(time1); // Won't get forced awake
fail;
// It will take MAX(time1,time2) for the program to finish.
# };
~~~
# Unfinished notes
## Actor patterns
## Linearity, option dancing, owned closures
## Creating a task with a bi-directional communication path
A very common thing to do is to spawn a child task where the parent
and child both need to exchange messages with each other. The
@ -171,3 +527,4 @@ assert from_child.recv() == ~"0";
The parent task first calls `DuplexStream` to create a pair of bidirectional endpoints. It then uses `task::spawn` to create the child task, which captures one end of the communication channel. As a result, both parent
and child can send and receive data to and from the other.

View file

@ -82,7 +82,7 @@ supported build environments that are most likely to work.
> ***Note:*** Windows users should read the detailed
> [getting started][wiki-start] notes on the wiki. Even when using
> the binary installer the windows build requires a MinGW installation,
> the binary installer the Windows build requires a MinGW installation,
> the precise details of which are not discussed in this tutorial.
To build from source you will also need the following prerequisite
@ -111,12 +111,9 @@ can be adjusted by passing a `--prefix` argument to
`configure`. Various other options are also supported, pass `--help`
for more information on them.
When complete, `make install` will place the following programs into
`/usr/local/bin`:
* `rustc`, the Rust compiler
* `rustdoc`, the API-documentation tool
* `cargo`, the Rust package manager
When complete, `make install` will place several programs into
`/usr/local/bin`: `rustc`, the Rust compiler; `rustdoc`, the
API-documentation tool, and `cargo`, the Rust package manager.
[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
[tarball]: http://dl.rust-lang.org/dist/rust-0.4.tar.gz
@ -216,8 +213,8 @@ fn main() {
}
~~~~
The `let` keyword, introduces a local variable. By default, variables
are immutable. `let mut` can be used to introduce a local variable
The `let` keyword introduces a local variable. Variables are immutable
by default, so `let mut` can be used to introduce a local variable
that can be reassigned.
~~~~
@ -232,14 +229,17 @@ while count < 10 {
Although Rust can almost always infer the types of local variables, it
can help readability to specify a variable's type by following it with
a colon, then the type name. Local variables may shadow earlier
declarations, making the earlier variables inaccessible.
a colon, then the type name.
~~~~
let my_favorite_value: float = 57.8;
let my_favorite_value: int = my_favorite_value as int;
~~~~
Local variables may shadow earlier declarations, as in the previous
example in which `my_favorite_value` is first declared as a `float`
then a second `my_favorite_value` is declared as an int.
Rust identifiers follow the same rules as C; they start with an alphabetic
character or an underscore, and after that may contain any sequence of
alphabetic characters, numbers, or underscores. The preferred style is to
@ -371,7 +371,7 @@ more detail later on (the `T`s here stand for any other type):
`[T * N]` Vector (like an array in other languages) with N elements
`[mut T * N]` Mutable vector with N elements
`(T1, T2)` Tuple type. Any arity above 1 is supported
`@T`, `~T`, `&T` [Pointer types](#boxes-and-pointers)
`&T`, `~T`, `@T` [Pointer types](#boxes-and-pointers)
------------------------- -----------------------------------------------
Some types can only be manipulated by pointer, never directly. For instance,
@ -421,7 +421,7 @@ Rust will assume that an unsuffixed integer literal has type
~~~~
let a = 1; // a is an int
let b = 10i; // b is an int, due to the 'i' suffix
let c = 100u; // c as a uint
let c = 100u; // c is a uint
let d = 1000i32; // d is an i32
~~~~
@ -619,7 +619,7 @@ literals and most enum variants.
`while` produces a loop that runs as long as its given condition
(which must have type `bool`) evaluates to true. Inside a loop, the
keyword `break` can be used to abort the loop, and `again` can be used
keyword `break` can be used to abort the loop, and `loop` can be used
to abort the current iteration and continue with the next.
~~~~
@ -713,16 +713,16 @@ enum Shape {
}
~~~~
A value of this type is either a Circle, in which case it contains a
point struct and a float, or a Rectangle, in which case it contains
two point records. The run-time representation of such a value
A value of this type is either a `Circle`, in which case it contains a
`Point` struct and a float, or a `Rectangle`, in which case it contains
two `Point` structs. The run-time representation of such a value
includes an identifier of the actual form that it holds, much like the
'tagged union' pattern in C, but with better ergonomics.
The above declaration will define a type `shape` that can be used to
refer to such shapes, and two functions, `circle` and `rectangle`,
The above declaration will define a type `Shape` that can be used to
refer to such shapes, and two functions, `Circle` and `Rectangle`,
which can be used to construct values of the type (taking arguments of
the specified types). So `circle({x: 0f, y: 0f}, 10f)` is the way to
the specified types). So `Circle(Point {x: 0f, y: 0f}, 10f)` is the way to
create a new circle.
Enum variants need not have type parameters. This, for example, is
@ -820,7 +820,7 @@ fn point_from_direction(dir: Direction) -> Point {
## Tuples
Tuples in Rust behave exactly like records, except that their fields
Tuples in Rust behave exactly like structs, except that their fields
do not have names (and can thus not be accessed with dot notation).
Tuples can have any arity except for 0 or 1 (though you may consider
nil, `()`, as the empty tuple if you like).
@ -957,7 +957,7 @@ Rust has three competing goals that inform its view of memory:
Most languages that offer strong memory safety guarantees rely upon a
garbage-collected heap to manage all of the objects. This approach is
straightforward both in concept and in implementation, but has
significant costs. Languages that take this approach tend to
significant costs. Languages that follow this path tend to
aggressively pursue ways to ameliorate allocation costs (think the
Java Virtual Machine). Rust supports this strategy with _managed
boxes_: memory allocated on the heap whose lifetime is managed
@ -982,7 +982,7 @@ tasks. Experience in other languages has proven that isolating each
task's heap from the others is a reliable strategy and one that is
easy for programmers to reason about. Heap isolation has the
additional benefit that garbage collection must only be done
per-heap. Rust never "stops the world" to garbage-collect memory.
per-heap. Rust never "stops the world" to reclaim memory.
Complete isolation of heaps between tasks implies that any data
transferred between tasks must be copied. While this is a fine and
@ -995,27 +995,18 @@ _owned boxes_. All tasks may allocate objects on the exchange heap,
then transfer ownership of those objects to other tasks, avoiding
expensive copies.
## What to be aware of
Rust has three "realms" in which objects can be allocated: the stack,
the local heap, and the exchange heap. These realms have corresponding
pointer types: the borrowed pointer (`&T`), the managed box (`@T`),
and the owned box (`~T`). These three sigils will appear
repeatedly as we explore the language. Learning the appropriate role
of each is key to using Rust effectively.
# Boxes and pointers
In contrast to a lot of modern languages, aggregate types like records
In contrast to a lot of modern languages, aggregate types like structs
and enums are _not_ represented as pointers to allocated memory in
Rust. They are, as in C and C++, represented directly. This means that
if you `let x = {x: 1f, y: 1f};`, you are creating a record on the
stack. If you then copy it into a data structure, the whole record is
if you `let x = Point {x: 1f, y: 1f};`, you are creating a struct on the
stack. If you then copy it into a data structure, the whole struct is
copied, not just a pointer.
For small records like `point`, this is usually more efficient than
allocating memory and going through a pointer. But for big records, or
records with mutable fields, it can be useful to have a single copy on
For small structs like `Point`, this is usually more efficient than
allocating memory and going through a pointer. But for big structs, or
those with mutable fields, it can be useful to have a single copy on
the heap, and refer to that through a pointer.
Rust supports several types of pointers. The safe pointer types are
@ -1191,8 +1182,8 @@ compute_distance(shared_box, unique_box);
~~~
Here the `&` operator is used to take the address of the variable
`on_the_stack`; this is because `on_the_stack` has the type `point`
(that is, a record value) and we have to take its address to get a
`on_the_stack`; this is because `on_the_stack` has the type `Point`
(that is, a struct value) and we have to take its address to get a
value. We also call this _borrowing_ the local variable
`on_the_stack`, because we are created an alias: that is, another
route to the same data.
@ -1517,7 +1508,7 @@ fn each(v: &[int], op: fn(v: &int)) {
The reason we pass in a *pointer* to an integer rather than the
integer itself is that this is how the actual `each()` function for
vectors works. Using a pointer means that the function can be used
for vectors of any type, even large records that would be impractical
for vectors of any type, even large structs that would be impractical
to copy out of the vector on each iteration. As a caller, if we use a
closure to provide the final operator argument, we can write it in a
way that has a pleasant, block-like structure.
@ -1576,7 +1567,7 @@ Empty argument lists can be omitted from `do` expressions.
Most iteration in Rust is done with `for` loops. Like `do`,
`for` is a nice syntax for doing control flow with closures.
Additionally, within a `for` loop, `break`, `again`, and `return`
Additionally, within a `for` loop, `break`, `loop`, and `return`
work just as they do with `while` and `loop`.
Consider again our `each` function, this time improved to
@ -1611,7 +1602,7 @@ With `for`, functions like `each` can be treated more
like builtin looping structures. When calling `each`
in a `for` loop, instead of returning `false` to break
out of the loop, you just write `break`. To skip ahead
to the next iteration, write `again`.
to the next iteration, write `loop`.
~~~~
# use each = vec::each;
@ -1644,14 +1635,15 @@ fn contains(v: &[int], elt: int) -> bool {
# Generics
Throughout this tutorial, we've been defining functions that act only on
single data types. With type parameters we can also define functions that
may be invoked on multiple types.
specific data types. With type parameters we can also define functions whose
arguments represent generic types, and which can be invoked with a variety
of types. Consider a generic `map` function.
~~~~
fn map<T, U>(vector: &[T], function: fn(v: &T) -> U) -> ~[U] {
let mut accumulator = ~[];
for vec::each(vector) |element| {
vec::push(accumulator, function(element));
accumulator.push(function(element));
}
return accumulator;
}
@ -1665,7 +1657,7 @@ each other.
Inside a generic function, the names of the type parameters
(capitalized by convention) stand for opaque types. You can't look
inside them, but you can pass them around. Note that instances of
generic types are almost always passed by pointer. For example, the
generic types are often passed by pointer. For example, the
parameter `function()` is supplied with a pointer to a value of type
`T` and not a value of type `T` itself. This ensures that the
function works with the broadest set of types possible, since some
@ -1691,11 +1683,11 @@ These declarations produce valid types like `Set<int>`, `Stack<int>`
and `Maybe<int>`.
Generic functions in Rust are compiled to very efficient runtime code
through a process called _monomorphisation_. This big word just means
that, for each generic function you call, the compiler generates a
specialized version that is optimized specifically for the argument
types. In this respect Rust's generics have similar performance
characteristics to C++ templates.
through a process called _monomorphisation_. This is a fancy way of
saying that, for each generic function you call, the compiler
generates a specialized version that is optimized specifically for the
argument types. In this respect Rust's generics have similar
performance characteristics to C++ templates.
## Traits
@ -1760,13 +1752,10 @@ types by the compiler, and may not be overridden:
## Declaring and implementing traits
A trait consists of a set of methods, or may be empty, as is the case
with `Copy`, `Send`, and `Const`. A method is a function that
can be applied to a `self` value and a number of arguments, using the
dot notation: `self.foo(arg1, arg2)`.
For example, we could declare the trait `Printable` for things that
can be printed to the console, with a single method:
A trait consists of a set of methods, without bodies, or may be empty,
as is the case with `Copy`, `Send`, and `Const`. For example, we could
declare the trait `Printable` for things that can be printed to the
console, with a single method:
~~~~
trait Printable {
@ -1774,9 +1763,12 @@ trait Printable {
}
~~~~
To actually implement a trait for a given type, the `impl` form is
used. This defines implementations of `Printable` for the `int` and
`~str` types.
Traits may be implemented for specific types with [impls]. An impl
that implements a trait includes the name of the trait at the start of
the definition, as in the following impls of `Printable` for `int`
and `~str`.
[impls]: #functions-and-methods
~~~~
# trait Printable { fn print(); }
@ -1792,14 +1784,10 @@ impl ~str: Printable {
# (~"foo").print();
~~~~
Given these, we may call `1.print()` to print `"1"`, or
`(~"foo").print()` to print `"foo"` again, as with . This is basically a form of
static overloading—when the Rust compiler sees the `print` method
call, it looks for an implementation that matches the type with a
method that matches the name, and simply calls that.
Traits may themselves contain type parameters. A trait for
generalized sequence types might look like the following:
Methods defined in an implementation of a trait may be called just as
any other method, using dot notation, as in `1.print()`. Traits may
themselves contain type parameters. A trait for generalized sequence
types might look like the following:
~~~~
trait Seq<T> {

View file

@ -75,10 +75,7 @@ Write intermediate files (.bc, .opt.bc, .o)
in addition to normal output
.TP
\fB\-\-static\fR
Use or produce static libraries or binaries
.TP
\fB\-\-stats\fR
Print compilation statistics
Use or produce static libraries or binaries (experimental)
.TP
\fB\-\-sysroot\fR <path>
Override the system root
@ -87,10 +84,9 @@ Override the system root
Build a test harness
.TP
\fB\-\-target\fR <triple>
Target cpu\-manufacturer\-kernel[\-os] to compile for
(default: host triple)
(see http://sources.redhat.com/autobook/autobook/
autobook_17.html for detail)
Target cpu\-manufacturer\-kernel[\-os] to compile for (default: host triple)
(see <\fBhttp://sources.redhat.com/autobook/autobook/autobook_17.html\fR> for
detail)
.TP
\fB\-W\fR <foo>
enable warning <foo>
@ -121,7 +117,7 @@ To build either with a crate (.rc) file:
$ rustc hello.rc
.SH "BUGS"
See \fBhttps://github.com/mozilla/rust/issues\fR for a list of known bugs.
See <\fBhttps://github.com/mozilla/rust/issues\fR> for a list of known bugs.
.SH "AUTHOR"
See \fBAUTHORS.txt\fR in the rust source distribution. Graydon Hoare

View file

@ -24,6 +24,8 @@
#[allow(vecs_implicitly_copyable,
non_implicitly_copyable_typarams)];
#[allow(non_camel_case_types)];
#[allow(deprecated_mode)];
#[allow(deprecated_pattern)];
extern mod core(vers = "0.4");
extern mod std(vers = "0.4");

View file

@ -11,13 +11,14 @@ use syntax::diagnostic;
use result::{Ok, Err};
use io::WriterUtil;
use send_map::linear::LinearMap;
use std::{map, json, tempfile, term, sort, getopts};
use map::HashMap;
use to_str::to_str;
use getopts::{optflag, optopt, opt_present};
use dvec::DVec;
type package = {
struct Package {
name: ~str,
uuid: ~str,
url: ~str,
@ -26,10 +27,10 @@ type package = {
reference: Option<~str>,
tags: ~[~str],
versions: ~[(~str, ~str)]
};
}
impl package : cmp::Ord {
pure fn lt(other: &package) -> bool {
impl Package : cmp::Ord {
pure fn lt(other: &Package) -> bool {
if self.name.lt(&(*other).name) { return true; }
if (*other).name.lt(&self.name) { return false; }
if self.uuid.lt(&(*other).uuid) { return true; }
@ -45,28 +46,21 @@ impl package : cmp::Ord {
if self.versions.lt(&(*other).versions) { return true; }
return false;
}
pure fn le(other: &package) -> bool { !(*other).lt(&self) }
pure fn ge(other: &package) -> bool { !self.lt(other) }
pure fn gt(other: &package) -> bool { (*other).lt(&self) }
pure fn le(other: &Package) -> bool { !(*other).lt(&self) }
pure fn ge(other: &Package) -> bool { !self.lt(other) }
pure fn gt(other: &Package) -> bool { (*other).lt(&self) }
}
type local_package = {
name: ~str,
metaname: ~str,
version: ~str,
files: ~[~str]
};
type source = @{
struct Source {
name: ~str,
mut url: ~str,
mut method: ~str,
mut key: Option<~str>,
mut keyfp: Option<~str>,
packages: DVec<package>
};
packages: DVec<Package>
}
type cargo = {
struct Cargo {
pgp: bool,
root: Path,
installdir: Path,
@ -74,13 +68,13 @@ type cargo = {
libdir: Path,
workdir: Path,
sourcedir: Path,
sources: map::HashMap<~str, source>,
sources: map::HashMap<~str, @Source>,
mut current_install: ~str,
dep_cache: map::HashMap<~str, bool>,
opts: options
};
opts: Options
}
type crate = {
struct Crate {
name: ~str,
vers: ~str,
uuid: ~str,
@ -88,22 +82,22 @@ type crate = {
sigs: Option<~str>,
crate_type: Option<~str>,
deps: ~[~str]
};
}
type options = {
struct Options {
test: bool,
mode: mode,
mode: Mode,
free: ~[~str],
help: bool,
};
}
enum mode { system_mode, user_mode, local_mode }
enum Mode { SystemMode, UserMode, LocalMode }
impl mode : cmp::Eq {
pure fn eq(other: &mode) -> bool {
impl Mode : cmp::Eq {
pure fn eq(other: &Mode) -> bool {
(self as uint) == ((*other) as uint)
}
pure fn ne(other: &mode) -> bool { !self.eq(other) }
pure fn ne(other: &Mode) -> bool { !self.eq(other) }
}
fn opts() -> ~[getopts::Opt] {
@ -150,7 +144,7 @@ fn is_uuid(id: ~str) -> bool {
if vec::len(parts) == 5u {
let mut correct = 0u;
for vec::eachi(parts) |i, part| {
fn is_hex_digit(ch: char) -> bool {
fn is_hex_digit(+ch: char) -> bool {
('0' <= ch && ch <= '9') ||
('a' <= ch && ch <= 'f') ||
('A' <= ch && ch <= 'F')
@ -270,7 +264,7 @@ fn load_link(mis: ~[@ast::meta_item]) -> (Option<~str>,
(name, vers, uuid)
}
fn load_crate(filename: &Path) -> Option<crate> {
fn load_crate(filename: &Path) -> Option<Crate> {
let sess = parse::new_parse_sess(None);
let c = parse::parse_crate_from_crate_file(filename, ~[], sess);
@ -351,7 +345,7 @@ fn load_crate(filename: &Path) -> Option<crate> {
match *ps.interner.get(attr_name) {
~"std" | ~"core" => (),
_ => vec::push(e.deps, query)
_ => e.deps.push(query)
}
}
_ => ()
@ -375,7 +369,7 @@ fn load_crate(filename: &Path) -> Option<crate> {
match (name, vers, uuid) {
(Some(name0), Some(vers0), Some(uuid0)) => {
Some({
Some(Crate {
name: name0,
vers: vers0,
uuid: uuid0,
@ -407,8 +401,8 @@ fn need_dir(s: &Path) {
}
}
fn valid_pkg_name(s: ~str) -> bool {
fn is_valid_digit(c: char) -> bool {
fn valid_pkg_name(s: &str) -> bool {
fn is_valid_digit(+c: char) -> bool {
('0' <= c && c <= '9') ||
('a' <= c && c <= 'z') ||
('A' <= c && c <= 'Z') ||
@ -419,33 +413,33 @@ fn valid_pkg_name(s: ~str) -> bool {
s.all(is_valid_digit)
}
fn parse_source(name: ~str, j: json::Json) -> source {
fn parse_source(name: ~str, j: &json::Json) -> @Source {
if !valid_pkg_name(name) {
fail fmt!("'%s' is an invalid source name", name);
}
match j {
json::Dict(j) => {
let mut url = match j.find(~"url") {
Some(json::String(u)) => *u,
match *j {
json::Object(j) => {
let mut url = match j.find(&~"url") {
Some(json::String(u)) => u,
_ => fail ~"needed 'url' field in source"
};
let method = match j.find(~"method") {
Some(json::String(u)) => *u,
let method = match j.find(&~"method") {
Some(json::String(u)) => u,
_ => assume_source_method(url)
};
let key = match j.find(~"key") {
Some(json::String(u)) => Some(*u),
let key = match j.find(&~"key") {
Some(json::String(u)) => Some(u),
_ => None
};
let keyfp = match j.find(~"keyfp") {
Some(json::String(u)) => Some(*u),
let keyfp = match j.find(&~"keyfp") {
Some(json::String(u)) => Some(u),
_ => None
};
if method == ~"file" {
url = os::make_absolute(&Path(url)).to_str();
}
return @{
return @Source {
name: name,
mut url: url,
mut method: method,
@ -457,14 +451,14 @@ fn parse_source(name: ~str, j: json::Json) -> source {
};
}
fn try_parse_sources(filename: &Path, sources: map::HashMap<~str, source>) {
fn try_parse_sources(filename: &Path, sources: map::HashMap<~str, @Source>) {
if !os::path_exists(filename) { return; }
let c = io::read_whole_file_str(filename);
match json::from_str(result::get(c)) {
Ok(json::Dict(j)) => {
for j.each |k, v| {
sources.insert(k, parse_source(k, v));
debug!("source: %s", k);
match json::from_str(c.get()) {
Ok(json::Object(j)) => {
for j.each |k, v| {
sources.insert(copy *k, parse_source(*k, v));
debug!("source: %s", *k);
}
}
Ok(_) => fail ~"malformed sources.json",
@ -472,17 +466,17 @@ fn try_parse_sources(filename: &Path, sources: map::HashMap<~str, source>) {
}
}
fn load_one_source_package(src: source, p: map::HashMap<~str, json::Json>) {
let name = match p.find(~"name") {
fn load_one_source_package(src: @Source, p: &json::Object) {
let name = match p.find(&~"name") {
Some(json::String(n)) => {
if !valid_pkg_name(*n) {
if !valid_pkg_name(n) {
warn(~"malformed source json: "
+ src.name + ~", '" + *n + ~"'"+
+ src.name + ~", '" + n + ~"'"+
~" is an invalid name (alphanumeric, underscores and" +
~" dashes only)");
return;
}
*n
n
}
_ => {
warn(~"malformed source json: " + src.name + ~" (missing name)");
@ -490,15 +484,15 @@ fn load_one_source_package(src: source, p: map::HashMap<~str, json::Json>) {
}
};
let uuid = match p.find(~"uuid") {
let uuid = match p.find(&~"uuid") {
Some(json::String(n)) => {
if !is_uuid(*n) {
if !is_uuid(n) {
warn(~"malformed source json: "
+ src.name + ~", '" + *n + ~"'"+
+ src.name + ~", '" + n + ~"'"+
~" is an invalid uuid");
return;
}
*n
n
}
_ => {
warn(~"malformed source json: " + src.name + ~" (missing uuid)");
@ -506,16 +500,16 @@ fn load_one_source_package(src: source, p: map::HashMap<~str, json::Json>) {
}
};
let url = match p.find(~"url") {
Some(json::String(n)) => *n,
let url = match p.find(&~"url") {
Some(json::String(n)) => n,
_ => {
warn(~"malformed source json: " + src.name + ~" (missing url)");
return;
}
};
let method = match p.find(~"method") {
Some(json::String(n)) => *n,
let method = match p.find(&~"method") {
Some(json::String(n)) => n,
_ => {
warn(~"malformed source json: "
+ src.name + ~" (missing method)");
@ -523,17 +517,17 @@ fn load_one_source_package(src: source, p: map::HashMap<~str, json::Json>) {
}
};
let reference = match p.find(~"ref") {
Some(json::String(n)) => Some(*n),
let reference = match p.find(&~"ref") {
Some(json::String(n)) => Some(n),
_ => None
};
let mut tags = ~[];
match p.find(~"tags") {
match p.find(&~"tags") {
Some(json::List(js)) => {
for (*js).each |j| {
for js.each |j| {
match *j {
json::String(j) => vec::grow(tags, 1u, *j),
json::String(ref j) => tags.grow(1u, j),
_ => ()
}
}
@ -541,8 +535,8 @@ fn load_one_source_package(src: source, p: map::HashMap<~str, json::Json>) {
_ => ()
}
let description = match p.find(~"description") {
Some(json::String(n)) => *n,
let description = match p.find(&~"description") {
Some(json::String(n)) => n,
_ => {
warn(~"malformed source json: " + src.name
+ ~" (missing description)");
@ -550,7 +544,7 @@ fn load_one_source_package(src: source, p: map::HashMap<~str, json::Json>) {
}
};
let newpkg = {
let newpkg = Package {
name: name,
uuid: uuid,
url: url,
@ -574,14 +568,14 @@ fn load_one_source_package(src: source, p: map::HashMap<~str, json::Json>) {
log(debug, ~" loaded package: " + src.name + ~"/" + name);
}
fn load_source_info(c: &cargo, src: source) {
fn load_source_info(c: &Cargo, src: @Source) {
let dir = c.sourcedir.push(src.name);
let srcfile = dir.push("source.json");
if !os::path_exists(&srcfile) { return; }
let srcstr = io::read_whole_file_str(&srcfile);
match json::from_str(result::get(srcstr)) {
Ok(json::Dict(s)) => {
let o = parse_source(src.name, json::Dict(s));
match json::from_str(srcstr.get()) {
Ok(ref json @ json::Object(_)) => {
let o = parse_source(src.name, json);
src.key = o.key;
src.keyfp = o.keyfp;
@ -595,17 +589,17 @@ fn load_source_info(c: &cargo, src: source) {
}
};
}
fn load_source_packages(c: &cargo, src: source) {
fn load_source_packages(c: &Cargo, src: @Source) {
log(debug, ~"loading source: " + src.name);
let dir = c.sourcedir.push(src.name);
let pkgfile = dir.push("packages.json");
if !os::path_exists(&pkgfile) { return; }
let pkgstr = io::read_whole_file_str(&pkgfile);
match json::from_str(result::get(pkgstr)) {
match json::from_str(pkgstr.get()) {
Ok(json::List(js)) => {
for (*js).each |j| {
for js.each |j| {
match *j {
json::Dict(p) => {
json::Object(p) => {
load_one_source_package(src, p);
}
_ => {
@ -625,7 +619,7 @@ fn load_source_packages(c: &cargo, src: source) {
};
}
fn build_cargo_options(argv: ~[~str]) -> options {
fn build_cargo_options(argv: ~[~str]) -> Options {
let matches = match getopts::getopts(argv, opts()) {
result::Ok(m) => m,
result::Err(f) => {
@ -649,34 +643,34 @@ fn build_cargo_options(argv: ~[~str]) -> options {
}
let mode =
if (!is_install && !is_uninstall) || g { user_mode }
else if G { system_mode }
else { local_mode };
if (!is_install && !is_uninstall) || g { UserMode }
else if G { SystemMode }
else { LocalMode };
{test: test, mode: mode, free: matches.free, help: help}
Options {test: test, mode: mode, free: matches.free, help: help}
}
fn configure(opts: options) -> cargo {
fn configure(opts: Options) -> Cargo {
let home = match get_cargo_root() {
Ok(home) => home,
Err(_err) => result::get(get_cargo_sysroot())
Err(_err) => get_cargo_sysroot().get()
};
let get_cargo_dir = match opts.mode {
system_mode => get_cargo_sysroot,
user_mode => get_cargo_root,
local_mode => get_cargo_root_nearest
SystemMode => get_cargo_sysroot,
UserMode => get_cargo_root,
LocalMode => get_cargo_root_nearest
};
let p = result::get(get_cargo_dir());
let p = get_cargo_dir().get();
let sources = map::HashMap();
let sources = HashMap();
try_parse_sources(&home.push("sources.json"), sources);
try_parse_sources(&home.push("local-sources.json"), sources);
let dep_cache = map::HashMap();
let dep_cache = HashMap();
let mut c = {
let mut c = Cargo {
pgp: pgp::supported(),
root: home,
installdir: p,
@ -714,10 +708,10 @@ fn configure(opts: options) -> cargo {
c
}
fn for_each_package(c: &cargo, b: fn(source, package)) {
fn for_each_package(c: &Cargo, b: fn(s: @Source, p: &Package)) {
for c.sources.each_value |v| {
for v.packages.each |p| {
b(v, *p);
b(v, p);
}
}
}
@ -748,7 +742,7 @@ fn run_in_buildpath(what: &str, path: &Path, subdir: &Path, cf: &Path,
Some(buildpath)
}
fn test_one_crate(_c: &cargo, path: &Path, cf: &Path) {
fn test_one_crate(_c: &Cargo, path: &Path, cf: &Path) {
let buildpath = match run_in_buildpath(~"testing", path,
&Path("test"),
cf,
@ -759,7 +753,7 @@ fn test_one_crate(_c: &cargo, path: &Path, cf: &Path) {
run_programs(&buildpath);
}
fn install_one_crate(c: &cargo, path: &Path, cf: &Path) {
fn install_one_crate(c: &Cargo, path: &Path, cf: &Path) {
let buildpath = match run_in_buildpath(~"installing", path,
&Path("build"),
cf, ~[]) {
@ -776,7 +770,7 @@ fn install_one_crate(c: &cargo, path: &Path, cf: &Path) {
~"lib")) {
debug!(" bin: %s", ct.to_str());
install_to_dir(*ct, &c.bindir);
if c.opts.mode == system_mode {
if c.opts.mode == SystemMode {
// FIXME (#2662): Put this file in PATH / symlink it so it can
// be used as a generic executable
// `cargo install -G rustray` and `rustray file.obj`
@ -800,14 +794,14 @@ fn rustc_sysroot() -> ~str {
}
}
fn install_source(c: &cargo, path: &Path) {
fn install_source(c: &Cargo, path: &Path) {
debug!("source: %s", path.to_str());
os::change_dir(path);
let mut cratefiles = ~[];
for os::walk_dir(&Path(".")) |p| {
if p.filetype() == Some(~".rc") {
vec::push(cratefiles, *p);
cratefiles.push(*p);
}
}
@ -839,7 +833,7 @@ fn install_source(c: &cargo, path: &Path) {
}
}
fn install_git(c: &cargo, wd: &Path, url: ~str, reference: Option<~str>) {
fn install_git(c: &Cargo, wd: &Path, url: ~str, reference: Option<~str>) {
run::program_output(~"git", ~[~"clone", url, wd.to_str()]);
if reference.is_some() {
let r = reference.get();
@ -850,7 +844,7 @@ fn install_git(c: &cargo, wd: &Path, url: ~str, reference: Option<~str>) {
install_source(c, wd);
}
fn install_curl(c: &cargo, wd: &Path, url: ~str) {
fn install_curl(c: &Cargo, wd: &Path, url: ~str) {
let tarpath = wd.push("pkg.tar");
let p = run::program_output(~"curl", ~[~"-f", ~"-s", ~"-o",
tarpath.to_str(), url]);
@ -863,14 +857,14 @@ fn install_curl(c: &cargo, wd: &Path, url: ~str) {
install_source(c, wd);
}
fn install_file(c: &cargo, wd: &Path, path: &Path) {
fn install_file(c: &Cargo, wd: &Path, path: &Path) {
run::program_output(~"tar", ~[~"-x", ~"--strip-components=1",
~"-C", wd.to_str(),
~"-f", path.to_str()]);
install_source(c, wd);
}
fn install_package(c: &cargo, src: ~str, wd: &Path, pkg: package) {
fn install_package(c: &Cargo, src: ~str, wd: &Path, pkg: Package) {
let url = copy pkg.url;
let method = match pkg.method {
~"git" => ~"git",
@ -883,12 +877,12 @@ fn install_package(c: &cargo, src: ~str, wd: &Path, pkg: package) {
match method {
~"git" => install_git(c, wd, url, copy pkg.reference),
~"file" => install_file(c, wd, &Path(url)),
~"curl" => install_curl(c, wd, copy url),
~"curl" => install_curl(c, wd, url),
_ => ()
}
}
fn cargo_suggestion(c: &cargo, fallback: fn())
fn cargo_suggestion(c: &Cargo, fallback: fn())
{
if c.sources.size() == 0u {
error(~"no sources defined - you may wish to run " +
@ -898,11 +892,11 @@ fn cargo_suggestion(c: &cargo, fallback: fn())
fallback();
}
fn install_uuid(c: &cargo, wd: &Path, uuid: ~str) {
fn install_uuid(c: &Cargo, wd: &Path, uuid: ~str) {
let mut ps = ~[];
for_each_package(c, |s, p| {
if p.uuid == uuid {
vec::grow(ps, 1u, (s.name, copy p));
vec::push(&mut ps, (s.name, copy *p));
}
});
if vec::len(ps) == 1u {
@ -922,11 +916,11 @@ fn install_uuid(c: &cargo, wd: &Path, uuid: ~str) {
}
}
fn install_named(c: &cargo, wd: &Path, name: ~str) {
fn install_named(c: &Cargo, wd: &Path, name: ~str) {
let mut ps = ~[];
for_each_package(c, |s, p| {
if p.name == name {
vec::grow(ps, 1u, (s.name, copy p));
vec::push(&mut ps, (s.name, copy *p));
}
});
if vec::len(ps) == 1u {
@ -946,7 +940,7 @@ fn install_named(c: &cargo, wd: &Path, name: ~str) {
}
}
fn install_uuid_specific(c: &cargo, wd: &Path, src: ~str, uuid: ~str) {
fn install_uuid_specific(c: &Cargo, wd: &Path, src: ~str, uuid: ~str) {
match c.sources.find(src) {
Some(s) => {
for s.packages.each |p| {
@ -961,7 +955,7 @@ fn install_uuid_specific(c: &cargo, wd: &Path, src: ~str, uuid: ~str) {
error(~"can't find package: " + src + ~"/" + uuid);
}
fn install_named_specific(c: &cargo, wd: &Path, src: ~str, name: ~str) {
fn install_named_specific(c: &Cargo, wd: &Path, src: ~str, name: ~str) {
match c.sources.find(src) {
Some(s) => {
for s.packages.each |p| {
@ -976,7 +970,7 @@ fn install_named_specific(c: &cargo, wd: &Path, src: ~str, name: ~str) {
error(~"can't find package: " + src + ~"/" + name);
}
fn cmd_uninstall(c: &cargo) {
fn cmd_uninstall(c: &Cargo) {
if vec::len(c.opts.free) < 3u {
cmd_usage();
return;
@ -1028,7 +1022,7 @@ fn cmd_uninstall(c: &cargo) {
}
}
fn install_query(c: &cargo, wd: &Path, target: ~str) {
fn install_query(c: &Cargo, wd: &Path, target: ~str) {
match c.dep_cache.find(target) {
Some(inst) => {
if inst {
@ -1088,7 +1082,7 @@ fn install_query(c: &cargo, wd: &Path, target: ~str) {
}
}
fn get_temp_workdir(c: &cargo) -> Path {
fn get_temp_workdir(c: &Cargo) -> Path {
match tempfile::mkdtemp(&c.workdir, "cargo") {
Some(wd) => wd,
None => fail fmt!("needed temp dir: %s",
@ -1096,7 +1090,7 @@ fn get_temp_workdir(c: &cargo) -> Path {
}
}
fn cmd_install(c: &cargo) unsafe {
fn cmd_install(c: &Cargo) unsafe {
let wd = get_temp_workdir(c);
if vec::len(c.opts.free) == 2u {
@ -1120,7 +1114,7 @@ fn cmd_install(c: &cargo) unsafe {
install_query(c, &wd, query);
}
fn sync(c: &cargo) {
fn sync(c: &Cargo) {
for c.sources.each_key |k| {
let mut s = c.sources.get(k);
sync_one(c, s);
@ -1128,7 +1122,7 @@ fn sync(c: &cargo) {
}
}
fn sync_one_file(c: &cargo, dir: &Path, src: source) -> bool {
fn sync_one_file(c: &Cargo, dir: &Path, src: @Source) -> bool {
let name = src.name;
let srcfile = dir.push("source.json.new");
let destsrcfile = dir.push("source.json");
@ -1206,7 +1200,7 @@ fn sync_one_file(c: &cargo, dir: &Path, src: source) -> bool {
return true;
}
fn sync_one_git(c: &cargo, dir: &Path, src: source) -> bool {
fn sync_one_git(c: &Cargo, dir: &Path, src: @Source) -> bool {
let name = src.name;
let srcfile = dir.push("source.json");
let pkgfile = dir.push("packages.json");
@ -1309,7 +1303,7 @@ fn sync_one_git(c: &cargo, dir: &Path, src: source) -> bool {
return true;
}
fn sync_one_curl(c: &cargo, dir: &Path, src: source) -> bool {
fn sync_one_curl(c: &Cargo, dir: &Path, src: @Source) -> bool {
let name = src.name;
let srcfile = dir.push("source.json.new");
let destsrcfile = dir.push("source.json");
@ -1425,7 +1419,7 @@ fn sync_one_curl(c: &cargo, dir: &Path, src: source) -> bool {
return true;
}
fn sync_one(c: &cargo, src: source) {
fn sync_one(c: &Cargo, src: @Source) {
let name = src.name;
let dir = c.sourcedir.push(name);
@ -1445,7 +1439,7 @@ fn sync_one(c: &cargo, src: source) {
}
}
fn cmd_init(c: &cargo) {
fn cmd_init(c: &Cargo) {
let srcurl = ~"http://www.rust-lang.org/cargo/sources.json";
let sigurl = ~"http://www.rust-lang.org/cargo/sources.json.sig";
@ -1484,7 +1478,7 @@ fn cmd_init(c: &cargo) {
info(fmt!("initialized .cargo in %s", c.root.to_str()));
}
fn print_pkg(s: source, p: package) {
fn print_pkg(s: @Source, p: &Package) {
let mut m = s.name + ~"/" + p.name + ~" (" + p.uuid + ~")";
if vec::len(p.tags) > 0u {
m = m + ~" [" + str::connect(p.tags, ~", ") + ~"]";
@ -1495,7 +1489,7 @@ fn print_pkg(s: source, p: package) {
}
}
fn print_source(s: source) {
fn print_source(s: @Source) {
info(s.name + ~" (" + s.url + ~")");
let pks = sort::merge_sort(s.packages.get(), sys::shape_lt);
@ -1516,7 +1510,7 @@ fn print_source(s: source) {
}));
}
fn cmd_list(c: &cargo) {
fn cmd_list(c: &Cargo) {
sync(c);
if vec::len(c.opts.free) >= 3u {
@ -1542,7 +1536,7 @@ fn cmd_list(c: &cargo) {
}
}
fn cmd_search(c: &cargo) {
fn cmd_search(c: &Cargo) {
if vec::len(c.opts.free) < 3u {
cmd_usage();
return;
@ -1575,17 +1569,17 @@ fn install_to_dir(srcfile: &Path, destdir: &Path) {
}
}
fn dump_cache(c: &cargo) {
fn dump_cache(c: &Cargo) {
need_dir(&c.root);
let out = c.root.push("cache.json");
let _root = json::Dict(map::HashMap());
let _root = json::Object(~LinearMap());
if os::path_exists(&out) {
copy_warn(&out, &c.root.push("cache.json.old"));
}
}
fn dump_sources(c: &cargo) {
fn dump_sources(c: &Cargo) {
if c.sources.size() < 1u {
return;
}
@ -1600,33 +1594,31 @@ fn dump_sources(c: &cargo) {
match io::buffered_file_writer(&out) {
result::Ok(writer) => {
let hash = map::HashMap();
let root = json::Dict(hash);
let mut hash = ~LinearMap();
for c.sources.each |k, v| {
let chash = map::HashMap();
let child = json::Dict(chash);
for c.sources.each |k, v| {
let mut chash = ~LinearMap();
chash.insert(~"url", json::String(@v.url));
chash.insert(~"method", json::String(@v.method));
chash.insert(~"url", json::String(v.url));
chash.insert(~"method", json::String(v.method));
match copy v.key {
Some(key) => {
chash.insert(~"key", json::String(@key));
chash.insert(~"key", json::String(copy key));
}
_ => ()
}
match copy v.keyfp {
Some(keyfp) => {
chash.insert(~"keyfp", json::String(@keyfp));
chash.insert(~"keyfp", json::String(copy keyfp));
}
_ => ()
}
hash.insert(k, child);
hash.insert(copy k, json::Object(chash));
}
writer.write_str(json::to_str(root));
json::to_writer(writer, &json::Object(hash))
}
result::Err(e) => {
error(fmt!("could not dump sources: %s", e));
@ -1641,7 +1633,7 @@ fn copy_warn(srcfile: &Path, destfile: &Path) {
}
}
fn cmd_sources(c: &cargo) {
fn cmd_sources(c: &Cargo) {
if vec::len(c.opts.free) < 3u {
for c.sources.each_value |v| {
info(fmt!("%s (%s) via %s",
@ -1677,7 +1669,7 @@ fn cmd_sources(c: &cargo) {
if c.sources.contains_key(name) {
error(fmt!("source already exists: %s", name));
} else {
c.sources.insert(name, @{
c.sources.insert(name, @Source {
name: name,
mut url: url,
mut method: assume_source_method(url),

View file

@ -5,6 +5,8 @@
#[allow(vecs_implicitly_copyable)];
#[allow(non_camel_case_types)];
#[allow(deprecated_mode)];
#[allow(deprecated_pattern)];
extern mod core(vers = "0.4");
extern mod std(vers = "0.4");

View file

@ -58,7 +58,7 @@ fn parse_config(args: ~[~str]) -> config {
} else { option::None },
logfile: option::map(&getopts::opt_maybe_str(matches,
~"logfile"),
|s| Path(s)),
|s| Path(*s)),
runtool: getopts::opt_maybe_str(matches, ~"runtool"),
rustcflags: getopts::opt_maybe_str(matches, ~"rustcflags"),
jit: getopts::opt_present(matches, ~"jit"),
@ -141,7 +141,7 @@ fn make_tests(config: config) -> ~[test::TestDesc] {
let file = copy *file;
debug!("inspecting file %s", file.to_str());
if is_test(config, file) {
vec::push(tests, make_test(config, file))
tests.push(make_test(config, file))
}
}
return tests;

View file

@ -9,7 +9,7 @@ type expected_error = { line: uint, kind: ~str, msg: ~str };
// Load any test directives embedded in the file
fn load_errors(testfile: &Path) -> ~[expected_error] {
let mut error_patterns = ~[];
let rdr = result::get(io::file_reader(testfile));
let rdr = io::file_reader(testfile).get();
let mut line_num = 1u;
while !rdr.eof() {
let ln = rdr.read_line();

View file

@ -28,7 +28,7 @@ fn load_props(testfile: &Path) -> test_props {
let mut pp_exact = option::None;
for iter_header(testfile) |ln| {
match parse_error_pattern(ln) {
option::Some(ep) => vec::push(error_patterns, ep),
option::Some(ep) => error_patterns.push(ep),
option::None => ()
};
@ -41,11 +41,11 @@ fn load_props(testfile: &Path) -> test_props {
}
do parse_aux_build(ln).iter |ab| {
vec::push(aux_builds, ab);
aux_builds.push(*ab);
}
do parse_exec_env(ln).iter |ee| {
vec::push(exec_env, ee);
exec_env.push(*ee);
}
};
return {
@ -73,7 +73,7 @@ fn is_test_ignored(config: config, testfile: &Path) -> bool {
}
fn iter_header(testfile: &Path, it: fn(~str) -> bool) -> bool {
let rdr = result::get(io::file_reader(testfile));
let rdr = io::file_reader(testfile).get();
while !rdr.eof() {
let ln = rdr.read_line();
@ -103,7 +103,7 @@ fn parse_compile_flags(line: ~str) -> Option<~str> {
fn parse_exec_env(line: ~str) -> Option<(~str, ~str)> {
do parse_name_value_directive(line, ~"exec-env").map |nv| {
// nv is either FOO or FOO=BAR
let strs = str::splitn_char(nv, '=', 1u);
let strs = str::splitn_char(*nv, '=', 1u);
match strs.len() {
1u => (strs[0], ~""),
2u => (strs[0], strs[1]),

View file

@ -14,12 +14,12 @@ fn target_env(lib_path: ~str, prog: ~str) -> ~[(~str,~str)] {
let aux_path = prog.slice(0u, prog.len() - 4u) + ~".libaux";
env = do vec::map(env) |pair| {
let (k,v) = pair;
let (k,v) = *pair;
if k == ~"PATH" { (~"PATH", v + ~";" + lib_path + ~";" + aux_path) }
else { (k,v) }
};
if str::ends_with(prog, ~"rustc.exe") {
vec::push(env, (~"RUST_THREADS", ~"1"));
env.push((~"RUST_THREADS", ~"1"));
}
return env;
}

View file

@ -109,7 +109,7 @@ fn run_pretty_test(config: config, props: test_props, testfile: &Path) {
let rounds =
match props.pp_exact { option::Some(_) => 1, option::None => 2 };
let mut srcs = ~[result::get(io::read_whole_file_str(testfile))];
let mut srcs = ~[io::read_whole_file_str(testfile).get()];
let mut round = 0;
while round < rounds {
@ -121,7 +121,7 @@ fn run_pretty_test(config: config, props: test_props, testfile: &Path) {
procres);
}
vec::push(srcs, procres.stdout);
srcs.push(procres.stdout);
round += 1;
}
@ -129,7 +129,7 @@ fn run_pretty_test(config: config, props: test_props, testfile: &Path) {
match props.pp_exact {
option::Some(file) => {
let filepath = testfile.dir_path().push_rel(&file);
result::get(io::read_whole_file_str(&filepath))
io::read_whole_file_str(&filepath).get()
}
option::None => { srcs[vec::len(srcs) - 2u] }
};
@ -503,10 +503,7 @@ fn make_run_args(config: config, _props: test_props, testfile: &Path) ->
fn split_maybe_args(argstr: Option<~str>) -> ~[~str] {
fn rm_whitespace(v: ~[~str]) -> ~[~str] {
fn flt(&&s: ~str) -> Option<~str> {
if !str::is_whitespace(s) { option::Some(s) } else { option::None }
}
vec::filter_map(v, flt)
vec::filter(v, |s| !str::is_whitespace(*s))
}
match argstr {
@ -561,8 +558,8 @@ fn dump_output(config: config, testfile: &Path, out: ~str, err: ~str) {
fn dump_output_file(config: config, testfile: &Path,
out: ~str, extension: ~str) {
let outfile = make_out_name(config, testfile, extension);
let writer = result::get(
io::file_writer(&outfile, ~[io::Create, io::Truncate]));
let writer =
io::file_writer(&outfile, ~[io::Create, io::Truncate]).get();
writer.write_str(out);
}

View file

@ -30,7 +30,7 @@ for t in os.listdir(run_pass):
"xfail-fast" in s or
"xfail-win32" in s):
stage2_tests.append(t)
if "main(args: ~[~str])" in s:
if "fn main(args:" in s or "fn main(++args:" in s:
take_args[t] = True
f.close()
@ -39,11 +39,13 @@ stage2_tests.sort()
c = open("tmp/run_pass_stage2.rc", "w")
i = 0
c.write("// AUTO-GENERATED FILE: DO NOT EDIT\n")
c.write("#[legacy_exports];\n")
c.write("#[link(name=\"run_pass_stage2\", vers=\"0.1\")];\n")
for t in stage2_tests:
p = os.path.join(run_pass, t)
p = p.replace("\\", "\\\\")
c.write("#[path = \"%s\"]" % p);
c.write("#[legacy_exports]");
c.write("mod t_%d;\n" % i)
i += 1
c.close()

View file

@ -70,7 +70,7 @@
"let" "log" "loop"
"move" "new"
"pure" "pub" "priv"
"return" "static"
"ref" "return" "static"
"unchecked" "unsafe"
"while"))
(puthash word t table))

View file

@ -62,7 +62,7 @@ fn test_cycles(r : rand::rng, k: uint, n: uint)
// Create a graph with no edges
range(0u, vlen) {|_i|
vec::push(v, empty_pointy());
v.push(empty_pointy());
}
// Fill in the graph with random edges, with density k/n
@ -77,7 +77,7 @@ fn test_cycles(r : rand::rng, k: uint, n: uint)
// https://github.com/mozilla/rust/issues/1899
if (likelihood(r, k, n)) { v[i].m = [p(choice(r, v))]; }
if (likelihood(r, k, n)) { vec::push(v[i].n, mut p(choice(r, v))); }
if (likelihood(r, k, n)) { v[i].n.push(mut p(choice(r, v))); }
if (likelihood(r, k, n)) { v[i].o = {x: 0, y: p(choice(r, v))}; }
}

View file

@ -9,6 +9,8 @@
#[allow(vecs_implicitly_copyable)];
#[allow(non_camel_case_types)];
#[allow(deprecated_mode)];
#[allow(deprecated_pattern)];
extern mod core(vers = "0.4");
extern mod std(vers = "0.4");

View file

@ -19,7 +19,7 @@ impl test_mode : cmp::Eq {
fn write_file(filename: &Path, content: ~str) {
result::get(
io::file_writer(filename, ~[io::Create, io::Truncate]))
&io::file_writer(filename, ~[io::Create, io::Truncate]))
.write_str(content);
}
@ -30,7 +30,7 @@ fn contains(haystack: ~str, needle: ~str) -> bool {
fn find_rust_files(files: &mut ~[Path], path: &Path) {
if path.filetype() == Some(~".rs") && !contains(path.to_str(), ~"utf8") {
// ignoring "utf8" tests because something is broken
vec::push(*files, *path);
files.push(*path);
} else if os::path_is_dir(path)
&& !contains(path.to_str(), ~"compile-fail")
&& !contains(path.to_str(), ~"build") {
@ -124,7 +124,7 @@ fn stash_ty_if(c: fn@(@ast::ty, test_mode)->bool,
e: @ast::ty,
tm: test_mode) {
if c(e, tm) {
vec::push(*es,*e);
es.push(*e);
} else {/* now my indices are wrong :( */ }
}
@ -221,7 +221,7 @@ fn under(n: uint, it: fn(uint)) {
while i < n { it(i); i += 1u; }
}
fn as_str(f: fn@(io::Writer)) -> ~str {
fn as_str(f: fn@(+x: io::Writer)) -> ~str {
io::with_str_writer(f)
}
@ -229,7 +229,7 @@ fn check_variants_of_ast(crate: ast::crate, codemap: codemap::codemap,
filename: &Path, cx: context) {
let stolen = steal(crate, cx.mode);
let extra_exprs = vec::filter(common_exprs(),
|a| safe_to_use_expr(a, cx.mode) );
|a| safe_to_use_expr(*a, cx.mode) );
check_variants_T(crate, codemap, filename, ~"expr",
extra_exprs + stolen.exprs, pprust::expr_to_str,
replace_expr_in_crate, cx);
@ -243,7 +243,7 @@ fn check_variants_T<T: Copy>(
filename: &Path,
thing_label: ~str,
things: ~[T],
stringifier: fn@(@T, syntax::parse::token::ident_interner) -> ~str,
stringifier: fn@(@T, @syntax::parse::token::ident_interner) -> ~str,
replacer: fn@(ast::crate, uint, T, test_mode) -> ast::crate,
cx: context
) {
@ -543,7 +543,7 @@ fn check_convergence(files: &[Path]) {
error!("pp convergence tests: %u files", vec::len(files));
for files.each |file| {
if !file_might_not_converge(file) {
let s = @result::get(io::read_whole_file_str(file));
let s = @result::get(&io::read_whole_file_str(file));
if !content_might_not_converge(*s) {
error!("pp converge: %s", file.to_str());
// Change from 7u to 2u once
@ -563,7 +563,7 @@ fn check_variants(files: &[Path], cx: context) {
loop;
}
let s = @result::get(io::read_whole_file_str(file));
let s = @result::get(&io::read_whole_file_str(file));
if contains(*s, ~"#") {
loop; // Macros are confusing
}

View file

@ -55,11 +55,11 @@ fn vec_edits<T: copy>(v: ~[T], xs: ~[T]) -> ~[~[T]] {
if Lv != 1u {
// When Lv == 1u, this is redundant with omit.
vec::push(edits, ~[]);
edits.push(~[]);
}
if Lv >= 3u {
// When Lv == 2u, this is redundant with swap.
vec::push(edits, vec::reversed(v));
edits.push(vec::reversed(v));
}
ix(0u, 1u, Lv) {|i| edits += ~[vec_omit(v, i)]; }
ix(0u, 1u, Lv) {|i| edits += ~[vec_dup(v, i)]; }
@ -69,10 +69,10 @@ fn vec_edits<T: copy>(v: ~[T], xs: ~[T]) -> ~[~[T]] {
ix(0u, 1u, len(xs)) {|j|
ix(0u, 1u, Lv) {|i|
vec::push(edits, vec_poke(v, i, xs[j]));
edits.push(vec_poke(v, i, xs[j]));
}
ix(0u, 0u, Lv) {|i|
vec::push(edits, vec_insert(v, i, xs[j]));
edits.push(vec_insert(v, i, xs[j]));
}
}

View file

@ -61,7 +61,7 @@ fn weighted_vec<T: copy>(v : ~[weighted<T>]) -> ~[T] {
for {weight: weight, item: item} in v {
let i = 0u;
while i < weight {
vec::push(r, item);
r.push(item);
i += 1u;
}
}

View file

@ -1,14 +1,11 @@
//! Managed vectors
use ptr::addr_of;
// NB: transitionary, de-mode-ing.
// tjc: re-forbid deprecated modes after snapshot
#[forbid(deprecated_pattern)];
export init_op;
export capacity;
export build_sized, build, build_sized_opt;
export map;
export from_fn, from_elem;
export raw;
export traits;
use cast::transmute;
use ptr::addr_of;
/// Code for dealing with @-vectors. This is pretty incomplete, and
/// contains a bunch of duplication from the code for ~-vectors.
@ -29,10 +26,10 @@ extern mod rusti {
/// Returns the number of elements the vector can hold without reallocating
#[inline(always)]
pure fn capacity<T>(&&v: @[const T]) -> uint {
pub pure fn capacity<T>(v: @[const T]) -> uint {
unsafe {
let repr: **raw::VecRepr =
::cast::reinterpret_cast(&addr_of(v));
::cast::reinterpret_cast(&addr_of(&v));
(**repr).unboxed.alloc / sys::size_of::<T>()
}
}
@ -50,12 +47,12 @@ pure fn capacity<T>(&&v: @[const T]) -> uint {
* onto the vector being constructed.
*/
#[inline(always)]
pure fn build_sized<A>(size: uint,
builder: fn(push: pure fn(+v: A))) -> @[A] {
let mut vec = @[];
unsafe { raw::reserve(vec, size); }
builder(|+x| unsafe { raw::push(vec, move x) });
return vec;
pub pure fn build_sized<A>(size: uint,
builder: &fn(push: pure fn(v: A))) -> @[A] {
let mut vec: @[const A] = @[];
unsafe { raw::reserve(&mut vec, size); }
builder(|+x| unsafe { raw::push(&mut vec, move x) });
return unsafe { transmute(vec) };
}
/**
@ -69,7 +66,7 @@ pure fn build_sized<A>(size: uint,
* onto the vector being constructed.
*/
#[inline(always)]
pure fn build<A>(builder: fn(push: pure fn(+v: A))) -> @[A] {
pub pure fn build<A>(builder: &fn(push: pure fn(v: A))) -> @[A] {
build_sized(4, builder)
}
@ -86,14 +83,14 @@ pure fn build<A>(builder: fn(push: pure fn(+v: A))) -> @[A] {
* onto the vector being constructed.
*/
#[inline(always)]
pure fn build_sized_opt<A>(size: Option<uint>,
builder: fn(push: pure fn(+v: A))) -> @[A] {
pub pure fn build_sized_opt<A>(size: Option<uint>,
builder: &fn(push: pure fn(v: A))) -> @[A] {
build_sized(size.get_default(4), builder)
}
// Appending
#[inline(always)]
pure fn append<T: Copy>(lhs: @[T], rhs: &[const T]) -> @[T] {
pub pure fn append<T: Copy>(lhs: @[T], rhs: &[const T]) -> @[T] {
do build_sized(lhs.len() + rhs.len()) |push| {
for vec::each(lhs) |x| { push(*x); }
for uint::range(0, rhs.len()) |i| { push(rhs[i]); }
@ -102,10 +99,10 @@ pure fn append<T: Copy>(lhs: @[T], rhs: &[const T]) -> @[T] {
/// Apply a function to each element of a vector and return the results
pure fn map<T, U>(v: &[T], f: fn(T) -> U) -> @[U] {
pub pure fn map<T, U>(v: &[T], f: &fn(x: &T) -> U) -> @[U] {
do build_sized(v.len()) |push| {
for vec::each(v) |elem| {
push(f(*elem));
push(f(elem));
}
}
}
@ -116,7 +113,7 @@ pure fn map<T, U>(v: &[T], f: fn(T) -> U) -> @[U] {
* Creates an immutable vector of size `n_elts` and initializes the elements
* to the value returned by the function `op`.
*/
pure fn from_fn<T>(n_elts: uint, op: iter::InitOp<T>) -> @[T] {
pub pure fn from_fn<T>(n_elts: uint, op: iter::InitOp<T>) -> @[T] {
do build_sized(n_elts) |push| {
let mut i: uint = 0u;
while i < n_elts { push(op(i)); i += 1u; }
@ -129,17 +126,17 @@ pure fn from_fn<T>(n_elts: uint, op: iter::InitOp<T>) -> @[T] {
* Creates an immutable vector of size `n_elts` and initializes the elements
* to the value `t`.
*/
pure fn from_elem<T: Copy>(n_elts: uint, t: T) -> @[T] {
pub pure fn from_elem<T: Copy>(n_elts: uint, t: T) -> @[T] {
do build_sized(n_elts) |push| {
let mut i: uint = 0u;
while i < n_elts { push(t); i += 1u; }
while i < n_elts { push(copy t); i += 1u; }
}
}
#[cfg(notest)]
mod traits {
pub mod traits {
#[legacy_exports];
impl<T: Copy> @[T] : Add<&[const T],@[T]> {
pub impl<T: Copy> @[T] : Add<&[const T],@[T]> {
#[inline(always)]
pure fn add(rhs: & &[const T]) -> @[T] {
append(self, (*rhs))
@ -148,13 +145,12 @@ mod traits {
}
#[cfg(test)]
mod traits {
pub mod traits {
#[legacy_exports];}
mod raw {
#[legacy_exports];
type VecRepr = vec::raw::VecRepr;
type SliceRepr = vec::raw::SliceRepr;
pub mod raw {
pub type VecRepr = vec::raw::VecRepr;
pub type SliceRepr = vec::raw::SliceRepr;
/**
* Sets the length of a vector
@ -164,14 +160,14 @@ mod raw {
* the vector is actually the specified size.
*/
#[inline(always)]
unsafe fn set_len<T>(&&v: @[const T], new_len: uint) {
let repr: **VecRepr = ::cast::reinterpret_cast(&addr_of(v));
pub unsafe fn set_len<T>(v: @[const T], new_len: uint) {
let repr: **VecRepr = ::cast::reinterpret_cast(&addr_of(&v));
(**repr).unboxed.fill = new_len * sys::size_of::<T>();
}
#[inline(always)]
unsafe fn push<T>(&v: @[const T], +initval: T) {
let repr: **VecRepr = ::cast::reinterpret_cast(&addr_of(v));
pub unsafe fn push<T>(v: &mut @[const T], initval: T) {
let repr: **VecRepr = ::cast::reinterpret_cast(&v);
let fill = (**repr).unboxed.fill;
if (**repr).unboxed.alloc > fill {
push_fast(v, move initval);
@ -182,16 +178,16 @@ mod raw {
}
// This doesn't bother to make sure we have space.
#[inline(always)] // really pretty please
unsafe fn push_fast<T>(&v: @[const T], +initval: T) {
let repr: **VecRepr = ::cast::reinterpret_cast(&addr_of(v));
pub unsafe fn push_fast<T>(v: &mut @[const T], initval: T) {
let repr: **VecRepr = ::cast::reinterpret_cast(&v);
let fill = (**repr).unboxed.fill;
(**repr).unboxed.fill += sys::size_of::<T>();
let p = ptr::addr_of((**repr).unboxed.data);
let p = addr_of(&((**repr).unboxed.data));
let p = ptr::offset(p, fill) as *mut T;
rusti::move_val_init(*p, move initval);
}
unsafe fn push_slow<T>(&v: @[const T], +initval: T) {
pub unsafe fn push_slow<T>(v: &mut @[const T], initval: T) {
reserve_at_least(v, v.len() + 1u);
push_fast(v, move initval);
}
@ -207,10 +203,10 @@ mod raw {
* * v - A vector
* * n - The number of elements to reserve space for
*/
unsafe fn reserve<T>(&v: @[const T], n: uint) {
pub unsafe fn reserve<T>(v: &mut @[const T], n: uint) {
// Only make the (slow) call into the runtime if we have to
if capacity(v) < n {
let ptr = addr_of(v) as **VecRepr;
if capacity(*v) < n {
let ptr: **VecRepr = transmute(copy v);
rustrt::vec_reserve_shared_actual(sys::get_type_desc::<T>(),
ptr, n as libc::size_t);
}
@ -231,14 +227,14 @@ mod raw {
* * v - A vector
* * n - The number of elements to reserve space for
*/
unsafe fn reserve_at_least<T>(&v: @[const T], n: uint) {
pub unsafe fn reserve_at_least<T>(v: &mut @[const T], n: uint) {
reserve(v, uint::next_power_of_two(n));
}
}
#[test]
fn test() {
pub fn test() {
// Some code that could use that, then:
fn seq_range(lo: uint, hi: uint) -> @[uint] {
do build |push| {
@ -254,7 +250,6 @@ fn test() {
}
#[test]
fn append_test() {
pub fn append_test() {
assert @[1,2,3] + @[4,5,6] == @[1,2,3,4,5,6];
}

View file

@ -8,43 +8,39 @@
use cmp::Eq;
export not, and, or, xor, implies;
export eq, ne, is_true, is_false;
export from_str, to_str, all_values, to_bit;
/// Negation / inverse
pure fn not(v: bool) -> bool { !v }
pub pure fn not(v: bool) -> bool { !v }
/// Conjunction
pure fn and(a: bool, b: bool) -> bool { a && b }
pub pure fn and(a: bool, b: bool) -> bool { a && b }
/// Disjunction
pure fn or(a: bool, b: bool) -> bool { a || b }
pub pure fn or(a: bool, b: bool) -> bool { a || b }
/**
* Exclusive or
*
* Identical to `or(and(a, not(b)), and(not(a), b))`
*/
pure fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) }
pub pure fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) }
/// Implication in the logic, i.e. from `a` follows `b`
pure fn implies(a: bool, b: bool) -> bool { !a || b }
pub pure fn implies(a: bool, b: bool) -> bool { !a || b }
/// true if truth values `a` and `b` are indistinguishable in the logic
pure fn eq(a: bool, b: bool) -> bool { a == b }
pub pure fn eq(a: bool, b: bool) -> bool { a == b }
/// true if truth values `a` and `b` are distinguishable in the logic
pure fn ne(a: bool, b: bool) -> bool { a != b }
pub pure fn ne(a: bool, b: bool) -> bool { a != b }
/// true if `v` represents truth in the logic
pure fn is_true(v: bool) -> bool { v }
pub pure fn is_true(v: bool) -> bool { v }
/// true if `v` represents falsehood in the logic
pure fn is_false(v: bool) -> bool { !v }
pub pure fn is_false(v: bool) -> bool { !v }
/// Parse logic value from `s`
pure fn from_str(s: &str) -> Option<bool> {
pub pure fn from_str(s: &str) -> Option<bool> {
if s == "true" {
Some(true)
} else if s == "false" {
@ -55,19 +51,19 @@ pure fn from_str(s: &str) -> Option<bool> {
}
/// Convert `v` into a string
pure fn to_str(v: bool) -> ~str { if v { ~"true" } else { ~"false" } }
pub pure fn to_str(v: bool) -> ~str { if v { ~"true" } else { ~"false" } }
/**
* Iterates over all truth values by passing them to `blk` in an unspecified
* order
*/
fn all_values(blk: fn(v: bool)) {
pub fn all_values(blk: fn(v: bool)) {
blk(true);
blk(false);
}
/// converts truth value to an 8 bit byte
pure fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } }
pub pure fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } }
impl bool : cmp::Eq {
pure fn eq(other: &bool) -> bool { self == (*other) }
@ -75,20 +71,20 @@ impl bool : cmp::Eq {
}
#[test]
fn test_bool_from_str() {
pub fn test_bool_from_str() {
do all_values |v| {
assert Some(v) == from_str(bool::to_str(v))
}
}
#[test]
fn test_bool_to_str() {
pub fn test_bool_to_str() {
assert to_str(false) == ~"false";
assert to_str(true) == ~"true";
}
#[test]
fn test_bool_to_bit() {
pub fn test_bool_to_bit() {
do all_values |v| {
assert to_bit(v) == if is_true(v) { 1u8 } else { 0u8 };
}

View file

@ -7,28 +7,24 @@
use cmp::{Eq, Ord};
use intrinsic::TyDesc;
export ptr_eq, raw;
mod raw {
#[legacy_exports];
struct BoxHeaderRepr {
pub mod raw {
pub struct BoxHeaderRepr {
ref_count: uint,
type_desc: *TyDesc,
prev: *BoxRepr,
next: *BoxRepr,
}
struct BoxRepr {
pub struct BoxRepr {
header: BoxHeaderRepr,
data: u8
}
}
pure fn ptr_eq<T>(a: @T, b: @T) -> bool {
pub pure fn ptr_eq<T>(a: @T, b: @T) -> bool {
//! Determine if two shared boxes point to the same object
unsafe { ptr::addr_of(*a) == ptr::addr_of(*b) }
unsafe { ptr::addr_of(&(*a)) == ptr::addr_of(&(*b)) }
}
impl<T:Eq> @const T : Eq {

View file

@ -1,21 +1,14 @@
//! Unsafe operations
export reinterpret_cast, forget, bump_box_refcount, transmute;
export transmute_mut, transmute_immut, transmute_region, transmute_mut_region;
export transmute_mut_unsafe, transmute_immut_unsafe;
export copy_lifetime, copy_lifetime_vec;
#[abi = "rust-intrinsic"]
extern mod rusti {
#[legacy_exports];
fn forget<T>(-x: T);
fn reinterpret_cast<T, U>(e: T) -> U;
fn reinterpret_cast<T, U>(&&e: T) -> U;
}
/// Casts the value at `src` to U. The two types must have the same length.
#[inline(always)]
unsafe fn reinterpret_cast<T, U>(src: &T) -> U {
pub unsafe fn reinterpret_cast<T, U>(src: &T) -> U {
rusti::reinterpret_cast(*src)
}
@ -28,7 +21,7 @@ unsafe fn reinterpret_cast<T, U>(src: &T) -> U {
* reinterpret_cast on managed pointer types.
*/
#[inline(always)]
unsafe fn forget<T>(-thing: T) { rusti::forget(move thing); }
pub unsafe fn forget<T>(thing: T) { rusti::forget(move thing); }
/**
* Force-increment the reference count on a shared box. If used
@ -36,7 +29,7 @@ unsafe fn forget<T>(-thing: T) { rusti::forget(move thing); }
* and/or reinterpret_cast when such calls would otherwise scramble a box's
* reference count
*/
unsafe fn bump_box_refcount<T>(+t: @T) { forget(move t); }
pub unsafe fn bump_box_refcount<T>(t: @T) { forget(move t); }
/**
* Transform a value of one type into a value of another type.
@ -47,7 +40,7 @@ unsafe fn bump_box_refcount<T>(+t: @T) { forget(move t); }
* assert transmute("L") == ~[76u8, 0u8];
*/
#[inline(always)]
unsafe fn transmute<L, G>(-thing: L) -> G {
pub unsafe fn transmute<L, G>(thing: L) -> G {
let newthing: G = reinterpret_cast(&thing);
forget(move thing);
move newthing
@ -55,39 +48,45 @@ unsafe fn transmute<L, G>(-thing: L) -> G {
/// Coerce an immutable reference to be mutable.
#[inline(always)]
unsafe fn transmute_mut<T>(+ptr: &a/T) -> &a/mut T { transmute(move ptr) }
pub unsafe fn transmute_mut<T>(ptr: &a/T) -> &a/mut T { transmute(move ptr) }
/// Coerce a mutable reference to be immutable.
#[inline(always)]
unsafe fn transmute_immut<T>(+ptr: &a/mut T) -> &a/T { transmute(move ptr) }
pub unsafe fn transmute_immut<T>(ptr: &a/mut T) -> &a/T {
transmute(move ptr)
}
/// Coerce a borrowed pointer to have an arbitrary associated region.
#[inline(always)]
unsafe fn transmute_region<T>(+ptr: &a/T) -> &b/T { transmute(move ptr) }
pub unsafe fn transmute_region<T>(ptr: &a/T) -> &b/T { transmute(move ptr) }
/// Coerce an immutable reference to be mutable.
#[inline(always)]
unsafe fn transmute_mut_unsafe<T>(+ptr: *const T) -> *mut T { transmute(ptr) }
pub unsafe fn transmute_mut_unsafe<T>(ptr: *const T) -> *mut T {
transmute(ptr)
}
/// Coerce an immutable reference to be mutable.
#[inline(always)]
unsafe fn transmute_immut_unsafe<T>(+ptr: *const T) -> *T { transmute(ptr) }
pub unsafe fn transmute_immut_unsafe<T>(ptr: *const T) -> *T {
transmute(ptr)
}
/// Coerce a borrowed mutable pointer to have an arbitrary associated region.
#[inline(always)]
unsafe fn transmute_mut_region<T>(+ptr: &a/mut T) -> &b/mut T {
pub unsafe fn transmute_mut_region<T>(ptr: &a/mut T) -> &b/mut T {
transmute(move ptr)
}
/// Transforms lifetime of the second pointer to match the first.
#[inline(always)]
unsafe fn copy_lifetime<S,T>(_ptr: &a/S, ptr: &T) -> &a/T {
pub unsafe fn copy_lifetime<S,T>(_ptr: &a/S, ptr: &T) -> &a/T {
transmute_region(ptr)
}
/// Transforms lifetime of the second pointer to match the first.
#[inline(always)]
unsafe fn copy_lifetime_vec<S,T>(_ptr: &a/[S], ptr: &T) -> &a/T {
pub unsafe fn copy_lifetime_vec<S,T>(_ptr: &a/[S], ptr: &T) -> &a/T {
transmute_region(ptr)
}
@ -97,16 +96,14 @@ unsafe fn copy_lifetime_vec<S,T>(_ptr: &a/[S], ptr: &T) -> &a/T {
****************************************************************************/
#[cfg(test)]
mod tests {
#[legacy_exports];
pub mod tests {
#[test]
fn test_reinterpret_cast() {
pub fn test_reinterpret_cast() {
assert 1u == unsafe { reinterpret_cast(&1) };
}
#[test]
fn test_bump_box_refcount() {
pub fn test_bump_box_refcount() {
unsafe {
let box = @~"box box box"; // refcount 1
bump_box_refcount(box); // refcount 2
@ -121,7 +118,7 @@ mod tests {
}
#[test]
fn test_transmute() {
pub fn test_transmute() {
unsafe {
let x = @1;
let x: *int = transmute(x);
@ -131,7 +128,7 @@ mod tests {
}
#[test]
fn test_transmute2() {
pub fn test_transmute2() {
unsafe {
assert ~[76u8, 0u8] == transmute(~"L");
}

View file

@ -39,24 +39,16 @@ use cmp::Eq;
Cn Unassigned a reserved unassigned code point or a noncharacter
*/
export is_alphabetic,
is_XID_start, is_XID_continue,
is_lowercase, is_uppercase,
is_whitespace, is_alphanumeric,
is_ascii, is_digit,
to_digit, cmp,
escape_default, escape_unicode;
use is_alphabetic = unicode::derived_property::Alphabetic;
use is_XID_start = unicode::derived_property::XID_Start;
use is_XID_continue = unicode::derived_property::XID_Continue;
pub use is_alphabetic = unicode::derived_property::Alphabetic;
pub use is_XID_start = unicode::derived_property::XID_Start;
pub use is_XID_continue = unicode::derived_property::XID_Continue;
/**
* Indicates whether a character is in lower case, defined
* in terms of the Unicode General Category 'Ll'
*/
pure fn is_lowercase(c: char) -> bool {
pub pure fn is_lowercase(c: char) -> bool {
return unicode::general_category::Ll(c);
}
@ -64,7 +56,7 @@ pure fn is_lowercase(c: char) -> bool {
* Indicates whether a character is in upper case, defined
* in terms of the Unicode General Category 'Lu'.
*/
pure fn is_uppercase(c: char) -> bool {
pub pure fn is_uppercase(c: char) -> bool {
return unicode::general_category::Lu(c);
}
@ -73,7 +65,7 @@ pure fn is_uppercase(c: char) -> bool {
* terms of the Unicode General Categories 'Zs', 'Zl', 'Zp'
* additional 'Cc'-category control codes in the range [0x09, 0x0d]
*/
pure fn is_whitespace(c: char) -> bool {
pub pure fn is_whitespace(c: char) -> bool {
return ('\x09' <= c && c <= '\x0d')
|| unicode::general_category::Zs(c)
|| unicode::general_category::Zl(c)
@ -85,7 +77,7 @@ pure fn is_whitespace(c: char) -> bool {
* defined in terms of the Unicode General Categories 'Nd', 'Nl', 'No'
* and the Derived Core Property 'Alphabetic'.
*/
pure fn is_alphanumeric(c: char) -> bool {
pub pure fn is_alphanumeric(c: char) -> bool {
return unicode::derived_property::Alphabetic(c) ||
unicode::general_category::Nd(c) ||
unicode::general_category::Nl(c) ||
@ -93,12 +85,12 @@ pure fn is_alphanumeric(c: char) -> bool {
}
/// Indicates whether the character is an ASCII character
pure fn is_ascii(c: char) -> bool {
pub pure fn is_ascii(c: char) -> bool {
c - ('\x7F' & c) == '\x00'
}
/// Indicates whether the character is numeric (Nd, Nl, or No)
pure fn is_digit(c: char) -> bool {
pub pure fn is_digit(c: char) -> bool {
return unicode::general_category::Nd(c) ||
unicode::general_category::Nl(c) ||
unicode::general_category::No(c);
@ -114,7 +106,7 @@ pure fn is_digit(c: char) -> bool {
* 'b' or 'B', 11, etc. Returns none if the char does not
* refer to a digit in the given radix.
*/
pure fn to_digit(c: char, radix: uint) -> Option<uint> {
pub pure fn to_digit(c: char, radix: uint) -> Option<uint> {
let val = match c {
'0' .. '9' => c as uint - ('0' as uint),
'a' .. 'z' => c as uint + 10u - ('a' as uint),
@ -134,7 +126,7 @@ pure fn to_digit(c: char, radix: uint) -> Option<uint> {
* - chars in [0x100,0xffff] get 4-digit escapes: `\\uNNNN`
* - chars above 0x10000 get 8-digit escapes: `\\UNNNNNNNN`
*/
fn escape_unicode(c: char) -> ~str {
pub fn escape_unicode(c: char) -> ~str {
let s = u32::to_str(c as u32, 16u);
let (c, pad) = (if c <= '\xff' { ('x', 2u) }
else if c <= '\uffff' { ('u', 4u) }
@ -159,7 +151,7 @@ fn escape_unicode(c: char) -> ~str {
* - Any other chars in the range [0x20,0x7e] are not escaped.
* - Any other chars are given hex unicode escapes; see `escape_unicode`.
*/
fn escape_default(c: char) -> ~str {
pub fn escape_default(c: char) -> ~str {
match c {
'\t' => ~"\\t",
'\r' => ~"\\r",
@ -179,7 +171,7 @@ fn escape_default(c: char) -> ~str {
*
* -1 if a < b, 0 if a == b, +1 if a > b
*/
pure fn cmp(a: char, b: char) -> int {
pub pure fn cmp(a: char, b: char) -> int {
return if b > a { -1 }
else if b < a { 1 }
else { 0 }

View file

@ -10,8 +10,6 @@ use repr::BoxRepr;
use sys::TypeDesc;
use cast::transmute;
export annihilate;
/**
* Runtime structures
*

View file

@ -3,10 +3,6 @@
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];
// uncomment once #1433 is fixed
// FIXME (#1433): export c_float_math_consts;
// FIXME (#1433): export c_double_math_consts;
use libc::c_int;
use libc::c_float;
use libc::c_double;
@ -193,66 +189,62 @@ pub mod c_double_targ_consts {
FIXME use these once they can be parsed (see Issue #1433)
mod c_float_math_consts {
#[legacy_exports];
const pi: c_float = 0x1.921fb6p+1_f32;
const div_1_pi: c_float = 0x1.45f306p-2_f32;
const div_2_pi: c_float = 0x1.45f306p-1_f32;
const div_pi_2: c_float = 0x1.921fb6p+0_f32;
const div_pi_4: c_float = 0x1.921fb6p-1_f32;
const div_2_sqrtpi: c_float = 0x1.20dd76p+0_f32;
const e: c_float = 0x1.5bf0a8p+1_f32;
const log2_e: c_float = 0x1.715476p+0_f32;
const log10_e: c_float = 0x1.bcb7b2p-2_f32;
const ln_2: c_float = 0x1.62e43p-1_f32;
const ln_10: c_float = 0x1.26bb1cp+1_f32;
const sqrt2: c_float = 0x1.6a09e6p+0_f32;
const div_1_sqrt2: c_float = 0x1.6a09e6p-1_f32;
pub mod c_float_math_consts {
pub const pi: c_float = 0x1.921fb6p+1_f32;
pub const div_1_pi: c_float = 0x1.45f306p-2_f32;
pub const div_2_pi: c_float = 0x1.45f306p-1_f32;
pub const div_pi_2: c_float = 0x1.921fb6p+0_f32;
pub const div_pi_4: c_float = 0x1.921fb6p-1_f32;
pub const div_2_sqrtpi: c_float = 0x1.20dd76p+0_f32;
pub const e: c_float = 0x1.5bf0a8p+1_f32;
pub const log2_e: c_float = 0x1.715476p+0_f32;
pub const log10_e: c_float = 0x1.bcb7b2p-2_f32;
pub const ln_2: c_float = 0x1.62e43p-1_f32;
pub const ln_10: c_float = 0x1.26bb1cp+1_f32;
pub const sqrt2: c_float = 0x1.6a09e6p+0_f32;
pub const div_1_sqrt2: c_float = 0x1.6a09e6p-1_f32;
}
mod c_double_math_consts {
#[legacy_exports];
const pi: c_double = 0x1.921fb54442d18p+1_f64;
const div_1_pi: c_double = 0x1.45f306dc9c883p-2_f64;
const div_2_pi: c_double = 0x1.45f306dc9c883p-1_f64;
const div_pi_2: c_double = 0x1.921fb54442d18p+0_f64;
const div_pi_4: c_double = 0x1.921fb54442d18p-1_f64;
const div_2_sqrtpi: c_double = 0x1.20dd750429b6dp+0_f64;
const e: c_double = 0x1.5bf0a8b145769p+1_f64;
const log2_e: c_double = 0x1.71547652b82fep+0_f64;
const log10_e: c_double = 0x1.bcb7b1526e50ep-2_f64;
const ln_2: c_double = 0x1.62e42fefa39efp-1_f64;
const ln_10: c_double = 0x1.26bb1bbb55516p+1_f64;
const sqrt2: c_double = 0x1.6a09e667f3bcdp+0_f64;
const div_1_sqrt2: c_double = 0x1.6a09e667f3bcdp-1_f64;
pub mod c_double_math_consts {
pub const pi: c_double = 0x1.921fb54442d18p+1_f64;
pub const div_1_pi: c_double = 0x1.45f306dc9c883p-2_f64;
pub const div_2_pi: c_double = 0x1.45f306dc9c883p-1_f64;
pub const div_pi_2: c_double = 0x1.921fb54442d18p+0_f64;
pub const div_pi_4: c_double = 0x1.921fb54442d18p-1_f64;
pub const div_2_sqrtpi: c_double = 0x1.20dd750429b6dp+0_f64;
pub const e: c_double = 0x1.5bf0a8b145769p+1_f64;
pub const log2_e: c_double = 0x1.71547652b82fep+0_f64;
pub const log10_e: c_double = 0x1.bcb7b1526e50ep-2_f64;
pub const ln_2: c_double = 0x1.62e42fefa39efp-1_f64;
pub const ln_10: c_double = 0x1.26bb1bbb55516p+1_f64;
pub const sqrt2: c_double = 0x1.6a09e667f3bcdp+0_f64;
pub const div_1_sqrt2: c_double = 0x1.6a09e667f3bcdp-1_f64;
}
mod c_float_targ_consts {
#[legacy_exports];
const radix: uint = 2u;
const mantissa_digits: uint = 24u;
const digits: uint = 6u;
const min_exp: int = -125;
const max_exp: int = 128;
const min_10_exp: int = -37;
const max_10_exp: int = 38;
const min_value: c_float = 0x1p-126_f32;
const max_value: c_float = 0x1.fffffep+127_f32;
const epsilon: c_float = 0x1p-23_f32;
pub mod c_float_targ_consts {
pub const radix: uint = 2u;
pub const mantissa_digits: uint = 24u;
pub const digits: uint = 6u;
pub const min_exp: int = -125;
pub const max_exp: int = 128;
pub const min_10_exp: int = -37;
pub const max_10_exp: int = 38;
pub const min_value: c_float = 0x1p-126_f32;
pub const max_value: c_float = 0x1.fffffep+127_f32;
pub const epsilon: c_float = 0x1p-23_f32;
}
mod c_double_targ_consts {
#[legacy_exports];
const radix: uint = 2u;
const mantissa_digits: uint = 53u;
const digits: uint = 15u;
const min_exp: int = -1021;
const max_exp: int = 1024;
const min_10_exp: int = -307;
const max_10_exp: int = 308;
const min_value: c_double = 0x1p-1022_f64;
const max_value: c_double = 0x1.fffffffffffffp+1023_f64;
const epsilon: c_double = 0x1p-52_f64;
pub mod c_double_targ_consts {
pub const radix: uint = 2u;
pub const mantissa_digits: uint = 53u;
pub const digits: uint = 15u;
pub const min_exp: int = -1021;
pub const max_exp: int = 1024;
pub const min_10_exp: int = -307;
pub const max_10_exp: int = 308;
pub const min_value: c_double = 0x1p-1022_f64;
pub const max_value: c_double = 0x1.fffffffffffffp+1023_f64;
pub const epsilon: c_double = 0x1p-52_f64;
}
*/

View file

@ -14,17 +14,14 @@ and `Eq` to overload the `==` and `!=` operators.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];
use nounittest::*;
use unittest::*;
export Ord;
export Eq;
pub use nounittest::*;
pub use unittest::*;
/// Interfaces used for comparison.
// Awful hack to work around duplicate lang items in core test.
#[cfg(notest)]
mod nounittest {
#[legacy_exports];
/**
* Trait for values that can be compared for a sort-order.
*
@ -33,7 +30,7 @@ mod nounittest {
* default implementations.
*/
#[lang="ord"]
trait Ord {
pub trait Ord {
pure fn lt(other: &self) -> bool;
pure fn le(other: &self) -> bool;
pure fn ge(other: &self) -> bool;
@ -50,7 +47,7 @@ mod nounittest {
* a default implementation.
*/
#[lang="eq"]
trait Eq {
pub trait Eq {
pure fn eq(other: &self) -> bool;
pure fn ne(other: &self) -> bool;
}
@ -63,14 +60,14 @@ mod nounittest {
#[cfg(test)]
mod unittest {
#[legacy_exports];
trait Ord {
pub trait Ord {
pure fn lt(other: &self) -> bool;
pure fn le(other: &self) -> bool;
pure fn ge(other: &self) -> bool;
pure fn gt(other: &self) -> bool;
}
trait Eq {
pub trait Eq {
pure fn eq(other: &self) -> bool;
pure fn ne(other: &self) -> bool;
}
@ -80,27 +77,27 @@ mod unittest {
mod unittest {
#[legacy_exports];}
pure fn lt<T: Ord>(v1: &T, v2: &T) -> bool {
pub pure fn lt<T: Ord>(v1: &T, v2: &T) -> bool {
(*v1).lt(v2)
}
pure fn le<T: Ord Eq>(v1: &T, v2: &T) -> bool {
pub pure fn le<T: Ord Eq>(v1: &T, v2: &T) -> bool {
(*v1).lt(v2) || (*v1).eq(v2)
}
pure fn eq<T: Eq>(v1: &T, v2: &T) -> bool {
pub pure fn eq<T: Eq>(v1: &T, v2: &T) -> bool {
(*v1).eq(v2)
}
pure fn ne<T: Eq>(v1: &T, v2: &T) -> bool {
pub pure fn ne<T: Eq>(v1: &T, v2: &T) -> bool {
(*v1).ne(v2)
}
pure fn ge<T: Ord>(v1: &T, v2: &T) -> bool {
pub pure fn ge<T: Ord>(v1: &T, v2: &T) -> bool {
(*v1).ge(v2)
}
pure fn gt<T: Ord>(v1: &T, v2: &T) -> bool {
pub pure fn gt<T: Ord>(v1: &T, v2: &T) -> bool {
(*v1).gt(v2)
}

View file

@ -32,14 +32,13 @@ will once again be the preferred module for intertask communication.
*/
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
// NB: transitionary, de-mode-ing
// tjc: re-forbid deprecated modes after snapshot
#[forbid(deprecated_pattern)];
use either::Either;
use libc::size_t;
// After snapshot, change p2::addr_of => addr_of
/**
* A communication endpoint that can receive messages
@ -76,7 +75,7 @@ pub fn Port<T: Send>() -> Port<T> {
impl<T: Send> Port<T> {
fn chan() -> Chan<T> { Chan(self) }
fn send(+v: T) { self.chan().send(move v) }
fn send(v: T) { self.chan().send(move v) }
fn recv() -> T { recv(self) }
fn peek() -> bool { peek(self) }
@ -85,7 +84,7 @@ impl<T: Send> Port<T> {
impl<T: Send> Chan<T> {
fn chan() -> Chan<T> { self }
fn send(+v: T) { send(self, move v) }
fn send(v: T) { send(self, move v) }
fn recv() -> T { recv_chan(self) }
fn peek() -> bool { peek_chan(self) }
@ -104,7 +103,7 @@ struct PortPtr<T:Send> {
// Once the port is detached it's guaranteed not to receive further
// messages
let yield = 0;
let yieldp = ptr::addr_of(yield);
let yieldp = ptr::addr_of(&yield);
rustrt::rust_port_begin_detach(self.po, yieldp);
if yield != 0 {
// Need to wait for the port to be detached
@ -167,7 +166,7 @@ fn as_raw_port<T: Send, U>(ch: comm::Chan<T>, f: fn(*rust_port) -> U) -> U {
* Constructs a channel. The channel is bound to the port used to
* construct it.
*/
pub fn Chan<T: Send>(p: Port<T>) -> Chan<T> {
pub fn Chan<T: Send>(&&p: Port<T>) -> Chan<T> {
Chan_(rustrt::get_port_id((**p).po))
}
@ -175,9 +174,9 @@ pub fn Chan<T: Send>(p: Port<T>) -> Chan<T> {
* Sends data over a channel. The sent data is moved into the channel,
* whereupon the caller loses access to it.
*/
pub fn send<T: Send>(ch: Chan<T>, +data: T) {
pub fn send<T: Send>(ch: Chan<T>, data: T) {
let Chan_(p) = ch;
let data_ptr = ptr::addr_of(data) as *();
let data_ptr = ptr::addr_of(&data) as *();
let res = rustrt::rust_port_id_send(p, data_ptr);
if res != 0 unsafe {
// Data sent successfully
@ -207,10 +206,10 @@ fn peek_chan<T: Send>(ch: comm::Chan<T>) -> bool {
/// Receive on a raw port pointer
fn recv_<T: Send>(p: *rust_port) -> T {
let yield = 0;
let yieldp = ptr::addr_of(yield);
let yieldp = ptr::addr_of(&yield);
let mut res;
res = rusti::init::<T>();
rustrt::port_recv(ptr::addr_of(res) as *uint, p, yieldp);
rustrt::port_recv(ptr::addr_of(&res) as *uint, p, yieldp);
if yield != 0 {
// Data isn't available yet, so res has not been initialized.
@ -234,12 +233,12 @@ fn peek_(p: *rust_port) -> bool {
pub fn select2<A: Send, B: Send>(p_a: Port<A>, p_b: Port<B>)
-> Either<A, B> {
let ports = ~[(**p_a).po, (**p_b).po];
let yield = 0, yieldp = ptr::addr_of(yield);
let yield = 0, yieldp = ptr::addr_of(&yield);
let mut resport: *rust_port;
resport = rusti::init::<*rust_port>();
do vec::as_imm_buf(ports) |ports, n_ports| {
rustrt::rust_port_select(ptr::addr_of(resport), ports,
rustrt::rust_port_select(ptr::addr_of(&resport), ports,
n_ports as size_t, yieldp);
}
@ -275,7 +274,6 @@ type port_id = int;
#[abi = "cdecl"]
extern mod rustrt {
#[legacy_exports];
fn rust_port_id_send(target_port: port_id, data: *()) -> libc::uintptr_t;
fn new_port(unit_sz: libc::size_t) -> *rust_port;
@ -298,7 +296,6 @@ extern mod rustrt {
#[abi = "rust-intrinsic"]
extern mod rusti {
#[legacy_exports];
fn init<T>() -> T;
}
@ -459,7 +456,7 @@ fn test_recv_chan_wrong_task() {
let po = Port();
let ch = Chan(po);
send(ch, ~"flower");
assert result::is_err(task::try(||
assert result::is_err(&task::try(||
recv_chan(ch)
))
}

View file

@ -36,7 +36,10 @@ Implicitly, all crates behave as if they included the following prologue:
// Don't link to core. We are core.
#[no_core];
#[legacy_modes];
#[legacy_exports];
#[warn(deprecated_mode)];
#[warn(deprecated_pattern)];
#[warn(vecs_implicitly_copyable)];
#[deny(non_camel_case_types)];
@ -85,242 +88,158 @@ export private;
/// Operations and constants for `int`
#[path = "int-template"]
mod int {
#[legacy_exports];
use inst::{ pow };
export pow;
pub use inst::{ pow };
#[path = "int.rs"]
#[legacy_exports]
mod inst;
}
/// Operations and constants for `i8`
#[path = "int-template"]
mod i8 {
#[legacy_exports];
#[path = "i8.rs"]
#[legacy_exports]
mod inst;
}
/// Operations and constants for `i16`
#[path = "int-template"]
mod i16 {
#[legacy_exports];
#[path = "i16.rs"]
#[legacy_exports]
mod inst;
}
/// Operations and constants for `i32`
#[path = "int-template"]
mod i32 {
#[legacy_exports];
#[path = "i32.rs"]
#[legacy_exports]
mod inst;
}
/// Operations and constants for `i64`
#[path = "int-template"]
mod i64 {
#[legacy_exports];
#[path = "i64.rs"]
#[legacy_exports]
mod inst;
}
/// Operations and constants for `uint`
#[path = "uint-template"]
mod uint {
#[legacy_exports];
use inst::{
pub use inst::{
div_ceil, div_round, div_floor, iterate,
next_power_of_two
};
export div_ceil, div_round, div_floor, iterate,
next_power_of_two;
#[path = "uint.rs"]
#[legacy_exports]
mod inst;
}
/// Operations and constants for `u8`
#[path = "uint-template"]
mod u8 {
#[legacy_exports];
use inst::is_ascii;
export is_ascii;
pub use inst::is_ascii;
#[path = "u8.rs"]
#[legacy_exports]
mod inst;
}
/// Operations and constants for `u16`
#[path = "uint-template"]
mod u16 {
#[legacy_exports];
#[path = "u16.rs"]
#[legacy_exports]
mod inst;
}
/// Operations and constants for `u32`
#[path = "uint-template"]
mod u32 {
#[legacy_exports];
#[path = "u32.rs"]
#[legacy_exports]
mod inst;
}
/// Operations and constants for `u64`
#[path = "uint-template"]
mod u64 {
#[legacy_exports];
#[path = "u64.rs"]
#[legacy_exports]
mod inst;
}
#[legacy_exports]
mod box;
#[legacy_exports]
mod char;
#[legacy_exports]
mod float;
#[legacy_exports]
mod f32;
#[legacy_exports]
mod f64;
#[legacy_exports]
mod str;
#[legacy_exports]
mod ptr;
#[legacy_exports]
mod vec;
#[legacy_exports]
mod at_vec;
#[legacy_exports]
mod bool;
#[legacy_exports]
mod tuple;
#[legacy_exports]
mod unit;
#[legacy_exports]
mod uniq;
// Ubiquitous-utility-type modules
#[cfg(notest)]
#[legacy_exports]
mod ops;
#[legacy_exports]
mod cmp;
#[legacy_exports]
mod num;
#[legacy_exports]
mod hash;
#[legacy_exports]
mod either;
#[legacy_exports]
mod iter;
#[legacy_exports]
mod logging;
#[legacy_exports]
mod option;
#[path="iter-trait"]
mod option_iter {
#[legacy_exports];
#[path = "option.rs"]
#[legacy_exports]
mod inst;
}
#[legacy_exports]
mod result;
#[legacy_exports]
mod to_str;
#[legacy_exports]
mod to_bytes;
#[legacy_exports]
mod from_str;
#[legacy_exports]
mod util;
// Data structure modules
#[legacy_exports]
mod dvec;
#[path="iter-trait"]
mod dvec_iter {
#[legacy_exports];
#[path = "dvec.rs"]
#[legacy_exports]
mod inst;
}
#[legacy_exports]
mod dlist;
#[path="iter-trait"]
mod dlist_iter {
#[legacy_exports];
#[path ="dlist.rs"]
#[legacy_exports]
mod inst;
}
#[legacy_exports]
mod send_map;
// Concurrency
#[legacy_exports]
mod comm;
#[legacy_exports]
mod task {
#[legacy_exports];
#[legacy_exports]
mod local_data;
#[legacy_exports]
pub mod local_data;
mod local_data_priv;
#[legacy_exports]
mod spawn;
#[legacy_exports]
mod rt;
pub mod spawn;
pub mod rt;
}
#[legacy_exports]
mod future;
#[legacy_exports]
mod pipes;
// Runtime and language-primitive support
#[legacy_exports]
mod gc;
#[legacy_exports]
mod io;
#[legacy_exports]
mod libc;
#[legacy_exports]
mod os;
#[legacy_exports]
mod path;
#[legacy_exports]
mod rand;
#[legacy_exports]
mod run;
#[legacy_exports]
mod sys;
#[legacy_exports]
mod cast;
#[legacy_exports]
mod mutable;
#[legacy_exports]
mod flate;
#[legacy_exports]
mod repr;
#[legacy_exports]
mod cleanup;
#[legacy_exports]
mod reflect;
// Modules supporting compiler-generated code
@ -336,9 +255,7 @@ mod rt;
// For internal use, not exported
#[legacy_exports]
mod unicode;
#[legacy_exports]
mod private;
mod cmath;
mod stackwalk;

View file

@ -2,8 +2,6 @@
// Export various ubiquitous types, constructors, methods.
#[legacy_exports];
use option::{Some, None};
use Option = option::Option;
use result::{Result, Ok, Err};
@ -17,6 +15,7 @@ use tuple::{TupleOps, ExtendedTupleOps};
use str::{StrSlice, UniqueStr};
use vec::{ConstVector, CopyableVector, ImmutableVector};
use vec::{ImmutableEqVector, ImmutableCopyableVector};
use vec::{MutableVector, MutableCopyableVector};
use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter};
use iter::{CopyableOrderedIter, Times, TimesIx};
use num::Num;
@ -33,6 +32,7 @@ export Num, Times, TimesIx;
export StrSlice, UniqueStr;
export ConstVector, CopyableVector, ImmutableVector;
export ImmutableEqVector, ImmutableCopyableVector, IterTraitExtensions;
export MutableVector, MutableCopyableVector;
export BaseIter, CopyableIter, CopyableOrderedIter, ExtendedIter, EqIter;
export TupleOps, ExtendedTupleOps;
export Ptr;

View file

@ -9,12 +9,9 @@ Do not use ==, !=, <, etc on doubly-linked lists -- it may not terminate.
*/
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
// tjc: re-forbid deprecated modes after snapshot
#[forbid(deprecated_pattern)];
export DList;
export new_dlist, from_elem, from_vec, extensions;
type DListLink<T> = Option<DListNode<T>>;
enum DListNode<T> = @{
@ -24,7 +21,7 @@ enum DListNode<T> = @{
mut next: DListLink<T>
};
enum DList<T> {
pub enum DList<T> {
DList_(@{
mut size: uint,
mut hd: DListLink<T>,
@ -83,7 +80,7 @@ impl<T> DListNode<T> {
}
/// Creates a new dlist node with the given data.
pure fn new_dlist_node<T>(+data: T) -> DListNode<T> {
pure fn new_dlist_node<T>(data: T) -> DListNode<T> {
DListNode(@{data: move data, mut linked: false,
mut prev: None, mut next: None})
}
@ -94,15 +91,15 @@ pure fn DList<T>() -> DList<T> {
}
/// Creates a new dlist with a single element
pure fn from_elem<T>(+data: T) -> DList<T> {
pub pure fn from_elem<T>(data: T) -> DList<T> {
let list = DList();
unsafe { list.push(move data); }
list
}
fn from_vec<T: Copy>(+vec: &[T]) -> DList<T> {
pub fn from_vec<T: Copy>(vec: &[T]) -> DList<T> {
do vec::foldl(DList(), vec) |list,data| {
list.push(data); // Iterating left-to-right -- add newly to the tail.
list.push(*data); // Iterating left-to-right -- add newly to the tail.
list
}
}
@ -118,7 +115,7 @@ fn concat<T>(lists: DList<DList<T>>) -> DList<T> {
}
priv impl<T> DList<T> {
pure fn new_link(-data: T) -> DListLink<T> {
pure fn new_link(data: T) -> DListLink<T> {
Some(DListNode(@{data: move data, mut linked: true,
mut prev: None, mut next: None}))
}
@ -145,7 +142,7 @@ priv impl<T> DList<T> {
// Link two nodes together. If either of them are 'none', also sets
// the head and/or tail pointers appropriately.
#[inline(always)]
fn link(+before: DListLink<T>, +after: DListLink<T>) {
fn link(before: DListLink<T>, after: DListLink<T>) {
match before {
Some(neighbour) => neighbour.next = after,
None => self.hd = after
@ -166,12 +163,12 @@ priv impl<T> DList<T> {
self.size -= 1;
}
fn add_head(+nobe: DListLink<T>) {
fn add_head(nobe: DListLink<T>) {
self.link(nobe, self.hd); // Might set tail too.
self.hd = nobe;
self.size += 1;
}
fn add_tail(+nobe: DListLink<T>) {
fn add_tail(nobe: DListLink<T>) {
self.link(self.tl, nobe); // Might set head too.
self.tl = nobe;
self.size += 1;
@ -201,27 +198,27 @@ impl<T> DList<T> {
pure fn is_not_empty() -> bool { self.len() != 0 }
/// Add data to the head of the list. O(1).
fn push_head(+data: T) {
fn push_head(data: T) {
self.add_head(self.new_link(move data));
}
/**
* Add data to the head of the list, and get the new containing
* node. O(1).
*/
fn push_head_n(+data: T) -> DListNode<T> {
fn push_head_n(data: T) -> DListNode<T> {
let mut nobe = self.new_link(move data);
self.add_head(nobe);
option::get(&nobe)
}
/// Add data to the tail of the list. O(1).
fn push(+data: T) {
fn push(data: T) {
self.add_tail(self.new_link(move data));
}
/**
* Add data to the tail of the list, and get the new containing
* node. O(1).
*/
fn push_n(+data: T) -> DListNode<T> {
fn push_n(data: T) -> DListNode<T> {
let mut nobe = self.new_link(move data);
self.add_tail(nobe);
option::get(&nobe)
@ -230,7 +227,7 @@ impl<T> DList<T> {
* Insert data into the middle of the list, left of the given node.
* O(1).
*/
fn insert_before(+data: T, neighbour: DListNode<T>) {
fn insert_before(data: T, neighbour: DListNode<T>) {
self.insert_left(self.new_link(move data), neighbour);
}
/**
@ -245,7 +242,7 @@ impl<T> DList<T> {
* Insert data in the middle of the list, left of the given node,
* and get its containing node. O(1).
*/
fn insert_before_n(+data: T, neighbour: DListNode<T>) -> DListNode<T> {
fn insert_before_n(data: T, neighbour: DListNode<T>) -> DListNode<T> {
let mut nobe = self.new_link(move data);
self.insert_left(nobe, neighbour);
option::get(&nobe)
@ -254,7 +251,7 @@ impl<T> DList<T> {
* Insert data into the middle of the list, right of the given node.
* O(1).
*/
fn insert_after(+data: T, neighbour: DListNode<T>) {
fn insert_after(data: T, neighbour: DListNode<T>) {
self.insert_right(neighbour, self.new_link(move data));
}
/**
@ -269,7 +266,7 @@ impl<T> DList<T> {
* Insert data in the middle of the list, right of the given node,
* and get its containing node. O(1).
*/
fn insert_after_n(+data: T, neighbour: DListNode<T>) -> DListNode<T> {
fn insert_after_n(data: T, neighbour: DListNode<T>) -> DListNode<T> {
let mut nobe = self.new_link(move data);
self.insert_right(neighbour, nobe);
option::get(&nobe)
@ -278,13 +275,13 @@ impl<T> DList<T> {
/// Remove a node from the head of the list. O(1).
fn pop_n() -> Option<DListNode<T>> {
let hd = self.peek_n();
hd.map(|nobe| self.unlink(nobe));
hd.map(|nobe| self.unlink(*nobe));
hd
}
/// Remove a node from the tail of the list. O(1).
fn pop_tail_n() -> Option<DListNode<T>> {
let tl = self.peek_tail_n();
tl.map(|nobe| self.unlink(nobe));
tl.map(|nobe| self.unlink(*nobe));
tl
}
/// Get the node at the list's head. O(1).
@ -678,7 +675,7 @@ mod tests {
#[test]
fn test_dlist_foldl() {
let l = from_vec(vec::from_fn(101, |x|x));
assert iter::foldl(l, 0, |accum,elem| accum+elem) == 5050;
assert iter::foldl(&l, 0, |accum,elem| *accum+*elem) == 5050;
}
#[test]
fn test_dlist_break_early() {

View file

@ -10,18 +10,12 @@ Note that recursive use is not permitted.
*/
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
// tjc: re-forbid deprecated modes after snapshot
#[forbid(deprecated_pattern)];
use cast::reinterpret_cast;
use ptr::null;
export DVec;
export from_elem;
export from_vec;
export extensions;
export unwrap;
/**
* A growable, modifiable vector type that accumulates elements into a
* unique vector.
@ -57,27 +51,27 @@ type DVec_<A> = {
mut data: ~[A]
};
enum DVec<A> {
pub enum DVec<A> {
DVec_(DVec_<A>)
}
/// Creates a new, empty dvec
fn DVec<A>() -> DVec<A> {
pub fn DVec<A>() -> DVec<A> {
DVec_({mut data: ~[]})
}
/// Creates a new dvec with a single element
fn from_elem<A>(+e: A) -> DVec<A> {
pub fn from_elem<A>(e: A) -> DVec<A> {
DVec_({mut data: ~[move e]})
}
/// Creates a new dvec with the contents of a vector
fn from_vec<A>(+v: ~[A]) -> DVec<A> {
pub fn from_vec<A>(v: ~[A]) -> DVec<A> {
DVec_({mut data: move v})
}
/// Consumes the vector and returns its contents
fn unwrap<A>(+d: DVec<A>) -> ~[A] {
pub fn unwrap<A>(d: DVec<A>) -> ~[A] {
let DVec_({data: v}) <- d;
move v
}
@ -93,7 +87,7 @@ priv impl<A> DVec<A> {
}
#[inline(always)]
fn check_out<B>(f: fn(-v: ~[A]) -> B) -> B {
fn check_out<B>(f: &fn(v: ~[A]) -> B) -> B {
unsafe {
let mut data = cast::reinterpret_cast(&null::<()>());
data <-> self.data;
@ -104,7 +98,7 @@ priv impl<A> DVec<A> {
}
#[inline(always)]
fn give_back(+data: ~[A]) {
fn give_back(data: ~[A]) {
unsafe {
self.data = move data;
}
@ -126,7 +120,7 @@ impl<A> DVec<A> {
* and return a new vector to replace it with.
*/
#[inline(always)]
fn swap(f: fn(-v: ~[A]) -> ~[A]) {
fn swap(f: &fn(v: ~[A]) -> ~[A]) {
self.check_out(|v| self.give_back(f(move v)))
}
@ -136,7 +130,7 @@ impl<A> DVec<A> {
* and return a new vector to replace it with.
*/
#[inline(always)]
fn swap_mut(f: fn(-v: ~[mut A]) -> ~[mut A]) {
fn swap_mut(f: &fn(v: ~[mut A]) -> ~[mut A]) {
do self.swap |v| {
vec::from_mut(f(vec::to_mut(move v)))
}
@ -154,7 +148,7 @@ impl<A> DVec<A> {
}
/// Overwrite the current contents
fn set(+w: ~[A]) {
fn set(w: ~[A]) {
self.check_not_borrowed();
self.data <- w;
}
@ -163,14 +157,14 @@ impl<A> DVec<A> {
fn pop() -> A {
do self.check_out |v| {
let mut v <- v;
let result = vec::pop(v);
let result = v.pop();
self.give_back(move v);
move result
}
}
/// Insert a single item at the front of the list
fn unshift(-t: A) {
fn unshift(t: A) {
unsafe {
let mut data = cast::reinterpret_cast(&null::<()>());
data <-> self.data;
@ -178,22 +172,22 @@ impl<A> DVec<A> {
if data_ptr.is_null() { fail ~"Recursive use of dvec"; }
log(error, ~"a");
self.data <- ~[move t];
vec::push_all_move(self.data, move data);
self.data.push_all_move(move data);
log(error, ~"b");
}
}
/// Append a single item to the end of the list
fn push(+t: A) {
fn push(t: A) {
self.check_not_borrowed();
vec::push(self.data, move t);
self.data.push(move t);
}
/// Remove and return the first element
fn shift() -> A {
do self.check_out |v| {
let mut v = move v;
let result = vec::shift(v);
let result = v.shift();
self.give_back(move v);
move result
}
@ -246,7 +240,7 @@ impl<A: Copy> DVec<A> {
vec::reserve(&mut v, new_len);
let mut i = from_idx;
while i < to_idx {
vec::push(v, ts[i]);
v.push(ts[i]);
i += 1u;
}
move v
@ -272,7 +266,7 @@ impl<A: Copy> DVec<A> {
}
};
for ts.each |t| { vec::push(v, *t) };
for ts.each |t| { v.push(*t) };
v
}
}
@ -311,10 +305,10 @@ impl<A: Copy> DVec<A> {
* growing the vector if necessary. New elements will be initialized
* with `initval`
*/
fn grow_set_elt(idx: uint, initval: A, val: A) {
fn grow_set_elt(idx: uint, initval: &A, val: A) {
do self.swap |v| {
let mut v = move v;
vec::grow_set(v, idx, initval, val);
v.grow_set(idx, initval, val);
move v
}
}
@ -325,11 +319,11 @@ impl<A: Copy> DVec<A> {
self.check_not_borrowed();
let length = self.len();
if length == 0u {
if length == 0 {
fail ~"attempt to retrieve the last element of an empty vector";
}
return self.data[length - 1u];
return self.data[length - 1];
}
/// Iterates over the elements in reverse order
@ -360,7 +354,7 @@ impl<A: Copy> DVec<A> {
}
impl<A:Copy> DVec<A>: Index<uint,A> {
pure fn index(&&idx: uint) -> A {
pure fn index(idx: uint) -> A {
self.get_elt(idx)
}
}

View file

@ -1,5 +1,5 @@
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
// tjc: re-forbid deprecated modes after snapshot
#[forbid(deprecated_pattern)];
//! A type that represents one of two alternatives
@ -8,13 +8,13 @@ use cmp::Eq;
use result::Result;
/// The either type
enum Either<T, U> {
pub enum Either<T, U> {
Left(T),
Right(U)
}
fn either<T, U, V>(f_left: fn((&T)) -> V,
f_right: fn((&U)) -> V, value: &Either<T, U>) -> V {
pub fn either<T, U, V>(f_left: fn((&T)) -> V,
f_right: fn((&U)) -> V, value: &Either<T, U>) -> V {
/*!
* Applies a function based on the given either value
*
@ -29,33 +29,34 @@ fn either<T, U, V>(f_left: fn((&T)) -> V,
}
}
fn lefts<T: Copy, U>(eithers: &[Either<T, U>]) -> ~[T] {
pub fn lefts<T: Copy, U>(eithers: &[Either<T, U>]) -> ~[T] {
//! Extracts from a vector of either all the left values
let mut result: ~[T] = ~[];
for vec::each(eithers) |elt| {
match *elt {
Left(l) => vec::push(result, l),
_ => { /* fallthrough */ }
do vec::build_sized(eithers.len()) |push| {
for vec::each(eithers) |elt| {
match *elt {
Left(ref l) => { push(*l); }
_ => { /* fallthrough */ }
}
}
}
move result
}
fn rights<T, U: Copy>(eithers: &[Either<T, U>]) -> ~[U] {
pub fn rights<T, U: Copy>(eithers: &[Either<T, U>]) -> ~[U] {
//! Extracts from a vector of either all the right values
let mut result: ~[U] = ~[];
for vec::each(eithers) |elt| {
match *elt {
Right(r) => vec::push(result, r),
_ => { /* fallthrough */ }
do vec::build_sized(eithers.len()) |push| {
for vec::each(eithers) |elt| {
match *elt {
Right(ref r) => { push(*r); }
_ => { /* fallthrough */ }
}
}
}
move result
}
fn partition<T: Copy, U: Copy>(eithers: &[Either<T, U>])
// XXX bad copies. take arg by val
pub fn partition<T: Copy, U: Copy>(eithers: &[Either<T, U>])
-> {lefts: ~[T], rights: ~[U]} {
/*!
* Extracts from a vector of either all the left values and right values
@ -68,23 +69,26 @@ fn partition<T: Copy, U: Copy>(eithers: &[Either<T, U>])
let mut rights: ~[U] = ~[];
for vec::each(eithers) |elt| {
match *elt {
Left(l) => vec::push(lefts, l),
Right(r) => vec::push(rights, r)
Left(copy l) => lefts.push(l),
Right(copy r) => rights.push(r)
}
}
return {lefts: move lefts, rights: move rights};
}
pure fn flip<T: Copy, U: Copy>(eith: &Either<T, U>) -> Either<U, T> {
// XXX bad copies
pub pure fn flip<T: Copy, U: Copy>(eith: &Either<T, U>) -> Either<U, T> {
//! Flips between left and right of a given either
match *eith {
Right(r) => Left(r),
Left(l) => Right(l)
Right(copy r) => Left(r),
Left(copy l) => Right(l)
}
}
pure fn to_result<T: Copy, U: Copy>(eith: &Either<T, U>) -> Result<U, T> {
// XXX bad copies
pub pure fn to_result<T: Copy, U: Copy>(eith: &Either<T, U>)
-> Result<U, T> {
/*!
* Converts either::t to a result::t
*
@ -93,24 +97,25 @@ pure fn to_result<T: Copy, U: Copy>(eith: &Either<T, U>) -> Result<U, T> {
*/
match *eith {
Right(r) => result::Ok(r),
Left(l) => result::Err(l)
Right(copy r) => result::Ok(r),
Left(copy l) => result::Err(l)
}
}
pure fn is_left<T, U>(eith: &Either<T, U>) -> bool {
pub pure fn is_left<T, U>(eith: &Either<T, U>) -> bool {
//! Checks whether the given value is a left
match *eith { Left(_) => true, _ => false }
}
pure fn is_right<T, U>(eith: &Either<T, U>) -> bool {
pub pure fn is_right<T, U>(eith: &Either<T, U>) -> bool {
//! Checks whether the given value is a right
match *eith { Right(_) => true, _ => false }
}
pure fn unwrap_left<T,U>(+eith: Either<T,U>) -> T {
// tjc: fix the next two after a snapshot
pub pure fn unwrap_left<T,U>(eith: Either<T,U>) -> T {
//! Retrieves the value in the left branch. Fails if the either is Right.
match move eith {
@ -118,7 +123,7 @@ pure fn unwrap_left<T,U>(+eith: Either<T,U>) -> T {
}
}
pure fn unwrap_right<T,U>(+eith: Either<T,U>) -> U {
pub pure fn unwrap_right<T,U>(eith: Either<T,U>) -> U {
//! Retrieves the value in the right branch. Fails if the either is Left.
match move eith {
@ -129,16 +134,16 @@ pure fn unwrap_right<T,U>(+eith: Either<T,U>) -> U {
impl<T:Eq,U:Eq> Either<T,U> : Eq {
pure fn eq(other: &Either<T,U>) -> bool {
match self {
Left(a) => {
Left(ref a) => {
match (*other) {
Left(ref b) => a.eq(b),
Left(ref b) => (*a).eq(b),
Right(_) => false
}
}
Right(a) => {
Right(ref a) => {
match (*other) {
Left(_) => false,
Right(ref b) => a.eq(b)
Right(ref b) => (*a).eq(b)
}
}
}

View file

@ -81,16 +81,16 @@ mod ct {
// A fragment of the output sequence
enum Piece { PieceString(~str), PieceConv(Conv), }
type ErrorFn = fn@(~str) -> ! ;
type ErrorFn = fn@(&str) -> ! ;
fn parse_fmt_string(s: ~str, error: ErrorFn) -> ~[Piece] {
fn parse_fmt_string(s: &str, error: ErrorFn) -> ~[Piece] {
let mut pieces: ~[Piece] = ~[];
let lim = str::len(s);
let mut buf = ~"";
fn flush_buf(+buf: ~str, &pieces: ~[Piece]) -> ~str {
if str::len(buf) > 0 {
fn flush_buf(buf: ~str, pieces: &mut ~[Piece]) -> ~str {
if buf.len() > 0 {
let piece = PieceString(move buf);
vec::push(pieces, move piece);
pieces.push(move piece);
}
return ~"";
}
@ -108,17 +108,17 @@ mod ct {
buf += curr2;
i += 1;
} else {
buf = flush_buf(move buf, pieces);
buf = flush_buf(move buf, &mut pieces);
let rs = parse_conversion(s, i, lim, error);
vec::push(pieces, copy rs.piece);
pieces.push(copy rs.piece);
i = rs.next;
}
} else { buf += curr; i += size; }
}
flush_buf(move buf, pieces);
flush_buf(move buf, &mut pieces);
move pieces
}
fn peek_num(s: ~str, i: uint, lim: uint) ->
fn peek_num(s: &str, i: uint, lim: uint) ->
Option<{num: uint, next: uint}> {
let mut j = i;
let mut accum = 0u;
@ -140,7 +140,7 @@ mod ct {
None
}
}
fn parse_conversion(s: ~str, i: uint, lim: uint, error: ErrorFn) ->
fn parse_conversion(s: &str, i: uint, lim: uint, error: ErrorFn) ->
{piece: Piece, next: uint} {
let parm = parse_parameter(s, i, lim);
let flags = parse_flags(s, parm.next, lim);
@ -155,7 +155,7 @@ mod ct {
ty: ty.ty}),
next: ty.next};
}
fn parse_parameter(s: ~str, i: uint, lim: uint) ->
fn parse_parameter(s: &str, i: uint, lim: uint) ->
{param: Option<int>, next: uint} {
if i >= lim { return {param: None, next: i}; }
let num = peek_num(s, i, lim);
@ -170,12 +170,12 @@ mod ct {
}
};
}
fn parse_flags(s: ~str, i: uint, lim: uint) ->
fn parse_flags(s: &str, i: uint, lim: uint) ->
{flags: ~[Flag], next: uint} {
let noflags: ~[Flag] = ~[];
if i >= lim { return {flags: move noflags, next: i}; }
fn more_(f: Flag, s: ~str, i: uint, lim: uint) ->
fn more(f: Flag, s: &str, i: uint, lim: uint) ->
{flags: ~[Flag], next: uint} {
let next = parse_flags(s, i + 1u, lim);
let rest = copy next.flags;
@ -183,21 +183,22 @@ mod ct {
let curr: ~[Flag] = ~[f];
return {flags: vec::append(move curr, rest), next: j};
}
let more = |x, copy s| more_(x, copy s, i, lim);
// Unfortunate, but because s is borrowed, can't use a closure
// fn more(f: Flag, s: &str) { more_(f, s, i, lim); }
let f = s[i];
return if f == '-' as u8 {
more(FlagLeftJustify)
more(FlagLeftJustify, s, i, lim)
} else if f == '0' as u8 {
more(FlagLeftZeroPad)
more(FlagLeftZeroPad, s, i, lim)
} else if f == ' ' as u8 {
more(FlagSpaceForSign)
more(FlagSpaceForSign, s, i, lim)
} else if f == '+' as u8 {
more(FlagSignAlways)
more(FlagSignAlways, s, i, lim)
} else if f == '#' as u8 {
more(FlagAlternate)
more(FlagAlternate, s, i, lim)
} else { {flags: move noflags, next: i} };
}
fn parse_count(s: ~str, i: uint, lim: uint)
fn parse_count(s: &str, i: uint, lim: uint)
-> {count: Count, next: uint} {
return if i >= lim {
{count: CountImplied, next: i}
@ -219,7 +220,7 @@ mod ct {
}
};
}
fn parse_precision(s: ~str, i: uint, lim: uint) ->
fn parse_precision(s: &str, i: uint, lim: uint) ->
{count: Count, next: uint} {
return if i >= lim {
{count: CountImplied, next: i}
@ -235,7 +236,7 @@ mod ct {
}
} else { {count: CountImplied, next: i} };
}
fn parse_type(s: ~str, i: uint, lim: uint, error: ErrorFn) ->
fn parse_type(s: &str, i: uint, lim: uint, error: ErrorFn) ->
{ty: Ty, next: uint} {
if i >= lim { error(~"missing type in conversion"); }
let tstr = str::slice(s, i, i+1u);
@ -288,7 +289,7 @@ mod rt {
type Conv = {flags: u32, width: Count, precision: Count, ty: Ty};
pure fn conv_int(cv: Conv, i: int) -> ~str {
let radix = 10u;
let radix = 10;
let prec = get_int_precision(cv);
let mut s : ~str = int_to_str_prec(i, radix, prec);
if 0 <= i {
@ -350,8 +351,8 @@ mod rt {
}
return unsafe { pad(cv, s, PadFloat) };
}
pure fn conv_poly<T>(cv: Conv, v: T) -> ~str {
let s = sys::log_str(&v);
pure fn conv_poly<T>(cv: Conv, v: &T) -> ~str {
let s = sys::log_str(v);
return conv_str(cv, s);
}
@ -404,16 +405,17 @@ mod rt {
pure fn ne(other: &PadMode) -> bool { !self.eq(other) }
}
fn pad(cv: Conv, &s: ~str, mode: PadMode) -> ~str {
fn pad(cv: Conv, s: ~str, mode: PadMode) -> ~str {
let mut s = move s; // sadtimes
let uwidth : uint = match cv.width {
CountImplied => return copy s,
CountImplied => return s,
CountIs(width) => {
// FIXME: width should probably be uint (see Issue #1996)
width as uint
}
};
let strlen = str::char_len(s);
if uwidth <= strlen { return copy s; }
if uwidth <= strlen { return s; }
let mut padchar = ' ';
let diff = uwidth - strlen;
if have_flag(cv.flags, flag_left_justify) {
@ -444,7 +446,7 @@ mod rt {
// zeros. It may make sense to convert zero padding to a precision
// instead.
if signed && zero_padding && str::len(s) > 0u {
if signed && zero_padding && s.len() > 0 {
let head = str::shift_char(&mut s);
if head == '+' || head == '-' || head == ' ' {
let headstr = str::from_chars(vec::from_elem(1u, head));
@ -461,7 +463,12 @@ mod rt {
}
}
// XXX remove after snapshots
// Remove after snapshot
// Functions used by the fmt extension at runtime. For now there are a lot of
// decisions made a runtime. If it proves worthwhile then some of these
// conditions can be evaluated at compile-time. For now though it's cleaner to
// implement it 0this way, I think.
mod rt2 {
#[legacy_exports];
const flag_none : u32 = 0u32;
@ -477,7 +484,7 @@ mod rt2 {
type Conv = {flags: u32, width: Count, precision: Count, ty: Ty};
pure fn conv_int(cv: Conv, i: int) -> ~str {
let radix = 10u;
let radix = 10;
let prec = get_int_precision(cv);
let mut s : ~str = int_to_str_prec(i, radix, prec);
if 0 <= i {
@ -539,8 +546,8 @@ mod rt2 {
}
return unsafe { pad(cv, s, PadFloat) };
}
pure fn conv_poly<T>(cv: Conv, v: T) -> ~str {
let s = sys::log_str(&v);
pure fn conv_poly<T>(cv: Conv, v: &T) -> ~str {
let s = sys::log_str(v);
return conv_str(cv, s);
}
@ -593,16 +600,17 @@ mod rt2 {
pure fn ne(other: &PadMode) -> bool { !self.eq(other) }
}
fn pad(cv: Conv, &s: ~str, mode: PadMode) -> ~str {
fn pad(cv: Conv, s: ~str, mode: PadMode) -> ~str {
let mut s = move s; // sadtimes
let uwidth : uint = match cv.width {
CountImplied => return copy s,
CountImplied => return s,
CountIs(width) => {
// FIXME: width should probably be uint (see Issue #1996)
width as uint
}
};
let strlen = str::char_len(s);
if uwidth <= strlen { return copy s; }
if uwidth <= strlen { return s; }
let mut padchar = ' ';
let diff = uwidth - strlen;
if have_flag(cv.flags, flag_left_justify) {
@ -633,7 +641,7 @@ mod rt2 {
// zeros. It may make sense to convert zero padding to a precision
// instead.
if signed && zero_padding && str::len(s) > 0u {
if signed && zero_padding && s.len() > 0 {
let head = str::shift_char(&mut s);
if head == '+' || head == '-' || head == ' ' {
let headstr = str::from_chars(vec::from_elem(1u, head));

View file

@ -4,68 +4,51 @@
//! Operations and constants for `f32`
// PORT
use cmath::c_float::*;
use cmath::c_float_targ_consts::*;
export add, sub, mul, div, rem, lt, le, eq, ne, ge, gt;
export is_positive, is_negative, is_nonpositive, is_nonnegative;
export is_zero, is_infinite, is_finite;
export NaN, is_NaN, infinity, neg_infinity;
export consts;
export logarithm;
export acos, asin, atan, atan2, cbrt, ceil, copysign, cos, cosh, floor;
export erf, erfc, exp, expm1, exp2, abs, abs_sub;
export mul_add, fmax, fmin, nextafter, frexp, hypot, ldexp;
export lgamma, ln, log_radix, ln1p, log10, log2, ilog_radix;
export modf, pow, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc;
export signbit;
export num;
pub use cmath::c_float::*;
pub use cmath::c_float_targ_consts::*;
// These are not defined inside consts:: for consistency with
// the integer types
const NaN: f32 = 0.0_f32/0.0_f32;
pub const NaN: f32 = 0.0_f32/0.0_f32;
const infinity: f32 = 1.0_f32/0.0_f32;
pub const infinity: f32 = 1.0_f32/0.0_f32;
const neg_infinity: f32 = -1.0_f32/0.0_f32;
pub const neg_infinity: f32 = -1.0_f32/0.0_f32;
pure fn is_NaN(f: f32) -> bool { f != f }
pub pure fn is_NaN(f: f32) -> bool { f != f }
pure fn add(x: f32, y: f32) -> f32 { return x + y; }
pub pure fn add(x: f32, y: f32) -> f32 { return x + y; }
pure fn sub(x: f32, y: f32) -> f32 { return x - y; }
pub pure fn sub(x: f32, y: f32) -> f32 { return x - y; }
pure fn mul(x: f32, y: f32) -> f32 { return x * y; }
pub pure fn mul(x: f32, y: f32) -> f32 { return x * y; }
pure fn div(x: f32, y: f32) -> f32 { return x / y; }
pub pure fn div(x: f32, y: f32) -> f32 { return x / y; }
pure fn rem(x: f32, y: f32) -> f32 { return x % y; }
pub pure fn rem(x: f32, y: f32) -> f32 { return x % y; }
pure fn lt(x: f32, y: f32) -> bool { return x < y; }
pub pure fn lt(x: f32, y: f32) -> bool { return x < y; }
pure fn le(x: f32, y: f32) -> bool { return x <= y; }
pub pure fn le(x: f32, y: f32) -> bool { return x <= y; }
pure fn eq(x: f32, y: f32) -> bool { return x == y; }
pub pure fn eq(x: f32, y: f32) -> bool { return x == y; }
pure fn ne(x: f32, y: f32) -> bool { return x != y; }
pub pure fn ne(x: f32, y: f32) -> bool { return x != y; }
pure fn ge(x: f32, y: f32) -> bool { return x >= y; }
pub pure fn ge(x: f32, y: f32) -> bool { return x >= y; }
pure fn gt(x: f32, y: f32) -> bool { return x > y; }
pub pure fn gt(x: f32, y: f32) -> bool { return x > y; }
// FIXME (#1999): replace the predicates below with llvm intrinsics or
// calls to the libmath macros in the rust runtime for performance.
/// Returns true if `x` is a positive number, including +0.0f320 and +Infinity
pure fn is_positive(x: f32) -> bool
pub pure fn is_positive(x: f32) -> bool
{ return x > 0.0f32 || (1.0f32/x) == infinity; }
/// Returns true if `x` is a negative number, including -0.0f320 and -Infinity
pure fn is_negative(x: f32) -> bool
pub pure fn is_negative(x: f32) -> bool
{ return x < 0.0f32 || (1.0f32/x) == neg_infinity; }
/**
@ -73,7 +56,7 @@ pure fn is_negative(x: f32) -> bool
*
* This is the same as `f32::is_negative`.
*/
pure fn is_nonpositive(x: f32) -> bool {
pub pure fn is_nonpositive(x: f32) -> bool {
return x < 0.0f32 || (1.0f32/x) == neg_infinity;
}
@ -82,87 +65,85 @@ pure fn is_nonpositive(x: f32) -> bool {
*
* This is the same as `f32::is_positive`.)
*/
pure fn is_nonnegative(x: f32) -> bool {
pub pure fn is_nonnegative(x: f32) -> bool {
return x > 0.0f32 || (1.0f32/x) == infinity;
}
/// Returns true if `x` is a zero number (positive or negative zero)
pure fn is_zero(x: f32) -> bool {
pub pure fn is_zero(x: f32) -> bool {
return x == 0.0f32 || x == -0.0f32;
}
/// Returns true if `x`is an infinite number
pure fn is_infinite(x: f32) -> bool {
pub pure fn is_infinite(x: f32) -> bool {
return x == infinity || x == neg_infinity;
}
/// Returns true if `x`is a finite number
pure fn is_finite(x: f32) -> bool {
pub pure fn is_finite(x: f32) -> bool {
return !(is_NaN(x) || is_infinite(x));
}
// FIXME (#1999): add is_normal, is_subnormal, and fpclassify.
/* Module: consts */
mod consts {
#[legacy_exports];
pub mod consts {
// FIXME (requires Issue #1433 to fix): replace with mathematical
// constants from cmath.
/// Archimedes' constant
const pi: f32 = 3.14159265358979323846264338327950288_f32;
pub const pi: f32 = 3.14159265358979323846264338327950288_f32;
/// pi/2.0
const frac_pi_2: f32 = 1.57079632679489661923132169163975144_f32;
pub const frac_pi_2: f32 = 1.57079632679489661923132169163975144_f32;
/// pi/4.0
const frac_pi_4: f32 = 0.785398163397448309615660845819875721_f32;
pub const frac_pi_4: f32 = 0.785398163397448309615660845819875721_f32;
/// 1.0/pi
const frac_1_pi: f32 = 0.318309886183790671537767526745028724_f32;
pub const frac_1_pi: f32 = 0.318309886183790671537767526745028724_f32;
/// 2.0/pi
const frac_2_pi: f32 = 0.636619772367581343075535053490057448_f32;
pub const frac_2_pi: f32 = 0.636619772367581343075535053490057448_f32;
/// 2.0/sqrt(pi)
const frac_2_sqrtpi: f32 = 1.12837916709551257389615890312154517_f32;
pub const frac_2_sqrtpi: f32 = 1.12837916709551257389615890312154517_f32;
/// sqrt(2.0)
const sqrt2: f32 = 1.41421356237309504880168872420969808_f32;
pub const sqrt2: f32 = 1.41421356237309504880168872420969808_f32;
/// 1.0/sqrt(2.0)
const frac_1_sqrt2: f32 = 0.707106781186547524400844362104849039_f32;
pub const frac_1_sqrt2: f32 = 0.707106781186547524400844362104849039_f32;
/// Euler's number
const e: f32 = 2.71828182845904523536028747135266250_f32;
pub const e: f32 = 2.71828182845904523536028747135266250_f32;
/// log2(e)
const log2_e: f32 = 1.44269504088896340735992468100189214_f32;
pub const log2_e: f32 = 1.44269504088896340735992468100189214_f32;
/// log10(e)
const log10_e: f32 = 0.434294481903251827651128918916605082_f32;
pub const log10_e: f32 = 0.434294481903251827651128918916605082_f32;
/// ln(2.0)
const ln_2: f32 = 0.693147180559945309417232121458176568_f32;
pub const ln_2: f32 = 0.693147180559945309417232121458176568_f32;
/// ln(10.0)
const ln_10: f32 = 2.30258509299404568401799145468436421_f32;
pub const ln_10: f32 = 2.30258509299404568401799145468436421_f32;
}
pure fn signbit(x: f32) -> int {
pub pure fn signbit(x: f32) -> int {
if is_negative(x) { return 1; } else { return 0; }
}
pure fn logarithm(n: f32, b: f32) -> f32 {
pub pure fn logarithm(n: f32, b: f32) -> f32 {
return log2(n) / log2(b);
}
impl f32: num::Num {
pure fn add(&&other: f32) -> f32 { return self + other; }
pure fn sub(&&other: f32) -> f32 { return self - other; }
pure fn mul(&&other: f32) -> f32 { return self * other; }
pure fn div(&&other: f32) -> f32 { return self / other; }
pure fn modulo(&&other: f32) -> f32 { return self % other; }
pure fn add(other: &f32) -> f32 { return self + *other; }
pure fn sub(other: &f32) -> f32 { return self - *other; }
pure fn mul(other: &f32) -> f32 { return self * *other; }
pure fn div(other: &f32) -> f32 { return self / *other; }
pure fn modulo(other: &f32) -> f32 { return self % *other; }
pure fn neg() -> f32 { return -self; }
pure fn to_int() -> int { return self as int; }

View file

@ -4,95 +4,70 @@
//! Operations and constants for `f64`
// PORT
pub use cmath::c_double::*;
pub use cmath::c_double_targ_consts::*;
use cmath::c_double::*;
use cmath::c_double_targ_consts::*;
// Even though this module exports everything defined in it,
// because it contains re-exports, we also have to explicitly
// export locally defined things. That's a bit annoying.
export add, sub, mul, div, rem, lt, le, eq, ne, ge, gt;
export is_positive, is_negative, is_nonpositive, is_nonnegative;
export is_zero, is_infinite, is_finite;
export NaN, is_NaN, infinity, neg_infinity;
export consts;
export logarithm;
export acos, asin, atan, atan2, cbrt, ceil, copysign, cos, cosh, floor;
export erf, erfc, exp, expm1, exp2, abs, abs_sub;
export mul_add, fmax, fmin, nextafter, frexp, hypot, ldexp;
export lgamma, ln, log_radix, ln1p, log10, log2, ilog_radix;
export modf, pow, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc;
export signbit;
export epsilon;
export j0, j1, jn, y0, y1, yn;
export num;
// FIXME (#1433): obtain these in a different way
// These are not defined inside consts:: for consistency with
// the integer types
// PORT check per architecture
pub const radix: uint = 2u;
// FIXME (#1433): obtain these in a different way
pub const mantissa_digits: uint = 53u;
pub const digits: uint = 15u;
const radix: uint = 2u;
pub const epsilon: f64 = 2.2204460492503131e-16_f64;
const mantissa_digits: uint = 53u;
const digits: uint = 15u;
pub const min_value: f64 = 2.2250738585072014e-308_f64;
pub const max_value: f64 = 1.7976931348623157e+308_f64;
const epsilon: f64 = 2.2204460492503131e-16_f64;
pub const min_exp: int = -1021;
pub const max_exp: int = 1024;
const min_value: f64 = 2.2250738585072014e-308_f64;
const max_value: f64 = 1.7976931348623157e+308_f64;
pub const min_10_exp: int = -307;
pub const max_10_exp: int = 308;
const min_exp: int = -1021;
const max_exp: int = 1024;
pub const NaN: f64 = 0.0_f64/0.0_f64;
const min_10_exp: int = -307;
const max_10_exp: int = 308;
pub const infinity: f64 = 1.0_f64/0.0_f64;
const NaN: f64 = 0.0_f64/0.0_f64;
pub const neg_infinity: f64 = -1.0_f64/0.0_f64;
const infinity: f64 = 1.0_f64/0.0_f64;
pub pure fn is_NaN(f: f64) -> bool { f != f }
const neg_infinity: f64 = -1.0_f64/0.0_f64;
pub pure fn add(x: f64, y: f64) -> f64 { return x + y; }
pure fn is_NaN(f: f64) -> bool { f != f }
pub pure fn sub(x: f64, y: f64) -> f64 { return x - y; }
pure fn add(x: f64, y: f64) -> f64 { return x + y; }
pub pure fn mul(x: f64, y: f64) -> f64 { return x * y; }
pure fn sub(x: f64, y: f64) -> f64 { return x - y; }
pub pure fn div(x: f64, y: f64) -> f64 { return x / y; }
pure fn mul(x: f64, y: f64) -> f64 { return x * y; }
pub pure fn rem(x: f64, y: f64) -> f64 { return x % y; }
pure fn div(x: f64, y: f64) -> f64 { return x / y; }
pub pure fn lt(x: f64, y: f64) -> bool { return x < y; }
pure fn rem(x: f64, y: f64) -> f64 { return x % y; }
pub pure fn le(x: f64, y: f64) -> bool { return x <= y; }
pure fn lt(x: f64, y: f64) -> bool { return x < y; }
pub pure fn eq(x: f64, y: f64) -> bool { return x == y; }
pure fn le(x: f64, y: f64) -> bool { return x <= y; }
pub pure fn ne(x: f64, y: f64) -> bool { return x != y; }
pure fn eq(x: f64, y: f64) -> bool { return x == y; }
pub pure fn ge(x: f64, y: f64) -> bool { return x >= y; }
pure fn ne(x: f64, y: f64) -> bool { return x != y; }
pub pure fn gt(x: f64, y: f64) -> bool { return x > y; }
pure fn ge(x: f64, y: f64) -> bool { return x >= y; }
pure fn gt(x: f64, y: f64) -> bool { return x > y; }
pure fn sqrt(x: f64) -> f64 {
pub pure fn sqrt(x: f64) -> f64 {
cmath::c_double::sqrt(x as libc::c_double) as f64
}
/// Returns true if `x` is a positive number, including +0.0f640 and +Infinity
pure fn is_positive(x: f64) -> bool
pub pure fn is_positive(x: f64) -> bool
{ return x > 0.0f64 || (1.0f64/x) == infinity; }
/// Returns true if `x` is a negative number, including -0.0f640 and -Infinity
pure fn is_negative(x: f64) -> bool
pub pure fn is_negative(x: f64) -> bool
{ return x < 0.0f64 || (1.0f64/x) == neg_infinity; }
/**
@ -100,7 +75,7 @@ pure fn is_negative(x: f64) -> bool
*
* This is the same as `f64::is_negative`.
*/
pure fn is_nonpositive(x: f64) -> bool {
pub pure fn is_nonpositive(x: f64) -> bool {
return x < 0.0f64 || (1.0f64/x) == neg_infinity;
}
@ -109,87 +84,85 @@ pure fn is_nonpositive(x: f64) -> bool {
*
* This is the same as `f64::positive`.
*/
pure fn is_nonnegative(x: f64) -> bool {
pub pure fn is_nonnegative(x: f64) -> bool {
return x > 0.0f64 || (1.0f64/x) == infinity;
}
/// Returns true if `x` is a zero number (positive or negative zero)
pure fn is_zero(x: f64) -> bool {
pub pure fn is_zero(x: f64) -> bool {
return x == 0.0f64 || x == -0.0f64;
}
/// Returns true if `x`is an infinite number
pure fn is_infinite(x: f64) -> bool {
pub pure fn is_infinite(x: f64) -> bool {
return x == infinity || x == neg_infinity;
}
/// Returns true if `x`is a finite number
pure fn is_finite(x: f64) -> bool {
pub pure fn is_finite(x: f64) -> bool {
return !(is_NaN(x) || is_infinite(x));
}
// FIXME (#1999): add is_normal, is_subnormal, and fpclassify
/* Module: consts */
mod consts {
#[legacy_exports];
pub mod consts {
// FIXME (requires Issue #1433 to fix): replace with mathematical
// constants from cmath.
/// Archimedes' constant
const pi: f64 = 3.14159265358979323846264338327950288_f64;
pub const pi: f64 = 3.14159265358979323846264338327950288_f64;
/// pi/2.0
const frac_pi_2: f64 = 1.57079632679489661923132169163975144_f64;
pub const frac_pi_2: f64 = 1.57079632679489661923132169163975144_f64;
/// pi/4.0
const frac_pi_4: f64 = 0.785398163397448309615660845819875721_f64;
pub const frac_pi_4: f64 = 0.785398163397448309615660845819875721_f64;
/// 1.0/pi
const frac_1_pi: f64 = 0.318309886183790671537767526745028724_f64;
pub const frac_1_pi: f64 = 0.318309886183790671537767526745028724_f64;
/// 2.0/pi
const frac_2_pi: f64 = 0.636619772367581343075535053490057448_f64;
pub const frac_2_pi: f64 = 0.636619772367581343075535053490057448_f64;
/// 2.0/sqrt(pi)
const frac_2_sqrtpi: f64 = 1.12837916709551257389615890312154517_f64;
pub const frac_2_sqrtpi: f64 = 1.12837916709551257389615890312154517_f64;
/// sqrt(2.0)
const sqrt2: f64 = 1.41421356237309504880168872420969808_f64;
pub const sqrt2: f64 = 1.41421356237309504880168872420969808_f64;
/// 1.0/sqrt(2.0)
const frac_1_sqrt2: f64 = 0.707106781186547524400844362104849039_f64;
pub const frac_1_sqrt2: f64 = 0.707106781186547524400844362104849039_f64;
/// Euler's number
const e: f64 = 2.71828182845904523536028747135266250_f64;
pub const e: f64 = 2.71828182845904523536028747135266250_f64;
/// log2(e)
const log2_e: f64 = 1.44269504088896340735992468100189214_f64;
pub const log2_e: f64 = 1.44269504088896340735992468100189214_f64;
/// log10(e)
const log10_e: f64 = 0.434294481903251827651128918916605082_f64;
pub const log10_e: f64 = 0.434294481903251827651128918916605082_f64;
/// ln(2.0)
const ln_2: f64 = 0.693147180559945309417232121458176568_f64;
pub const ln_2: f64 = 0.693147180559945309417232121458176568_f64;
/// ln(10.0)
const ln_10: f64 = 2.30258509299404568401799145468436421_f64;
pub const ln_10: f64 = 2.30258509299404568401799145468436421_f64;
}
pure fn signbit(x: f64) -> int {
pub pure fn signbit(x: f64) -> int {
if is_negative(x) { return 1; } else { return 0; }
}
pure fn logarithm(n: f64, b: f64) -> f64 {
pub pure fn logarithm(n: f64, b: f64) -> f64 {
return log2(n) / log2(b);
}
impl f64: num::Num {
pure fn add(&&other: f64) -> f64 { return self + other; }
pure fn sub(&&other: f64) -> f64 { return self - other; }
pure fn mul(&&other: f64) -> f64 { return self * other; }
pure fn div(&&other: f64) -> f64 { return self / other; }
pure fn modulo(&&other: f64) -> f64 { return self % other; }
pure fn add(other: &f64) -> f64 { return self + *other; }
pure fn sub(other: &f64) -> f64 { return self - *other; }
pure fn mul(other: &f64) -> f64 { return self * *other; }
pure fn div(other: &f64) -> f64 { return self / *other; }
pure fn modulo(other: &f64) -> f64 { return self % *other; }
pure fn neg() -> f64 { return -self; }
pure fn to_int() -> int { return self as int; }

View file

@ -11,8 +11,6 @@ Simple compression
use libc::{c_void, size_t, c_int};
extern mod rustrt {
#[legacy_exports];
fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void,
src_buf_len: size_t,
pout_len: *size_t,
@ -29,14 +27,14 @@ const lz_fast : c_int = 0x1; // LZ with only one probe
const lz_norm : c_int = 0x80; // LZ with 128 probes, "normal"
const lz_best : c_int = 0xfff; // LZ with 4095 probes, "best"
fn deflate_bytes(bytes: &[const u8]) -> ~[u8] {
pub fn deflate_bytes(bytes: &[const u8]) -> ~[u8] {
do vec::as_const_buf(bytes) |b, len| {
unsafe {
let mut outsz : size_t = 0;
let res =
rustrt::tdefl_compress_mem_to_heap(b as *c_void,
len as size_t,
ptr::addr_of(outsz),
ptr::addr_of(&outsz),
lz_norm);
assert res as int != 0;
let out = vec::raw::from_buf(res as *u8,
@ -47,14 +45,14 @@ fn deflate_bytes(bytes: &[const u8]) -> ~[u8] {
}
}
fn inflate_bytes(bytes: &[const u8]) -> ~[u8] {
pub fn inflate_bytes(bytes: &[const u8]) -> ~[u8] {
do vec::as_const_buf(bytes) |b, len| {
unsafe {
let mut outsz : size_t = 0;
let res =
rustrt::tinfl_decompress_mem_to_heap(b as *c_void,
len as size_t,
ptr::addr_of(outsz),
ptr::addr_of(&outsz),
0);
assert res as int != 0;
let out = vec::raw::from_buf(res as *u8,
@ -71,12 +69,12 @@ fn test_flate_round_trip() {
let r = rand::Rng();
let mut words = ~[];
for 20.times {
vec::push(words, r.gen_bytes(r.gen_uint_range(1, 10)));
words.push(r.gen_bytes(r.gen_uint_range(1, 10)));
}
for 20.times {
let mut in = ~[];
for 2000.times {
vec::push_all(in, r.choose(words));
in.push_all(r.choose(words));
}
debug!("de/inflate of %u bytes of random word-sequences",
in.len());

View file

@ -7,26 +7,10 @@
// Even though this module exports everything defined in it,
// because it contains re-exports, we also have to explicitly
// export locally defined things. That's a bit annoying.
export to_str_common, to_str_exact, to_str, from_str;
export add, sub, mul, div, rem, lt, le, eq, ne, ge, gt;
export is_positive, is_negative, is_nonpositive, is_nonnegative;
export is_zero, is_infinite, is_finite;
export NaN, is_NaN, infinity, neg_infinity;
export consts;
export logarithm;
export acos, asin, atan, atan2, cbrt, ceil, copysign, cos, cosh, floor;
export erf, erfc, exp, expm1, exp2, abs, abs_sub;
export mul_add, fmax, fmin, nextafter, frexp, hypot, ldexp;
export lgamma, ln, log_radix, ln1p, log10, log2, ilog_radix;
export modf, pow, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc;
export signbit;
export pow_with_uint;
export num;
// export when m_float == c_double
export j0, j1, jn, y0, y1, yn;
// PORT this must match in width according to architecture
@ -44,56 +28,54 @@ use f64::{j0, j1, jn, y0, y1, yn};
use cmp::{Eq, Ord};
use num::from_int;
const NaN: float = 0.0/0.0;
pub const NaN: float = 0.0/0.0;
const infinity: float = 1.0/0.0;
pub const infinity: float = 1.0/0.0;
const neg_infinity: float = -1.0/0.0;
pub const neg_infinity: float = -1.0/0.0;
/* Module: consts */
mod consts {
#[legacy_exports];
pub mod consts {
// FIXME (requires Issue #1433 to fix): replace with mathematical
// constants from cmath.
/// Archimedes' constant
const pi: float = 3.14159265358979323846264338327950288;
pub const pi: float = 3.14159265358979323846264338327950288;
/// pi/2.0
const frac_pi_2: float = 1.57079632679489661923132169163975144;
pub const frac_pi_2: float = 1.57079632679489661923132169163975144;
/// pi/4.0
const frac_pi_4: float = 0.785398163397448309615660845819875721;
pub const frac_pi_4: float = 0.785398163397448309615660845819875721;
/// 1.0/pi
const frac_1_pi: float = 0.318309886183790671537767526745028724;
pub const frac_1_pi: float = 0.318309886183790671537767526745028724;
/// 2.0/pi
const frac_2_pi: float = 0.636619772367581343075535053490057448;
pub const frac_2_pi: float = 0.636619772367581343075535053490057448;
/// 2.0/sqrt(pi)
const frac_2_sqrtpi: float = 1.12837916709551257389615890312154517;
pub const frac_2_sqrtpi: float = 1.12837916709551257389615890312154517;
/// sqrt(2.0)
const sqrt2: float = 1.41421356237309504880168872420969808;
pub const sqrt2: float = 1.41421356237309504880168872420969808;
/// 1.0/sqrt(2.0)
const frac_1_sqrt2: float = 0.707106781186547524400844362104849039;
pub const frac_1_sqrt2: float = 0.707106781186547524400844362104849039;
/// Euler's number
const e: float = 2.71828182845904523536028747135266250;
pub const e: float = 2.71828182845904523536028747135266250;
/// log2(e)
const log2_e: float = 1.44269504088896340735992468100189214;
pub const log2_e: float = 1.44269504088896340735992468100189214;
/// log10(e)
const log10_e: float = 0.434294481903251827651128918916605082;
pub const log10_e: float = 0.434294481903251827651128918916605082;
/// ln(2.0)
const ln_2: float = 0.693147180559945309417232121458176568;
pub const ln_2: float = 0.693147180559945309417232121458176568;
/// ln(10.0)
const ln_10: float = 2.30258509299404568401799145468436421;
pub const ln_10: float = 2.30258509299404568401799145468436421;
}
/**
@ -109,7 +91,7 @@ mod consts {
* * digits - The number of significant digits
* * exact - Whether to enforce the exact number of significant digits
*/
fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
pub fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
if is_NaN(num) { return ~"NaN"; }
if num == infinity { return ~"inf"; }
if num == neg_infinity { return ~"-inf"; }
@ -139,11 +121,11 @@ fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
// while we still need digits
// build stack of digits
while ii > 0u && (frac >= epsilon_prime || exact) {
while ii > 0 && (frac >= epsilon_prime || exact) {
// store the next digit
frac *= 10.0;
let digit = frac as uint;
vec::push(fractionalParts, digit);
fractionalParts.push(digit);
// calculate the next frac
frac -= digit as float;
@ -153,25 +135,25 @@ fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
let mut acc;
let mut racc = ~"";
let mut carry = if frac * 10.0 as uint >= 5u { 1u } else { 0u };
let mut carry = if frac * 10.0 as uint >= 5 { 1 } else { 0 };
// turn digits into string
// using stack of digits
while vec::len(fractionalParts) > 0u {
let mut adjusted_digit = carry + vec::pop(fractionalParts);
while fractionalParts.is_not_empty() {
let mut adjusted_digit = carry + fractionalParts.pop();
if adjusted_digit == 10u {
carry = 1u;
adjusted_digit %= 10u
if adjusted_digit == 10 {
carry = 1;
adjusted_digit %= 10
} else {
carry = 0u
carry = 0;
};
racc = uint::str(adjusted_digit) + racc;
}
// pad decimals with trailing zeroes
while str::len(racc) < digits && exact {
while racc.len() < digits && exact {
racc += ~"0"
}
@ -194,12 +176,12 @@ fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
* * num - The float value
* * digits - The number of significant digits
*/
fn to_str_exact(num: float, digits: uint) -> ~str {
pub fn to_str_exact(num: float, digits: uint) -> ~str {
to_str_common(num, digits, true)
}
#[test]
fn test_to_str_exact_do_decimal() {
pub fn test_to_str_exact_do_decimal() {
let s = to_str_exact(5.0, 4u);
assert s == ~"5.0000";
}
@ -214,7 +196,7 @@ fn test_to_str_exact_do_decimal() {
* * num - The float value
* * digits - The number of significant digits
*/
fn to_str(num: float, digits: uint) -> ~str {
pub fn to_str(num: float, digits: uint) -> ~str {
to_str_common(num, digits, false)
}
@ -244,7 +226,7 @@ fn to_str(num: float, digits: uint) -> ~str {
* `none` if the string did not represent a valid number. Otherwise,
* `Some(n)` where `n` is the floating-point number represented by `[num]`.
*/
fn from_str(num: &str) -> Option<float> {
pub fn from_str(num: &str) -> Option<float> {
if num == "inf" {
return Some(infinity as float);
} else if num == "-inf" {
@ -379,7 +361,7 @@ fn from_str(num: &str) -> Option<float> {
*
* `NaN` if both `x` and `pow` are `0u`, otherwise `x^pow`
*/
fn pow_with_uint(base: uint, pow: uint) -> float {
pub fn pow_with_uint(base: uint, pow: uint) -> float {
if base == 0u {
if pow == 0u {
return NaN as float;
@ -399,40 +381,40 @@ fn pow_with_uint(base: uint, pow: uint) -> float {
return total;
}
pure fn is_positive(x: float) -> bool { f64::is_positive(x as f64) }
pure fn is_negative(x: float) -> bool { f64::is_negative(x as f64) }
pure fn is_nonpositive(x: float) -> bool { f64::is_nonpositive(x as f64) }
pure fn is_nonnegative(x: float) -> bool { f64::is_nonnegative(x as f64) }
pure fn is_zero(x: float) -> bool { f64::is_zero(x as f64) }
pure fn is_infinite(x: float) -> bool { f64::is_infinite(x as f64) }
pure fn is_finite(x: float) -> bool { f64::is_finite(x as f64) }
pure fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) }
pub pure fn is_positive(x: float) -> bool { f64::is_positive(x as f64) }
pub pure fn is_negative(x: float) -> bool { f64::is_negative(x as f64) }
pub pure fn is_nonpositive(x: float) -> bool { f64::is_nonpositive(x as f64) }
pub pure fn is_nonnegative(x: float) -> bool { f64::is_nonnegative(x as f64) }
pub pure fn is_zero(x: float) -> bool { f64::is_zero(x as f64) }
pub pure fn is_infinite(x: float) -> bool { f64::is_infinite(x as f64) }
pub pure fn is_finite(x: float) -> bool { f64::is_finite(x as f64) }
pub pure fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) }
pure fn abs(x: float) -> float { f64::abs(x as f64) as float }
pure fn sqrt(x: float) -> float { f64::sqrt(x as f64) as float }
pure fn atan(x: float) -> float { f64::atan(x as f64) as float }
pure fn sin(x: float) -> float { f64::sin(x as f64) as float }
pure fn cos(x: float) -> float { f64::cos(x as f64) as float }
pure fn tan(x: float) -> float { f64::tan(x as f64) as float }
pub pure fn abs(x: float) -> float { f64::abs(x as f64) as float }
pub pure fn sqrt(x: float) -> float { f64::sqrt(x as f64) as float }
pub pure fn atan(x: float) -> float { f64::atan(x as f64) as float }
pub pure fn sin(x: float) -> float { f64::sin(x as f64) as float }
pub pure fn cos(x: float) -> float { f64::cos(x as f64) as float }
pub pure fn tan(x: float) -> float { f64::tan(x as f64) as float }
impl float : Eq {
pure fn eq(other: &float) -> bool { self == (*other) }
pure fn ne(other: &float) -> bool { self != (*other) }
pub pure fn eq(other: &float) -> bool { self == (*other) }
pub pure fn ne(other: &float) -> bool { self != (*other) }
}
impl float : Ord {
pure fn lt(other: &float) -> bool { self < (*other) }
pure fn le(other: &float) -> bool { self <= (*other) }
pure fn ge(other: &float) -> bool { self >= (*other) }
pure fn gt(other: &float) -> bool { self > (*other) }
pub pure fn lt(other: &float) -> bool { self < (*other) }
pub pure fn le(other: &float) -> bool { self <= (*other) }
pub pure fn ge(other: &float) -> bool { self >= (*other) }
pub pure fn gt(other: &float) -> bool { self > (*other) }
}
impl float: num::Num {
pure fn add(&&other: float) -> float { return self + other; }
pure fn sub(&&other: float) -> float { return self - other; }
pure fn mul(&&other: float) -> float { return self * other; }
pure fn div(&&other: float) -> float { return self / other; }
pure fn modulo(&&other: float) -> float { return self % other; }
pub pure fn add(other: &float) -> float { return self + *other; }
pub pure fn sub(other: &float) -> float { return self - *other; }
pub pure fn mul(other: &float) -> float { return self * *other; }
pub pure fn div(other: &float) -> float { return self / *other; }
pure fn modulo(other: &float) -> float { return self % *other; }
pure fn neg() -> float { return -self; }
pure fn to_int() -> int { return self as int; }
@ -440,7 +422,7 @@ impl float: num::Num {
}
#[test]
fn test_from_str() {
pub fn test_from_str() {
assert from_str(~"3") == Some(3.);
assert from_str(~"3") == Some(3.);
assert from_str(~"3.14") == Some(3.14);
@ -483,7 +465,7 @@ fn test_from_str() {
}
#[test]
fn test_positive() {
pub fn test_positive() {
assert(is_positive(infinity));
assert(is_positive(1.));
assert(is_positive(0.));
@ -494,7 +476,7 @@ fn test_positive() {
}
#[test]
fn test_negative() {
pub fn test_negative() {
assert(!is_negative(infinity));
assert(!is_negative(1.));
assert(!is_negative(0.));
@ -505,7 +487,7 @@ fn test_negative() {
}
#[test]
fn test_nonpositive() {
pub fn test_nonpositive() {
assert(!is_nonpositive(infinity));
assert(!is_nonpositive(1.));
assert(!is_nonpositive(0.));
@ -516,7 +498,7 @@ fn test_nonpositive() {
}
#[test]
fn test_nonnegative() {
pub fn test_nonnegative() {
assert(is_nonnegative(infinity));
assert(is_nonnegative(1.));
assert(is_nonnegative(0.));
@ -527,24 +509,24 @@ fn test_nonnegative() {
}
#[test]
fn test_to_str_inf() {
pub fn test_to_str_inf() {
assert to_str(infinity, 10u) == ~"inf";
assert to_str(-infinity, 10u) == ~"-inf";
}
#[test]
fn test_traits() {
pub fn test_traits() {
fn test<U:num::Num cmp::Eq>(ten: &U) {
assert (ten.to_int() == 10);
let two: U = from_int(2);
assert (two.to_int() == 2);
assert (ten.add(two) == from_int(12));
assert (ten.sub(two) == from_int(8));
assert (ten.mul(two) == from_int(20));
assert (ten.div(two) == from_int(5));
assert (ten.modulo(two) == from_int(0));
assert (ten.add(&two) == from_int(12));
assert (ten.sub(&two) == from_int(8));
assert (ten.mul(&two) == from_int(20));
assert (ten.div(&two) == from_int(5));
assert (ten.modulo(&two) == from_int(0));
}
test(&10.0);

View file

@ -6,7 +6,7 @@
use option::Option;
trait FromStr {
pub trait FromStr {
static fn from_str(s: &str) -> Option<self>;
}

View file

@ -1,5 +1,5 @@
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
// tjc: re-forbid deprecated modes after snapshot
#[forbid(deprecated_pattern)];
/*!
@ -19,20 +19,8 @@ use either::Either;
use pipes::recv;
use cast::copy_lifetime;
export Future;
export extensions;
export from_value;
export from_port;
export from_fn;
export get;
export with;
export spawn;
// for task.rs
export future_pipe;
#[doc = "The future type"]
struct Future<A> {
pub struct Future<A> {
/*priv*/ mut state: FutureState<A>,
// FIXME(#2829) -- futures should not be copyable, because they close
@ -67,7 +55,7 @@ impl<A> Future<A> {
}
}
fn from_value<A>(+val: A) -> Future<A> {
pub fn from_value<A>(val: A) -> Future<A> {
/*!
* Create a future from a value
*
@ -78,7 +66,8 @@ fn from_value<A>(+val: A) -> Future<A> {
Future {state: Forced(~(move val))}
}
fn from_port<A:Send>(+port: future_pipe::client::waiting<A>) -> Future<A> {
pub fn from_port<A:Send>(port: future_pipe::client::waiting<A>) ->
Future<A> {
/*!
* Create a future from a port
*
@ -97,7 +86,7 @@ fn from_port<A:Send>(+port: future_pipe::client::waiting<A>) -> Future<A> {
}
}
fn from_fn<A>(+f: ~fn() -> A) -> Future<A> {
pub fn from_fn<A>(+f: ~fn() -> A) -> Future<A> {
/*!
* Create a future from a function.
*
@ -109,7 +98,7 @@ fn from_fn<A>(+f: ~fn() -> A) -> Future<A> {
Future {state: Pending(move f)}
}
fn spawn<A:Send>(+blk: fn~() -> A) -> Future<A> {
pub fn spawn<A:Send>(+blk: fn~() -> A) -> Future<A> {
/*!
* Create a future from a unique closure.
*
@ -122,7 +111,7 @@ fn spawn<A:Send>(+blk: fn~() -> A) -> Future<A> {
}))
}
fn get_ref<A>(future: &r/Future<A>) -> &r/A {
pub fn get_ref<A>(future: &r/Future<A>) -> &r/A {
/*!
* Executes the future's closure and then returns a borrowed
* pointer to the result. The borrowed pointer lasts as long as
@ -160,13 +149,13 @@ fn get_ref<A>(future: &r/Future<A>) -> &r/A {
}
}
fn get<A:Copy>(future: &Future<A>) -> A {
pub fn get<A:Copy>(future: &Future<A>) -> A {
//! Get the value of the future
*get_ref(future)
}
fn with<A,B>(future: &Future<A>, blk: fn((&A)) -> B) -> B {
pub fn with<A,B>(future: &Future<A>, blk: fn((&A)) -> B) -> B {
//! Work with the value without copying it
blk(get_ref(future))
@ -179,16 +168,15 @@ proto! future_pipe (
)
#[allow(non_implicitly_copyable_typarams)]
mod test {
#[legacy_exports];
pub mod test {
#[test]
fn test_from_value() {
pub fn test_from_value() {
let f = from_value(~"snail");
assert get(&f) == ~"snail";
}
#[test]
fn test_from_port() {
pub fn test_from_port() {
let (po, ch) = future_pipe::init();
future_pipe::server::completed(ch, ~"whale");
let f = from_port(po);
@ -196,43 +184,43 @@ mod test {
}
#[test]
fn test_from_fn() {
pub fn test_from_fn() {
let f = from_fn(|| ~"brail");
assert get(&f) == ~"brail";
}
#[test]
fn test_interface_get() {
pub fn test_interface_get() {
let f = from_value(~"fail");
assert f.get() == ~"fail";
}
#[test]
fn test_with() {
pub fn test_with() {
let f = from_value(~"nail");
assert with(&f, |v| copy *v) == ~"nail";
}
#[test]
fn test_get_ref_method() {
pub fn test_get_ref_method() {
let f = from_value(22);
assert *f.get_ref() == 22;
}
#[test]
fn test_get_ref_fn() {
pub fn test_get_ref_fn() {
let f = from_value(22);
assert *get_ref(&f) == 22;
}
#[test]
fn test_interface_with() {
pub fn test_interface_with() {
let f = from_value(~"kale");
assert f.with(|v| copy *v) == ~"kale";
}
#[test]
fn test_spawn() {
pub fn test_spawn() {
let f = spawn(|| ~"bale");
assert get(&f) == ~"bale";
}
@ -240,13 +228,13 @@ mod test {
#[test]
#[should_fail]
#[ignore(cfg(target_os = "win32"))]
fn test_futurefail() {
pub fn test_futurefail() {
let f = spawn(|| fail);
let _x: ~str = get(&f);
}
#[test]
fn test_sendable_future() {
pub fn test_sendable_future() {
let expected = ~"schlorf";
let f = do spawn |copy expected| { copy expected };
do task::spawn {

View file

@ -29,15 +29,11 @@ with destructors.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];
use stackwalk::Word;
pub use stackwalk::Word;
use libc::size_t;
use libc::uintptr_t;
use send_map::linear::LinearMap;
export Word;
export gc;
export cleanup_stack_for_failure;
// Mirrors rust_stack.h stk_seg
struct StackSegment {
prev: *StackSegment,
@ -268,7 +264,7 @@ unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) {
}
}
fn gc() {
pub fn gc() {
unsafe {
// Abort when GC is disabled.
if get_safe_point_count() == 0 {
@ -301,7 +297,7 @@ fn expect_sentinel() -> bool { false }
// This should only be called from fail, as it will drop the roots
// which are *live* on the stack, rather than dropping those that are
// dead.
fn cleanup_stack_for_failure() {
pub fn cleanup_stack_for_failure() {
unsafe {
// Abort when GC is disabled.
if get_safe_point_count() == 0 {
@ -320,7 +316,7 @@ fn cleanup_stack_for_failure() {
// own stack roots on the stack anyway.
let sentinel_box = ~0;
let sentinel: **Word = if expect_sentinel() {
cast::reinterpret_cast(&ptr::addr_of(sentinel_box))
cast::reinterpret_cast(&ptr::addr_of(&sentinel_box))
} else {
ptr::null()
};

View file

@ -17,9 +17,6 @@ use io::Writer;
use io::WriterUtil;
use to_bytes::IterBytes;
export Streaming, State, Hash, HashUtil;
export default_state;
/**
* Types that can meaningfully be hashed should implement this.
*
@ -32,7 +29,7 @@ export default_state;
* the rest. This is the recommended approach, since constructing
* good keyed hash functions is quite difficult.
*/
trait Hash {
pub trait Hash {
/**
* Compute a "keyed" hash of the value implementing the trait,
* taking `k0` and `k1` as "keying" parameters that randomize or
@ -49,7 +46,7 @@ trait Hash {
}
// When we have default methods, won't need this.
trait HashUtil {
pub trait HashUtil {
pure fn hash() -> u64;
}
@ -59,7 +56,7 @@ impl <A: Hash> A: HashUtil {
}
/// Streaming hash-functions should implement this.
trait Streaming {
pub trait Streaming {
fn input((&[const u8]));
// These can be refactored some when we have default methods.
fn result_bytes() -> ~[u8];
@ -139,15 +136,15 @@ pure fn hash_keyed_5<A: IterBytes,
// Implement State as SipState
type State = SipState;
pub type State = SipState;
#[inline(always)]
fn State(k0: u64, k1: u64) -> State {
pub fn State(k0: u64, k1: u64) -> State {
SipState(k0, k1)
}
#[inline(always)]
fn default_state() -> State {
pub fn default_state() -> State {
State(0,0)
}
@ -361,7 +358,7 @@ impl &SipState : Streaming {
}
#[test]
fn test_siphash() {
pub fn test_siphash() {
let vecs : [[u8]/8]/64 = [
[ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, ]/_,
[ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, ]/_,
@ -468,26 +465,26 @@ fn test_siphash() {
}
#[test] #[cfg(target_arch = "arm")]
fn test_hash_uint() {
pub fn test_hash_uint() {
let val = 0xdeadbeef_deadbeef_u64;
assert (val as u64).hash() != (val as uint).hash();
assert (val as u32).hash() == (val as uint).hash();
}
#[test] #[cfg(target_arch = "x86_64")]
fn test_hash_uint() {
pub fn test_hash_uint() {
let val = 0xdeadbeef_deadbeef_u64;
assert (val as u64).hash() == (val as uint).hash();
assert (val as u32).hash() != (val as uint).hash();
}
#[test] #[cfg(target_arch = "x86")]
fn test_hash_uint() {
pub fn test_hash_uint() {
let val = 0xdeadbeef_deadbeef_u64;
assert (val as u64).hash() != (val as uint).hash();
assert (val as u32).hash() == (val as uint).hash();
}
#[test]
fn test_hash_idempotent() {
pub fn test_hash_idempotent() {
let val64 = 0xdeadbeef_deadbeef_u64;
val64.hash() == val64.hash();
let val32 = 0xdeadbeef_u32;
@ -495,7 +492,7 @@ fn test_hash_idempotent() {
}
#[test]
fn test_hash_no_bytes_dropped_64() {
pub fn test_hash_no_bytes_dropped_64() {
let val = 0xdeadbeef_deadbeef_u64;
assert val.hash() != zero_byte(val, 0).hash();
@ -514,7 +511,7 @@ fn test_hash_no_bytes_dropped_64() {
}
#[test]
fn test_hash_no_bytes_dropped_32() {
pub fn test_hash_no_bytes_dropped_32() {
let val = 0xdeadbeef_u32;
assert val.hash() != zero_byte(val, 0).hash();

View file

@ -1,5 +1,5 @@
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
// tjc: re-forbid deprecated modes after snapshot
#[forbid(deprecated_pattern)];
use T = inst::T;
@ -7,49 +7,36 @@ use cmp::{Eq, Ord};
use from_str::FromStr;
use num::from_int;
export min_value, max_value;
export min, max;
export add, sub, mul, div, rem;
export lt, le, eq, ne, ge, gt;
export is_positive, is_negative;
export is_nonpositive, is_nonnegative;
export range;
export compl;
export abs;
export parse_bytes, from_str, to_str, to_str_bytes, str;
export num, ord, eq, times, timesi;
export bits, bytes;
pub const bits : uint = inst::bits;
pub const bytes : uint = (inst::bits / 8);
const bits : uint = inst::bits;
const bytes : uint = (inst::bits / 8);
pub const min_value: T = (-1 as T) << (bits - 1);
pub const max_value: T = min_value - 1 as T;
const min_value: T = (-1 as T) << (bits - 1);
const max_value: T = min_value - 1 as T;
pub pure fn min(x: T, y: T) -> T { if x < y { x } else { y } }
pub pure fn max(x: T, y: T) -> T { if x > y { x } else { y } }
pure fn min(x: T, y: T) -> T { if x < y { x } else { y } }
pure fn max(x: T, y: T) -> T { if x > y { x } else { y } }
pub pure fn add(x: T, y: T) -> T { x + y }
pub pure fn sub(x: T, y: T) -> T { x - y }
pub pure fn mul(x: T, y: T) -> T { x * y }
pub pure fn div(x: T, y: T) -> T { x / y }
pub pure fn rem(x: T, y: T) -> T { x % y }
pure fn add(x: T, y: T) -> T { x + y }
pure fn sub(x: T, y: T) -> T { x - y }
pure fn mul(x: T, y: T) -> T { x * y }
pure fn div(x: T, y: T) -> T { x / y }
pure fn rem(x: T, y: T) -> T { x % y }
pub pure fn lt(x: T, y: T) -> bool { x < y }
pub pure fn le(x: T, y: T) -> bool { x <= y }
pub pure fn eq(x: T, y: T) -> bool { x == y }
pub pure fn ne(x: T, y: T) -> bool { x != y }
pub pure fn ge(x: T, y: T) -> bool { x >= y }
pub pure fn gt(x: T, y: T) -> bool { x > y }
pure fn lt(x: T, y: T) -> bool { x < y }
pure fn le(x: T, y: T) -> bool { x <= y }
pure fn eq(x: T, y: T) -> bool { x == y }
pure fn ne(x: T, y: T) -> bool { x != y }
pure fn ge(x: T, y: T) -> bool { x >= y }
pure fn gt(x: T, y: T) -> bool { x > y }
pure fn is_positive(x: T) -> bool { x > 0 as T }
pure fn is_negative(x: T) -> bool { x < 0 as T }
pure fn is_nonpositive(x: T) -> bool { x <= 0 as T }
pure fn is_nonnegative(x: T) -> bool { x >= 0 as T }
pub pure fn is_positive(x: T) -> bool { x > 0 as T }
pub pure fn is_negative(x: T) -> bool { x < 0 as T }
pub pure fn is_nonpositive(x: T) -> bool { x <= 0 as T }
pub pure fn is_nonnegative(x: T) -> bool { x >= 0 as T }
#[inline(always)]
/// Iterate over the range [`lo`..`hi`)
fn range(lo: T, hi: T, it: fn(T) -> bool) {
pub fn range(lo: T, hi: T, it: fn(T) -> bool) {
let mut i = lo;
while i < hi {
if !it(i) { break }
@ -58,13 +45,13 @@ fn range(lo: T, hi: T, it: fn(T) -> bool) {
}
/// Computes the bitwise complement
pure fn compl(i: T) -> T {
pub pure fn compl(i: T) -> T {
-1 as T ^ i
}
/// Computes the absolute value
// FIXME: abs should return an unsigned int (#2353)
pure fn abs(i: T) -> T {
pub pure fn abs(i: T) -> T {
if is_negative(i) { -i } else { i }
}
@ -81,11 +68,11 @@ impl T : Eq {
}
impl T: num::Num {
pure fn add(&&other: T) -> T { return self + other; }
pure fn sub(&&other: T) -> T { return self - other; }
pure fn mul(&&other: T) -> T { return self * other; }
pure fn div(&&other: T) -> T { return self / other; }
pure fn modulo(&&other: T) -> T { return self % other; }
pure fn add(other: &T) -> T { return self + *other; }
pure fn sub(other: &T) -> T { return self - *other; }
pure fn mul(other: &T) -> T { return self * *other; }
pure fn div(other: &T) -> T { return self / *other; }
pure fn modulo(other: &T) -> T { return self % *other; }
pure fn neg() -> T { return -self; }
pure fn to_int() -> int { return self as int; }
@ -137,7 +124,7 @@ impl T: iter::TimesIx {
* * buf - A byte buffer
* * radix - The base of the number
*/
fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> {
pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> {
if vec::len(buf) == 0u { return None; }
let mut i = vec::len(buf) - 1u;
let mut start = 0u;
@ -160,14 +147,14 @@ fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> {
}
/// Parse a string to an int
fn from_str(s: &str) -> Option<T> { parse_bytes(str::to_bytes(s), 10u) }
pub fn from_str(s: &str) -> Option<T> { parse_bytes(str::to_bytes(s), 10u) }
impl T : FromStr {
static fn from_str(s: &str) -> Option<T> { from_str(s) }
}
/// Convert to a string in a given base
fn to_str(n: T, radix: uint) -> ~str {
pub fn to_str(n: T, radix: uint) -> ~str {
do to_str_bytes(n, radix) |slice| {
do vec::as_imm_buf(slice) |p, len| {
unsafe { str::raw::from_buf_len(p, len) }
@ -175,7 +162,7 @@ fn to_str(n: T, radix: uint) -> ~str {
}
}
fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
pub fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
if n < 0 as T {
uint::to_str_bytes(true, -n as uint, radix, f)
} else {
@ -184,7 +171,7 @@ fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
}
/// Convert to a string
fn str(i: T) -> ~str { return to_str(i, 10u); }
pub fn str(i: T) -> ~str { return to_str(i, 10u); }
// FIXME: Has alignment issues on windows and 32-bit linux (#2609)
#[test]
@ -244,17 +231,17 @@ fn test_to_str() {
#[test]
fn test_interfaces() {
fn test<U:num::Num cmp::Eq>(+ten: U) {
fn test<U:num::Num cmp::Eq>(ten: U) {
assert (ten.to_int() == 10);
let two: U = from_int(2);
assert (two.to_int() == 2);
assert (ten.add(two) == from_int(12));
assert (ten.sub(two) == from_int(8));
assert (ten.mul(two) == from_int(20));
assert (ten.div(two) == from_int(5));
assert (ten.modulo(two) == from_int(0));
assert (ten.add(&two) == from_int(12));
assert (ten.sub(&two) == from_int(8));
assert (ten.mul(&two) == from_int(20));
assert (ten.div(&two) == from_int(5));
assert (ten.modulo(&two) == from_int(0));
assert (ten.neg() == from_int(-10));
}

View file

@ -1,2 +1,2 @@
type T = i16;
const bits: uint = u16::bits;
pub type T = i16;
pub const bits: uint = u16::bits;

View file

@ -1,2 +1,2 @@
type T = i32;
const bits: uint = u32::bits;
pub type T = i32;
pub const bits: uint = u32::bits;

View file

@ -1,2 +1,2 @@
type T = i64;
const bits: uint = u64::bits;
pub type T = i64;
pub const bits: uint = u64::bits;

View file

@ -1,2 +1,2 @@
type T = i8;
const bits: uint = u8::bits;
pub type T = i8;
pub const bits: uint = u8::bits;

View file

@ -1,8 +1,8 @@
type T = int;
const bits: uint = uint::bits;
pub type T = int;
pub const bits: uint = uint::bits;
/// Returns `base` raised to the power of `exponent`
fn pow(base: int, exponent: uint) -> int {
pub fn pow(base: int, exponent: uint) -> int {
if exponent == 0u { return 1; } //Not mathemtically true if ~[base == 0]
if base == 0 { return 0; }
let mut my_pow = exponent;

View file

@ -17,7 +17,6 @@ type fd_t = c_int;
#[abi = "cdecl"]
extern mod rustrt {
#[legacy_exports];
fn rust_get_stdin() -> *libc::FILE;
fn rust_get_stdout() -> *libc::FILE;
fn rust_get_stderr() -> *libc::FILE;
@ -27,11 +26,11 @@ extern mod rustrt {
// FIXME (#2004): This is all buffered. We might need an unbuffered variant
// as well
enum SeekStyle { SeekSet, SeekEnd, SeekCur, }
pub enum SeekStyle { SeekSet, SeekEnd, SeekCur, }
// The raw underlying reader trait. All readers must implement this.
trait Reader {
pub trait Reader {
// FIXME (#2004): Seekable really should be orthogonal.
// FIXME (#2982): This should probably return an error.
@ -45,19 +44,30 @@ trait Reader {
// Generic utility functions defined on readers
trait ReaderUtil {
pub trait ReaderUtil {
fn read_bytes(len: uint) -> ~[u8];
fn read_line() -> ~str;
fn read_chars(n: uint) -> ~[char];
fn read_char() -> char;
fn read_c_str() -> ~str;
fn read_le_uint(size: uint) -> uint;
fn read_le_int(size: uint) -> int;
fn read_be_uint(size: uint) -> uint;
fn read_whole_stream() -> ~[u8];
fn each_byte(it: fn(int) -> bool);
fn each_char(it: fn(char) -> bool);
fn each_line(it: fn((&str)) -> bool);
}
impl<T: Reader> T : ReaderUtil {
fn read_bytes(len: uint) -> ~[u8] {
let mut buf = vec::with_capacity(len);
unsafe { vec::raw::set_len(buf, len); }
unsafe { vec::raw::set_len(&mut buf, len); }
let count = self.read(buf, len);
unsafe { vec::raw::set_len(buf, count); }
unsafe { vec::raw::set_len(&mut buf, count); }
move buf
}
fn read_line() -> ~str {
@ -65,78 +75,78 @@ impl<T: Reader> T : ReaderUtil {
loop {
let ch = self.read_byte();
if ch == -1 || ch == 10 { break; }
vec::push(buf, ch as u8);
buf.push(ch as u8);
}
str::from_bytes(buf)
}
}
impl Reader {
fn read_chars(n: uint) -> ~[char] {
// returns the (consumed offset, n_req), appends characters to &chars
fn chars_from_bytes(buf: ~[u8], &chars: ~[char]) -> (uint, uint) {
let mut i = 0u;
while i < vec::len(buf) {
fn chars_from_bytes<T: Reader>(buf: &~[u8], chars: &mut ~[char])
-> (uint, uint) {
let mut i = 0;
let buf_len = buf.len();
while i < buf_len {
let b0 = buf[i];
let w = str::utf8_char_width(b0);
let end = i + w;
i += 1u;
assert (w > 0u);
if w == 1u {
vec::push(chars, b0 as char );
i += 1;
assert (w > 0);
if w == 1 {
chars.push(b0 as char);
loop;
}
// can't satisfy this char with the existing data
if end > vec::len(buf) {
return (i - 1u, end - vec::len(buf));
if end > buf_len {
return (i - 1, end - buf_len);
}
let mut val = 0u;
let mut val = 0;
while i < end {
let next = buf[i] as int;
i += 1u;
i += 1;
assert (next > -1);
assert (next & 192 == 128);
val <<= 6u;
val <<= 6;
val += (next & 63) as uint;
}
// See str::char_at
val += ((b0 << ((w + 1u) as u8)) as uint)
<< (w - 1u) * 6u - w - 1u;
vec::push(chars, val as char );
val += ((b0 << ((w + 1) as u8)) as uint)
<< (w - 1) * 6 - w - 1u;
chars.push(val as char);
}
return (i, 0u);
return (i, 0);
}
let mut buf: ~[u8] = ~[];
let mut chars: ~[char] = ~[];
// might need more bytes, but reading n will never over-read
let mut nbread = n;
while nbread > 0u {
while nbread > 0 {
let data = self.read_bytes(nbread);
if vec::len(data) == 0u {
if data.is_empty() {
// eof - FIXME (#2004): should we do something if
// we're split in a unicode char?
break;
}
vec::push_all(buf, data);
let (offset, nbreq) = chars_from_bytes(buf, chars);
let ncreq = n - vec::len(chars);
buf.push_all(data);
let (offset, nbreq) = chars_from_bytes::<T>(&buf, &mut chars);
let ncreq = n - chars.len();
// again we either know we need a certain number of bytes
// to complete a character, or we make sure we don't
// over-read by reading 1-byte per char needed
nbread = if ncreq > nbreq { ncreq } else { nbreq };
if nbread > 0u {
buf = vec::slice(buf, offset, vec::len(buf));
if nbread > 0 {
buf = vec::slice(buf, offset, buf.len());
}
}
move chars
}
fn read_char() -> char {
let c = self.read_chars(1u);
if vec::len(c) == 0u {
let c = self.read_chars(1);
if vec::len(c) == 0 {
return -1 as char; // FIXME will this stay valid? // #2004
}
assert(vec::len(c) == 1u);
assert(vec::len(c) == 1);
return c[0];
}
@ -144,7 +154,7 @@ impl Reader {
let mut buf: ~[u8] = ~[];
loop {
let ch = self.read_byte();
if ch < 1 { break; } else { vec::push(buf, ch as u8); }
if ch < 1 { break; } else { buf.push(ch as u8); }
}
str::from_bytes(buf)
}
@ -179,7 +189,7 @@ impl Reader {
fn read_whole_stream() -> ~[u8] {
let mut buf: ~[u8] = ~[];
while !self.eof() { vec::push_all(buf, self.read_bytes(2048u)); }
while !self.eof() { buf.push_all(self.read_bytes(2048u)); }
move buf
}
@ -195,7 +205,7 @@ impl Reader {
}
}
fn each_line(it: fn(~str) -> bool) {
fn each_line(it: fn(s: &str) -> bool) {
while !self.eof() {
if !it(self.read_line()) { break; }
}
@ -256,7 +266,7 @@ fn FILERes(f: *libc::FILE) -> FILERes {
}
}
fn FILE_reader(f: *libc::FILE, cleanup: bool) -> Reader {
pub fn FILE_reader(f: *libc::FILE, cleanup: bool) -> Reader {
if cleanup {
{base: f, cleanup: FILERes(f)} as Reader
} else {
@ -268,9 +278,9 @@ fn FILE_reader(f: *libc::FILE, cleanup: bool) -> Reader {
// top-level functions that take a reader, or a set of default methods on
// reader (which can then be called reader)
fn stdin() -> Reader { rustrt::rust_get_stdin() as Reader }
pub fn stdin() -> Reader { rustrt::rust_get_stdin() as Reader }
fn file_reader(path: &Path) -> Result<Reader, ~str> {
pub fn file_reader(path: &Path) -> Result<Reader, ~str> {
let f = os::as_c_charp(path.to_str(), |pathbuf| {
os::as_c_charp("r", |modebuf|
libc::fopen(pathbuf, modebuf)
@ -286,7 +296,7 @@ fn file_reader(path: &Path) -> Result<Reader, ~str> {
// Byte buffer readers
type ByteBuf = {buf: &[const u8], mut pos: uint};
pub type ByteBuf = {buf: &[const u8], mut pos: uint};
impl ByteBuf: Reader {
fn read(buf: &[mut u8], len: uint) -> uint {
@ -315,21 +325,21 @@ impl ByteBuf: Reader {
fn tell() -> uint { self.pos }
}
fn with_bytes_reader<t>(bytes: &[u8], f: fn(Reader) -> t) -> t {
pub fn with_bytes_reader<t>(bytes: &[u8], f: fn(Reader) -> t) -> t {
f({buf: bytes, mut pos: 0u} as Reader)
}
fn with_str_reader<T>(s: &str, f: fn(Reader) -> T) -> T {
pub fn with_str_reader<T>(s: &str, f: fn(Reader) -> T) -> T {
str::byte_slice(s, |bytes| with_bytes_reader(bytes, f))
}
// Writing
enum FileFlag { Append, Create, Truncate, NoFlag, }
pub enum FileFlag { Append, Create, Truncate, NoFlag, }
// What type of writer are we?
enum WriterType { Screen, File }
pub enum WriterType { Screen, File }
impl WriterType : Eq {
pub impl WriterType : Eq {
pure fn eq(other: &WriterType) -> bool {
match (self, (*other)) {
(Screen, Screen) | (File, File) => true,
@ -341,7 +351,7 @@ impl WriterType : Eq {
// FIXME (#2004): Seekable really should be orthogonal.
// FIXME (#2004): eventually u64
trait Writer {
pub trait Writer {
fn write(v: &[const u8]);
fn seek(int, SeekStyle);
fn tell() -> uint;
@ -382,7 +392,7 @@ impl *libc::FILE: Writer {
}
}
fn FILE_writer(f: *libc::FILE, cleanup: bool) -> Writer {
pub fn FILE_writer(f: *libc::FILE, cleanup: bool) -> Writer {
if cleanup {
{base: f, cleanup: FILERes(f)} as Writer
} else {
@ -431,7 +441,7 @@ fn FdRes(fd: fd_t) -> FdRes {
}
}
fn fd_writer(fd: fd_t, cleanup: bool) -> Writer {
pub fn fd_writer(fd: fd_t, cleanup: bool) -> Writer {
if cleanup {
{base: fd, cleanup: FdRes(fd)} as Writer
} else {
@ -440,7 +450,7 @@ fn fd_writer(fd: fd_t, cleanup: bool) -> Writer {
}
fn mk_file_writer(path: &Path, flags: ~[FileFlag])
pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
-> Result<Writer, ~str> {
#[cfg(windows)]
@ -470,7 +480,8 @@ fn mk_file_writer(path: &Path, flags: ~[FileFlag])
}
}
fn u64_to_le_bytes<T>(n: u64, size: uint, f: fn(v: &[u8]) -> T) -> T {
pub fn u64_to_le_bytes<T>(n: u64, size: uint,
f: fn(v: &[u8]) -> T) -> T {
assert size <= 8u;
match size {
1u => f(&[n as u8]),
@ -492,7 +503,7 @@ fn u64_to_le_bytes<T>(n: u64, size: uint, f: fn(v: &[u8]) -> T) -> T {
let mut bytes: ~[u8] = ~[], i = size, n = n;
while i > 0u {
vec::push(bytes, (n & 255_u64) as u8);
bytes.push((n & 255_u64) as u8);
n >>= 8_u64;
i -= 1u;
}
@ -501,7 +512,8 @@ fn u64_to_le_bytes<T>(n: u64, size: uint, f: fn(v: &[u8]) -> T) -> T {
}
}
fn u64_to_be_bytes<T>(n: u64, size: uint, f: fn(v: &[u8]) -> T) -> T {
pub fn u64_to_be_bytes<T>(n: u64, size: uint,
f: fn(v: &[u8]) -> T) -> T {
assert size <= 8u;
match size {
1u => f(&[n as u8]),
@ -524,7 +536,7 @@ fn u64_to_be_bytes<T>(n: u64, size: uint, f: fn(v: &[u8]) -> T) -> T {
let mut i = size;
while i > 0u {
let shift = ((i - 1u) * 8u) as u64;
vec::push(bytes, (n >> shift) as u8);
bytes.push((n >> shift) as u8);
i -= 1u;
}
f(bytes)
@ -532,7 +544,8 @@ fn u64_to_be_bytes<T>(n: u64, size: uint, f: fn(v: &[u8]) -> T) -> T {
}
}
fn u64_from_be_bytes(data: &[const u8], start: uint, size: uint) -> u64 {
pub fn u64_from_be_bytes(data: &[const u8],
start: uint, size: uint) -> u64 {
let mut sz = size;
assert (sz <= 8u);
let mut val = 0_u64;
@ -547,7 +560,7 @@ fn u64_from_be_bytes(data: &[const u8], start: uint, size: uint) -> u64 {
// FIXME: #3048 combine trait+impl (or just move these to
// default methods on writer)
trait WriterUtil {
pub trait WriterUtil {
fn write_char(ch: char);
fn write_str(s: &str);
fn write_line(s: &str);
@ -644,13 +657,13 @@ impl<T: Writer> T : WriterUtil {
}
#[allow(non_implicitly_copyable_typarams)]
fn file_writer(path: &Path, flags: ~[FileFlag]) -> Result<Writer, ~str> {
result::chain(mk_file_writer(path, flags), |w| result::Ok(w))
pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<Writer, ~str> {
mk_file_writer(path, flags).chain(|w| result::Ok(w))
}
// FIXME: fileflags // #2004
fn buffered_file_writer(path: &Path) -> Result<Writer, ~str> {
pub fn buffered_file_writer(path: &Path) -> Result<Writer, ~str> {
let f = do os::as_c_charp(path.to_str()) |pathbuf| {
do os::as_c_charp("w") |modebuf| {
libc::fopen(pathbuf, modebuf)
@ -664,13 +677,13 @@ fn buffered_file_writer(path: &Path) -> Result<Writer, ~str> {
// FIXME (#2004) it would be great if this could be a const
// FIXME (#2004) why are these different from the way stdin() is
// implemented?
fn stdout() -> Writer { fd_writer(libc::STDOUT_FILENO as c_int, false) }
fn stderr() -> Writer { fd_writer(libc::STDERR_FILENO as c_int, false) }
pub fn stdout() -> Writer { fd_writer(libc::STDOUT_FILENO as c_int, false) }
pub fn stderr() -> Writer { fd_writer(libc::STDERR_FILENO as c_int, false) }
fn print(s: &str) { stdout().write_str(s); }
fn println(s: &str) { stdout().write_line(s); }
pub fn print(s: &str) { stdout().write_str(s); }
pub fn println(s: &str) { stdout().write_line(s); }
struct BytesWriter {
pub struct BytesWriter {
buf: DVec<u8>,
mut pos: uint,
}
@ -684,10 +697,12 @@ impl BytesWriter: Writer {
let count = uint::max(buf_len, self.pos + v_len);
vec::reserve(&mut buf, count);
unsafe { vec::raw::set_len(buf, count); }
unsafe { vec::raw::set_len(&mut buf, count); }
let view = vec::mut_view(buf, self.pos, count);
vec::bytes::memcpy(view, v, v_len);
{
let view = vec::mut_view(buf, self.pos, count);
vec::bytes::memcpy(view, v, v_len);
}
self.pos += v_len;
@ -712,28 +727,28 @@ impl @BytesWriter : Writer {
fn get_type() -> WriterType { (*self).get_type() }
}
fn BytesWriter() -> BytesWriter {
pub fn BytesWriter() -> BytesWriter {
BytesWriter { buf: DVec(), mut pos: 0u }
}
fn with_bytes_writer(f: fn(Writer)) -> ~[u8] {
pub fn with_bytes_writer(f: fn(Writer)) -> ~[u8] {
let wr = @BytesWriter();
f(wr as Writer);
wr.buf.check_out(|buf| buf)
}
fn with_str_writer(f: fn(Writer)) -> ~str {
pub fn with_str_writer(f: fn(Writer)) -> ~str {
let mut v = with_bytes_writer(f);
// Make sure the vector has a trailing null and is proper utf8.
vec::push(v, 0);
v.push(0);
assert str::is_utf8(v);
unsafe { move ::cast::transmute(v) }
}
// Utility functions
fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) ->
pub fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) ->
uint {
let mut bpos = pos as int;
let blen = len as int;
@ -747,7 +762,7 @@ fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) ->
}
#[allow(non_implicitly_copyable_typarams)]
fn read_whole_file_str(file: &Path) -> Result<~str, ~str> {
pub fn read_whole_file_str(file: &Path) -> Result<~str, ~str> {
result::chain(read_whole_file(file), |bytes| {
if str::is_utf8(bytes) {
result::Ok(str::from_bytes(bytes))
@ -760,7 +775,7 @@ fn read_whole_file_str(file: &Path) -> Result<~str, ~str> {
// FIXME (#2004): implement this in a low-level way. Going through the
// abstractions is pointless.
#[allow(non_implicitly_copyable_typarams)]
fn read_whole_file(file: &Path) -> Result<~[u8], ~str> {
pub fn read_whole_file(file: &Path) -> Result<~[u8], ~str> {
result::chain(file_reader(file), |rdr| {
result::Ok(rdr.read_whole_stream())
})
@ -768,10 +783,9 @@ fn read_whole_file(file: &Path) -> Result<~[u8], ~str> {
// fsync related
mod fsync {
#[legacy_exports];
pub mod fsync {
enum Level {
pub enum Level {
// whatever fsync does on that platform
FSync,
@ -786,7 +800,7 @@ mod fsync {
// Artifacts that need to fsync on destruction
struct Res<t> {
pub struct Res<t: Copy> {
arg: Arg<t>,
drop {
match self.arg.opt_level {
@ -799,51 +813,51 @@ mod fsync {
}
}
fn Res<t>(-arg: Arg<t>) -> Res<t>{
pub fn Res<t: Copy>(arg: Arg<t>) -> Res<t>{
Res {
arg: move arg
}
}
type Arg<t> = {
pub type Arg<t> = {
val: t,
opt_level: Option<Level>,
fsync_fn: fn@(t, Level) -> int
fsync_fn: fn@(f: t, Level) -> int
};
// fsync file after executing blk
// FIXME (#2004) find better way to create resources within lifetime of
// outer res
fn FILE_res_sync(&&file: FILERes, opt_level: Option<Level>,
blk: fn(&&v: Res<*libc::FILE>)) {
blk(Res({
pub fn FILE_res_sync(file: &FILERes, opt_level: Option<Level>,
blk: fn(v: Res<*libc::FILE>)) {
blk(move Res({
val: file.f, opt_level: opt_level,
fsync_fn: fn@(&&file: *libc::FILE, l: Level) -> int {
fsync_fn: fn@(file: *libc::FILE, l: Level) -> int {
return os::fsync_fd(libc::fileno(file), l) as int;
}
}));
}
// fsync fd after executing blk
fn fd_res_sync(&&fd: FdRes, opt_level: Option<Level>,
blk: fn(&&v: Res<fd_t>)) {
blk(Res({
pub fn fd_res_sync(fd: &FdRes, opt_level: Option<Level>,
blk: fn(v: Res<fd_t>)) {
blk(move Res({
val: fd.fd, opt_level: opt_level,
fsync_fn: fn@(&&fd: fd_t, l: Level) -> int {
fsync_fn: fn@(fd: fd_t, l: Level) -> int {
return os::fsync_fd(fd, l) as int;
}
}));
}
// Type of objects that may want to fsync
trait FSyncable { fn fsync(l: Level) -> int; }
pub trait FSyncable { fn fsync(l: Level) -> int; }
// Call o.fsync after executing blk
fn obj_sync(&&o: FSyncable, opt_level: Option<Level>,
blk: fn(&&v: Res<FSyncable>)) {
pub fn obj_sync(o: FSyncable, opt_level: Option<Level>,
blk: fn(v: Res<FSyncable>)) {
blk(Res({
val: o, opt_level: opt_level,
fsync_fn: fn@(&&o: FSyncable, l: Level) -> int {
fsync_fn: fn@(o: FSyncable, l: Level) -> int {
return o.fsync(l);
}
}));
@ -852,7 +866,6 @@ mod fsync {
#[cfg(test)]
mod tests {
#[legacy_exports];
#[test]
fn test_simple() {
@ -864,10 +877,10 @@ mod tests {
{
let out: io::Writer =
result::get(
io::file_writer(tmpfile, ~[io::Create, io::Truncate]));
&io::file_writer(tmpfile, ~[io::Create, io::Truncate]));
out.write_str(frood);
}
let inp: io::Reader = result::get(io::file_reader(tmpfile));
let inp: io::Reader = result::get(&io::file_reader(tmpfile));
let frood2: ~str = inp.read_c_str();
log(debug, frood2);
assert frood == frood2;
@ -876,8 +889,8 @@ mod tests {
#[test]
fn test_readchars_empty() {
do io::with_str_reader(~"") |inp| {
let res : ~[char] = inp.read_chars(128u);
assert(vec::len(res) == 0u);
let res : ~[char] = inp.read_chars(128);
assert(vec::len(res) == 0);
}
}
@ -890,7 +903,7 @@ mod tests {
104, 101, 108, 108, 111,
29983, 38152, 30340, 27748,
21273, 20999, 32905, 27748];
fn check_read_ln(len : uint, s: ~str, ivals: ~[int]) {
fn check_read_ln(len : uint, s: &str, ivals: &[int]) {
do io::with_str_reader(s) |inp| {
let res : ~[char] = inp.read_chars(len);
if (len <= vec::len(ivals)) {
@ -900,13 +913,13 @@ mod tests {
vec::map(res, |x| *x as int));
}
}
let mut i = 0u;
while i < 8u {
let mut i = 0;
while i < 8 {
check_read_ln(i, wide_test, ivals);
i += 1u;
i += 1;
}
// check a long read for good measure
check_read_ln(128u, wide_test, ivals);
check_read_ln(128, wide_test, ivals);
}
#[test]
@ -928,7 +941,7 @@ mod tests {
#[test]
fn file_reader_not_exist() {
match io::file_reader(&Path("not a file")) {
result::Err(e) => {
result::Err(copy e) => {
assert e == ~"error opening not a file";
}
result::Ok(_) => fail
@ -938,7 +951,7 @@ mod tests {
#[test]
fn file_writer_bad_name() {
match io::file_writer(&Path("?/?"), ~[]) {
result::Err(e) => {
result::Err(copy e) => {
assert str::starts_with(e, "error opening");
}
result::Ok(_) => fail
@ -948,7 +961,7 @@ mod tests {
#[test]
fn buffered_file_writer_bad_name() {
match io::buffered_file_writer(&Path("?/?")) {
result::Err(e) => {
result::Err(copy e) => {
assert str::starts_with(e, "error opening");
}
result::Ok(_) => fail

View file

@ -2,51 +2,52 @@
// workaround our lack of traits and lack of macros. See core.{rc,rs} for
// how this file is used.
#[warn(deprecated_mode)];
use cmp::{Eq, Ord};
use inst::{IMPL_T, EACH, SIZE_HINT};
export extensions;
impl<A> IMPL_T<A>: iter::BaseIter<A> {
pure fn each(blk: fn(v: &A) -> bool) { EACH(self, blk) }
pure fn size_hint() -> Option<uint> { SIZE_HINT(self) }
pure fn each(blk: fn(v: &A) -> bool) { EACH(&self, blk) }
pure fn size_hint() -> Option<uint> { SIZE_HINT(&self) }
}
impl<A> IMPL_T<A>: iter::ExtendedIter<A> {
pure fn eachi(blk: fn(uint, v: &A) -> bool) { iter::eachi(self, blk) }
pure fn all(blk: fn(A) -> bool) -> bool { iter::all(self, blk) }
pure fn any(blk: fn(A) -> bool) -> bool { iter::any(self, blk) }
pure fn foldl<B>(+b0: B, blk: fn(B, A) -> B) -> B {
iter::foldl(self, move b0, blk)
pure fn eachi(blk: fn(uint, v: &A) -> bool) { iter::eachi(&self, blk) }
pure fn all(blk: fn(&A) -> bool) -> bool { iter::all(&self, blk) }
pure fn any(blk: fn(&A) -> bool) -> bool { iter::any(&self, blk) }
pure fn foldl<B>(b0: B, blk: fn(&B, &A) -> B) -> B {
iter::foldl(&self, move b0, blk)
}
pure fn position(f: fn(A) -> bool) -> Option<uint> {
iter::position(self, f)
pure fn position(f: fn(&A) -> bool) -> Option<uint> {
iter::position(&self, f)
}
}
impl<A: Eq> IMPL_T<A>: iter::EqIter<A> {
pure fn contains(x: A) -> bool { iter::contains(self, x) }
pure fn count(x: A) -> uint { iter::count(self, x) }
pure fn contains(x: &A) -> bool { iter::contains(&self, x) }
pure fn count(x: &A) -> uint { iter::count(&self, x) }
}
impl<A: Copy> IMPL_T<A>: iter::CopyableIter<A> {
pure fn filter_to_vec(pred: fn(A) -> bool) -> ~[A] {
iter::filter_to_vec(self, pred)
pure fn filter_to_vec(pred: fn(a: A) -> bool) -> ~[A] {
iter::filter_to_vec(&self, pred)
}
pure fn map_to_vec<B>(op: fn(v: &A) -> B) -> ~[B] {
iter::map_to_vec(self, op)
pure fn map_to_vec<B>(op: fn(v: A) -> B) -> ~[B] {
iter::map_to_vec(&self, op)
}
pure fn to_vec() -> ~[A] { iter::to_vec(self) }
pure fn to_vec() -> ~[A] { iter::to_vec(&self) }
// FIXME--bug in resolve prevents this from working (#2611)
// fn flat_map_to_vec<B:copy,IB:base_iter<B>>(op: fn(A) -> IB) -> ~[B] {
// iter::flat_map_to_vec(self, op)
// }
pure fn flat_map_to_vec<B:Copy,IB:BaseIter<B>>(op: fn(a: A) -> IB)
-> ~[B] {
iter::flat_map_to_vec(&self, op)
}
pure fn find(p: fn(A) -> bool) -> Option<A> { iter::find(self, p) }
pure fn find(p: fn(a: A) -> bool) -> Option<A> { iter::find(&self, p) }
}
impl<A: Copy Ord> IMPL_T<A>: iter::CopyableOrderedIter<A> {
pure fn min() -> A { iter::min(self) }
pure fn max() -> A { iter::max(self) }
pure fn min() -> A { iter::min(&self) }
pure fn max() -> A { iter::max(&self) }
}

View file

@ -1,5 +1,5 @@
#[allow(non_camel_case_types)]
type IMPL_T<A> = dlist::DList<A>;
pub type IMPL_T<A> = dlist::DList<A>;
/**
* Iterates through the current contents.
@ -8,7 +8,7 @@ type IMPL_T<A> = dlist::DList<A>;
* e.g. breadth-first search with in-place enqueues), but removing the current
* node is forbidden.
*/
pure fn EACH<A>(self: IMPL_T<A>, f: fn(v: &A) -> bool) {
pub pure fn EACH<A>(self: &IMPL_T<A>, f: fn(v: &A) -> bool) {
let mut link = self.peek_n();
while option::is_some(&link) {
let nobe = option::get(&link);
@ -29,6 +29,6 @@ pure fn EACH<A>(self: IMPL_T<A>, f: fn(v: &A) -> bool) {
}
}
pure fn SIZE_HINT<A>(self: IMPL_T<A>) -> Option<uint> {
pub pure fn SIZE_HINT<A>(self: &IMPL_T<A>) -> Option<uint> {
Some(self.len())
}

View file

@ -1,12 +1,12 @@
#[allow(non_camel_case_types)]
type IMPL_T<A> = dvec::DVec<A>;
pub type IMPL_T<A> = dvec::DVec<A>;
/**
* Iterates through the current contents.
*
* Attempts to access this dvec during iteration will fail.
*/
pure fn EACH<A>(self: IMPL_T<A>, f: fn(v: &A) -> bool) {
pub pure fn EACH<A>(self: &IMPL_T<A>, f: fn(v: &A) -> bool) {
unsafe {
do self.swap |v| {
v.each(f);
@ -15,6 +15,6 @@ pure fn EACH<A>(self: IMPL_T<A>, f: fn(v: &A) -> bool) {
}
}
pure fn SIZE_HINT<A>(self: IMPL_T<A>) -> Option<uint> {
pub pure fn SIZE_HINT<A>(self: &IMPL_T<A>) -> Option<uint> {
Some(self.len())
}

View file

@ -1,16 +1,16 @@
#[allow(non_camel_case_types)]
type IMPL_T<A> = Option<A>;
pub type IMPL_T<A> = Option<A>;
pure fn EACH<A>(self: IMPL_T<A>, f: fn(v: &A) -> bool) {
match self {
pub pure fn EACH<A>(self: &IMPL_T<A>, f: fn(v: &A) -> bool) {
match *self {
None => (),
Some(ref a) => { f(a); }
}
}
pure fn SIZE_HINT<A>(self: IMPL_T<A>) -> Option<uint> {
match self {
None => Some(0u),
Some(_) => Some(1u)
pub pure fn SIZE_HINT<A>(self: &IMPL_T<A>) -> Option<uint> {
match *self {
None => Some(0),
Some(_) => Some(1)
}
}

View file

@ -7,48 +7,49 @@ The iteration traits and common implementation
use cmp::{Eq, Ord};
/// A function used to initialize the elements of a sequence
type InitOp<T> = fn(uint) -> T;
pub type InitOp<T> = &fn(uint) -> T;
trait BaseIter<A> {
pub trait BaseIter<A> {
pure fn each(blk: fn(v: &A) -> bool);
pure fn size_hint() -> Option<uint>;
}
trait ExtendedIter<A> {
pub trait ExtendedIter<A> {
pure fn eachi(blk: fn(uint, v: &A) -> bool);
pure fn all(blk: fn(A) -> bool) -> bool;
pure fn any(blk: fn(A) -> bool) -> bool;
pure fn foldl<B>(+b0: B, blk: fn(B, A) -> B) -> B;
pure fn position(f: fn(A) -> bool) -> Option<uint>;
pure fn all(blk: fn(&A) -> bool) -> bool;
pure fn any(blk: fn(&A) -> bool) -> bool;
pure fn foldl<B>(b0: B, blk: fn(&B, &A) -> B) -> B;
pure fn position(f: fn(&A) -> bool) -> Option<uint>;
}
trait EqIter<A:Eq> {
pure fn contains(x: A) -> bool;
pure fn count(x: A) -> uint;
pub trait EqIter<A:Eq> {
pure fn contains(x: &A) -> bool;
pure fn count(x: &A) -> uint;
}
trait Times {
pub trait Times {
pure fn times(it: fn() -> bool);
}
trait TimesIx{
pub trait TimesIx{
pure fn timesi(it: fn(uint) -> bool);
}
trait CopyableIter<A:Copy> {
pure fn filter_to_vec(pred: fn(A) -> bool) -> ~[A];
pure fn map_to_vec<B>(op: fn(v: &A) -> B) -> ~[B];
pub trait CopyableIter<A:Copy> {
pure fn filter_to_vec(pred: fn(a: A) -> bool) -> ~[A];
pure fn map_to_vec<B>(op: fn(v: A) -> B) -> ~[B];
pure fn to_vec() -> ~[A];
pure fn find(p: fn(A) -> bool) -> Option<A>;
pure fn find(p: fn(a: A) -> bool) -> Option<A>;
}
trait CopyableOrderedIter<A:Copy Ord> {
pub trait CopyableOrderedIter<A:Copy Ord> {
pure fn min() -> A;
pure fn max() -> A;
}
// A trait for sequences that can be by imperatively pushing elements
// onto them.
trait Buildable<A> {
pub trait Buildable<A> {
/**
* Builds a buildable sequence by calling a provided function with
* an argument function that pushes an element onto the back of
@ -63,33 +64,36 @@ trait Buildable<A> {
* onto the sequence being constructed.
*/
static pure fn build_sized(size: uint,
builder: fn(push: pure fn(+v: A))) -> self;
builder: fn(push: pure fn(v: A))) -> self;
}
pure fn eachi<A,IA:BaseIter<A>>(self: IA, blk: fn(uint, v: &A) -> bool) {
let mut i = 0u;
pub pure fn eachi<A,IA:BaseIter<A>>(self: &IA,
blk: fn(uint, v: &A) -> bool) {
let mut i = 0;
for self.each |a| {
if !blk(i, a) { break; }
i += 1u;
i += 1;
}
}
pure fn all<A,IA:BaseIter<A>>(self: IA, blk: fn(A) -> bool) -> bool {
pub pure fn all<A,IA:BaseIter<A>>(self: &IA,
blk: fn(&A) -> bool) -> bool {
for self.each |a| {
if !blk(*a) { return false; }
if !blk(a) { return false; }
}
return true;
}
pure fn any<A,IA:BaseIter<A>>(self: IA, blk: fn(A) -> bool) -> bool {
pub pure fn any<A,IA:BaseIter<A>>(self: &IA,
blk: fn(&A) -> bool) -> bool {
for self.each |a| {
if blk(*a) { return true; }
if blk(a) { return true; }
}
return false;
}
pure fn filter_to_vec<A:Copy,IA:BaseIter<A>>(self: IA,
prd: fn(A) -> bool) -> ~[A] {
pub pure fn filter_to_vec<A:Copy,IA:BaseIter<A>>(
self: &IA, prd: fn(a: A) -> bool) -> ~[A] {
do vec::build_sized_opt(self.size_hint()) |push| {
for self.each |a| {
if prd(*a) { push(*a); }
@ -97,18 +101,18 @@ pure fn filter_to_vec<A:Copy,IA:BaseIter<A>>(self: IA,
}
}
pure fn map_to_vec<A:Copy,B,IA:BaseIter<A>>(self: IA, op: fn(v: &A) -> B)
pub pure fn map_to_vec<A:Copy,B,IA:BaseIter<A>>(self: &IA,
op: fn(v: A) -> B)
-> ~[B] {
do vec::build_sized_opt(self.size_hint()) |push| {
for self.each |a| {
push(op(a));
push(op(*a));
}
}
}
pure fn flat_map_to_vec<A:Copy,B:Copy,IA:BaseIter<A>,IB:BaseIter<B>>(
self: IA, op: fn(A) -> IB) -> ~[B] {
pub pure fn flat_map_to_vec<A:Copy,B:Copy,IA:BaseIter<A>,IB:BaseIter<B>>(
self: &IA, op: fn(a: A) -> IB) -> ~[B] {
do vec::build |push| {
for self.each |a| {
for op(*a).each |b| {
@ -118,41 +122,43 @@ pure fn flat_map_to_vec<A:Copy,B:Copy,IA:BaseIter<A>,IB:BaseIter<B>>(
}
}
pure fn foldl<A,B,IA:BaseIter<A>>(self: IA, +b0: B, blk: fn(B, A) -> B) -> B {
pub pure fn foldl<A,B,IA:BaseIter<A>>(self: &IA, b0: B,
blk: fn(&B, &A) -> B)
-> B {
let mut b <- b0;
for self.each |a| {
b = blk(b, *a);
b = blk(&b, a);
}
move b
}
pure fn to_vec<A:Copy,IA:BaseIter<A>>(self: IA) -> ~[A] {
foldl::<A,~[A],IA>(self, ~[], |r, a| vec::append(copy r, ~[a]))
pub pure fn to_vec<A:Copy,IA:BaseIter<A>>(self: &IA) -> ~[A] {
foldl::<A,~[A],IA>(self, ~[], |r, a| vec::append(copy (*r), ~[*a]))
}
pure fn contains<A:Eq,IA:BaseIter<A>>(self: IA, x: A) -> bool {
pub pure fn contains<A:Eq,IA:BaseIter<A>>(self: &IA, x: &A) -> bool {
for self.each |a| {
if *a == x { return true; }
if *a == *x { return true; }
}
return false;
}
pure fn count<A:Eq,IA:BaseIter<A>>(self: IA, x: A) -> uint {
do foldl(self, 0u) |count, value| {
if value == x {
count + 1u
pub pure fn count<A:Eq,IA:BaseIter<A>>(self: &IA, x: &A) -> uint {
do foldl(self, 0) |count, value| {
if *value == *x {
*count + 1
} else {
count
*count
}
}
}
pure fn position<A,IA:BaseIter<A>>(self: IA, f: fn(A) -> bool)
pub pure fn position<A,IA:BaseIter<A>>(self: &IA, f: fn(&A) -> bool)
-> Option<uint>
{
let mut i = 0;
for self.each |a| {
if f(*a) { return Some(i); }
if f(a) { return Some(i); }
i += 1;
}
return None;
@ -162,48 +168,44 @@ pure fn position<A,IA:BaseIter<A>>(self: IA, f: fn(A) -> bool)
// iter interface, such as would provide "reach" in addition to "each". as is,
// it would have to be implemented with foldr, which is too inefficient.
pure fn repeat(times: uint, blk: fn() -> bool) {
let mut i = 0u;
pub pure fn repeat(times: uint, blk: fn() -> bool) {
let mut i = 0;
while i < times {
if !blk() { break }
i += 1u;
i += 1;
}
}
pure fn min<A:Copy Ord,IA:BaseIter<A>>(self: IA) -> A {
pub pure fn min<A:Copy Ord,IA:BaseIter<A>>(self: &IA) -> A {
match do foldl::<A,Option<A>,IA>(self, None) |a, b| {
match a {
Some(a_) if a_ < b => {
// FIXME (#2005): Not sure if this is successfully optimized to
// a move
a
&Some(ref a_) if *a_ < *b => {
*(move a)
}
_ => Some(b)
_ => Some(*b)
}
} {
Some(val) => val,
Some(move val) => val,
None => fail ~"min called on empty iterator"
}
}
pure fn max<A:Copy Ord,IA:BaseIter<A>>(self: IA) -> A {
pub pure fn max<A:Copy Ord,IA:BaseIter<A>>(self: &IA) -> A {
match do foldl::<A,Option<A>,IA>(self, None) |a, b| {
match a {
Some(a_) if a_ > b => {
// FIXME (#2005): Not sure if this is successfully optimized to
// a move.
a
&Some(ref a_) if *a_ > *b => {
*(move a)
}
_ => Some(b)
_ => Some(*b)
}
} {
Some(val) => val,
Some(move val) => val,
None => fail ~"max called on empty iterator"
}
}
pure fn find<A: Copy,IA:BaseIter<A>>(self: IA,
p: fn(A) -> bool) -> Option<A> {
pub pure fn find<A: Copy,IA:BaseIter<A>>(self: &IA,
p: fn(a: A) -> bool) -> Option<A> {
for self.each |i| {
if p(*i) { return Some(*i) }
}
@ -223,7 +225,8 @@ pure fn find<A: Copy,IA:BaseIter<A>>(self: IA,
* onto the sequence being constructed.
*/
#[inline(always)]
pure fn build<A,B: Buildable<A>>(builder: fn(push: pure fn(+v: A))) -> B {
pub pure fn build<A,B: Buildable<A>>(builder: fn(push: pure fn(v: A)))
-> B {
build_sized(4, builder)
}
@ -241,9 +244,9 @@ pure fn build<A,B: Buildable<A>>(builder: fn(push: pure fn(+v: A))) -> B {
* onto the sequence being constructed.
*/
#[inline(always)]
pure fn build_sized_opt<A,B: Buildable<A>>(
pub pure fn build_sized_opt<A,B: Buildable<A>>(
size: Option<uint>,
builder: fn(push: pure fn(+v: A))) -> B {
builder: fn(push: pure fn(v: A))) -> B {
build_sized(size.get_default(4), builder)
}
@ -251,10 +254,11 @@ pure fn build_sized_opt<A,B: Buildable<A>>(
// Functions that combine iteration and building
/// Apply a function to each element of an iterable and return the results
fn map<T,IT: BaseIter<T>,U,BU: Buildable<U>>(v: IT, f: fn(T) -> U) -> BU {
pub fn map<T,IT: BaseIter<T>,U,BU: Buildable<U>>(v: &IT, f: fn(&T) -> U)
-> BU {
do build_sized_opt(v.size_hint()) |push| {
for v.each() |elem| {
push(f(*elem));
push(f(elem));
}
}
}
@ -265,7 +269,8 @@ fn map<T,IT: BaseIter<T>,U,BU: Buildable<U>>(v: IT, f: fn(T) -> U) -> BU {
* Creates a generic sequence of size `n_elts` and initializes the elements
* to the value returned by the function `op`.
*/
pure fn from_fn<T,BT: Buildable<T>>(n_elts: uint, op: InitOp<T>) -> BT {
pub pure fn from_fn<T,BT: Buildable<T>>(n_elts: uint,
op: InitOp<T>) -> BT {
do build_sized(n_elts) |push| {
let mut i: uint = 0u;
while i < n_elts { push(op(i)); i += 1u; }
@ -278,19 +283,20 @@ pure fn from_fn<T,BT: Buildable<T>>(n_elts: uint, op: InitOp<T>) -> BT {
* Creates an immutable vector of size `n_elts` and initializes the elements
* to the value `t`.
*/
pure fn from_elem<T: Copy,BT: Buildable<T>>(n_elts: uint, t: T) -> BT {
pub pure fn from_elem<T: Copy,BT: Buildable<T>>(n_elts: uint,
t: T) -> BT {
do build_sized(n_elts) |push| {
let mut i: uint = 0u;
while i < n_elts { push(t); i += 1u; }
let mut i: uint = 0;
while i < n_elts { push(t); i += 1; }
}
}
/// Appending two generic sequences
#[inline(always)]
pure fn append<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
lhs: IT, rhs: IT) -> BT {
let size_opt = lhs.size_hint().chain(
|sz1| rhs.size_hint().map(|sz2| sz1+sz2));
pub pure fn append<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
lhs: &IT, rhs: &IT) -> BT {
let size_opt = lhs.size_hint().chain_ref(
|sz1| rhs.size_hint().map(|sz2| *sz1+*sz2));
do build_sized_opt(size_opt) |push| {
for lhs.each |x| { push(*x); }
for rhs.each |x| { push(*x); }
@ -300,8 +306,8 @@ pure fn append<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
/// Copies a generic sequence, possibly converting it to a different
/// type of sequence.
#[inline(always)]
pure fn copy_seq<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
v: IT) -> BT {
pub pure fn copy_seq<T: Copy,IT: BaseIter<T>,BT: Buildable<T>>(
v: &IT) -> BT {
do build_sized_opt(v.size_hint()) |push| {
for v.each |x| { push(*x); }
}

File diff suppressed because it is too large Load diff

View file

@ -6,18 +6,15 @@
use cast::transmute;
export console_on, console_off, log_type;
#[nolink]
extern mod rustrt {
#[legacy_exports];
fn rust_log_console_on();
fn rust_log_console_off();
fn rust_log_str(level: u32, string: *libc::c_char, size: libc::size_t);
}
/// Turns on logging to stdout globally
fn console_on() {
pub fn console_on() {
rustrt::rust_log_console_on();
}
@ -28,7 +25,7 @@ fn console_on() {
* runtime environment's logging spec, e.g. by setting
* the RUST_LOG environment variable
*/
fn console_off() {
pub fn console_off() {
rustrt::rust_log_console_off();
}

View file

@ -8,15 +8,12 @@ dynamic checks: your program will fail if you attempt to perform
mutation when the data structure should be immutable.
*/
#[forbid(deprecated_mode)];
// tjc: re-forbid deprecated modes after snapshot
#[forbid(deprecated_pattern)];
use util::with;
use cast::transmute_immut;
export Mut;
enum Mode { ReadOnly, Mutable, Immutable }
struct Data<T> {
@ -24,18 +21,18 @@ struct Data<T> {
priv mut mode: Mode
}
type Mut<T> = Data<T>;
pub type Mut<T> = Data<T>;
fn Mut<T>(+t: T) -> Mut<T> {
pub fn Mut<T>(t: T) -> Mut<T> {
Data {value: t, mode: ReadOnly}
}
fn unwrap<T>(+m: Mut<T>) -> T {
pub fn unwrap<T>(m: Mut<T>) -> T {
// Borrowck should prevent us from calling unwrap while the value
// is in use, as that would be a move from a borrowed value.
assert (m.mode as uint) == (ReadOnly as uint);
let Data {value, mode: _} <- m;
return move value;
let Data {value: move value, mode: _} = move m;
return value;
}
impl<T> Data<T> {
@ -71,7 +68,7 @@ impl<T> Data<T> {
#[test]
#[ignore(cfg(windows))]
#[should_fail]
fn test_mut_in_imm() {
pub fn test_mut_in_imm() {
let m = @Mut(1);
do m.borrow_imm |_p| {
do m.borrow_mut |_q| {
@ -83,7 +80,7 @@ fn test_mut_in_imm() {
#[test]
#[ignore(cfg(windows))]
#[should_fail]
fn test_imm_in_mut() {
pub fn test_imm_in_mut() {
let m = @Mut(1);
do m.borrow_mut |_p| {
do m.borrow_imm |_q| {
@ -93,7 +90,7 @@ fn test_imm_in_mut() {
}
#[test]
fn test_const_in_mut() {
pub fn test_const_in_mut() {
let m = @Mut(1);
do m.borrow_mut |p| {
do m.borrow_const |q| {
@ -105,7 +102,7 @@ fn test_const_in_mut() {
}
#[test]
fn test_mut_in_const() {
pub fn test_mut_in_const() {
let m = @Mut(1);
do m.borrow_const |p| {
do m.borrow_mut |q| {
@ -117,7 +114,7 @@ fn test_mut_in_const() {
}
#[test]
fn test_imm_in_const() {
pub fn test_imm_in_const() {
let m = @Mut(1);
do m.borrow_const |p| {
do m.borrow_imm |q| {
@ -127,7 +124,7 @@ fn test_imm_in_const() {
}
#[test]
fn test_const_in_imm() {
pub fn test_const_in_imm() {
let m = @Mut(1);
do m.borrow_imm |p| {
do m.borrow_const |q| {
@ -140,7 +137,7 @@ fn test_const_in_imm() {
#[test]
#[ignore(cfg(windows))]
#[should_fail]
fn test_mut_in_imm_in_const() {
pub fn test_mut_in_imm_in_const() {
let m = @Mut(1);
do m.borrow_const |_p| {
do m.borrow_imm |_q| {
@ -149,3 +146,4 @@ fn test_mut_in_imm_in_const() {
}
}
}

View file

@ -1,12 +1,12 @@
//! An interface for numeric types
trait Num {
pub trait Num {
// FIXME: Trait composition. (#2616)
pure fn add(&&other: self) -> self;
pure fn sub(&&other: self) -> self;
pure fn mul(&&other: self) -> self;
pure fn div(&&other: self) -> self;
pure fn modulo(&&other: self) -> self;
pure fn add(other: &self) -> self;
pure fn sub(other: &self) -> self;
pure fn mul(other: &self) -> self;
pure fn div(other: &self) -> self;
pure fn modulo(other: &self) -> self;
pure fn neg() -> self;
pure fn to_int() -> int;

View file

@ -1,82 +1,82 @@
// Core operators and kinds.
#[lang="const"]
trait Const {
pub trait Const {
// Empty.
}
#[lang="copy"]
trait Copy {
pub trait Copy {
// Empty.
}
#[lang="send"]
trait Send {
pub trait Send {
// Empty.
}
#[lang="owned"]
trait Owned {
pub trait Owned {
// Empty.
}
#[lang="add"]
trait Add<RHS,Result> {
pub trait Add<RHS,Result> {
pure fn add(rhs: &RHS) -> Result;
}
#[lang="sub"]
trait Sub<RHS,Result> {
pub trait Sub<RHS,Result> {
pure fn sub(rhs: &RHS) -> Result;
}
#[lang="mul"]
trait Mul<RHS,Result> {
pub trait Mul<RHS,Result> {
pure fn mul(rhs: &RHS) -> Result;
}
#[lang="div"]
trait Div<RHS,Result> {
pub trait Div<RHS,Result> {
pure fn div(rhs: &RHS) -> Result;
}
#[lang="modulo"]
trait Modulo<RHS,Result> {
pub trait Modulo<RHS,Result> {
pure fn modulo(rhs: &RHS) -> Result;
}
#[lang="neg"]
trait Neg<Result> {
pub trait Neg<Result> {
pure fn neg() -> Result;
}
#[lang="bitand"]
trait BitAnd<RHS,Result> {
pub trait BitAnd<RHS,Result> {
pure fn bitand(rhs: &RHS) -> Result;
}
#[lang="bitor"]
trait BitOr<RHS,Result> {
pub trait BitOr<RHS,Result> {
pure fn bitor(rhs: &RHS) -> Result;
}
#[lang="bitxor"]
trait BitXor<RHS,Result> {
pub trait BitXor<RHS,Result> {
pure fn bitxor(rhs: &RHS) -> Result;
}
#[lang="shl"]
trait Shl<RHS,Result> {
pub trait Shl<RHS,Result> {
pure fn shl(rhs: &RHS) -> Result;
}
#[lang="shr"]
trait Shr<RHS,Result> {
pub trait Shr<RHS,Result> {
pure fn shr(rhs: &RHS) -> Result;
}
#[lang="index"]
trait Index<Index,Result> {
pub trait Index<Index,Result> {
pure fn index(index: Index) -> Result;
}

View file

@ -9,18 +9,18 @@
*/
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
#[warn(deprecated_mode)];
#[forbid(deprecated_pattern)];
use cmp::Eq;
/// The option type
enum Option<T> {
pub enum Option<T> {
None,
Some(T),
}
pure fn get<T: Copy>(opt: &Option<T>) -> T {
pub pure fn get<T: Copy>(opt: &Option<T>) -> T {
/*!
* Gets the value out of an option
*
@ -30,12 +30,12 @@ pure fn get<T: Copy>(opt: &Option<T>) -> T {
*/
match *opt {
Some(x) => return x,
Some(copy x) => return x,
None => fail ~"option::get none"
}
}
pure fn get_ref<T>(opt: &r/Option<T>) -> &r/T {
pub pure fn get_ref<T>(opt: &r/Option<T>) -> &r/T {
/*!
* Gets an immutable reference to the value inside an option.
*
@ -49,7 +49,7 @@ pure fn get_ref<T>(opt: &r/Option<T>) -> &r/T {
}
}
pure fn expect<T: Copy>(opt: &Option<T>, +reason: ~str) -> T {
pub pure fn expect<T: Copy>(opt: &Option<T>, reason: ~str) -> T {
/*!
* Gets the value out of an option, printing a specified message on
* failure
@ -58,22 +58,17 @@ pure fn expect<T: Copy>(opt: &Option<T>, +reason: ~str) -> T {
*
* Fails if the value equals `none`
*/
match *opt { Some(x) => x, None => fail reason }
match *opt { Some(copy x) => x, None => fail reason }
}
pure fn map<T, U>(opt: &Option<T>, f: fn(T) -> U) -> Option<U> {
//! Maps a `some` value from one type to another
match *opt { Some(x) => Some(f(x)), None => None }
}
pure fn map_ref<T, U>(opt: &Option<T>, f: fn(x: &T) -> U) -> Option<U> {
pub pure fn map<T, U>(opt: &Option<T>, f: fn(x: &T) -> U) -> Option<U> {
//! Maps a `some` value by reference from one type to another
match *opt { Some(ref x) => Some(f(x)), None => None }
}
pure fn map_consume<T, U>(+opt: Option<T>, f: fn(+v: T) -> U) -> Option<U> {
pub pure fn map_consume<T, U>(opt: Option<T>,
f: fn(v: T) -> U) -> Option<U> {
/*!
* As `map`, but consumes the option and gives `f` ownership to avoid
* copying.
@ -81,17 +76,23 @@ pure fn map_consume<T, U>(+opt: Option<T>, f: fn(+v: T) -> U) -> Option<U> {
if opt.is_some() { Some(f(option::unwrap(move opt))) } else { None }
}
pure fn chain<T, U>(opt: &Option<T>, f: fn(T) -> Option<U>) -> Option<U> {
pub pure fn chain<T, U>(opt: Option<T>,
f: fn(t: T) -> Option<U>) -> Option<U> {
/*!
* Update an optional value by optionally running its content through a
* function that returns an option.
*/
match *opt { Some(x) => f(x), None => None }
// XXX write with move match
if opt.is_some() {
f(unwrap(opt))
} else {
None
}
}
pure fn chain_ref<T, U>(opt: &Option<T>,
f: fn(x: &T) -> Option<U>) -> Option<U> {
pub pure fn chain_ref<T, U>(opt: &Option<T>,
f: fn(x: &T) -> Option<U>) -> Option<U> {
/*!
* Update an optional value by optionally running its content by reference
* through a function that returns an option.
@ -100,7 +101,7 @@ pure fn chain_ref<T, U>(opt: &Option<T>,
match *opt { Some(ref x) => f(x), None => None }
}
pure fn or<T>(+opta: Option<T>, +optb: Option<T>) -> Option<T> {
pub pure fn or<T>(opta: Option<T>, optb: Option<T>) -> Option<T> {
/*!
* Returns the leftmost some() value, or none if both are none.
*/
@ -111,7 +112,7 @@ pure fn or<T>(+opta: Option<T>, +optb: Option<T>) -> Option<T> {
}
#[inline(always)]
pure fn while_some<T>(+x: Option<T>, blk: fn(+v: T) -> Option<T>) {
pub pure fn while_some<T>(x: Option<T>, blk: fn(v: T) -> Option<T>) {
//! Applies a function zero or more times until the result is none.
let mut opt <- x;
@ -120,54 +121,38 @@ pure fn while_some<T>(+x: Option<T>, blk: fn(+v: T) -> Option<T>) {
}
}
pure fn is_none<T>(opt: &Option<T>) -> bool {
pub pure fn is_none<T>(opt: &Option<T>) -> bool {
//! Returns true if the option equals `none`
match *opt { None => true, Some(_) => false }
}
pure fn is_some<T>(opt: &Option<T>) -> bool {
pub pure fn is_some<T>(opt: &Option<T>) -> bool {
//! Returns true if the option contains some value
!is_none(opt)
}
pure fn get_default<T: Copy>(opt: &Option<T>, +def: T) -> T {
pub pure fn get_default<T: Copy>(opt: &Option<T>, def: T) -> T {
//! Returns the contained value or a default
match *opt { Some(x) => x, None => def }
match *opt { Some(copy x) => x, None => def }
}
pure fn map_default<T, U>(opt: &Option<T>, +def: U, f: fn(T) -> U) -> U {
//! Applies a function to the contained value or returns a default
match *opt { None => move def, Some(t) => f(t) }
}
// This should replace map_default.
pure fn map_default_ref<T, U>(opt: &Option<T>, +def: U,
pub pure fn map_default<T, U>(opt: &Option<T>, def: U,
f: fn(x: &T) -> U) -> U {
//! Applies a function to the contained value or returns a default
match *opt { None => move def, Some(ref t) => f(t) }
}
// This should change to by-copy mode; use iter_ref below for by reference
pure fn iter<T>(opt: &Option<T>, f: fn(T)) {
//! Performs an operation on the contained value or does nothing
match *opt { None => (), Some(t) => f(t) }
}
pure fn iter_ref<T>(opt: &Option<T>, f: fn(x: &T)) {
pub pure fn iter<T>(opt: &Option<T>, f: fn(x: &T)) {
//! Performs an operation on the contained value by reference
match *opt { None => (), Some(ref t) => f(t) }
}
// tjc: shouldn't this be - instead of +?
// then could get rid of some superfluous moves
#[inline(always)]
pure fn unwrap<T>(+opt: Option<T>) -> T {
pub pure fn unwrap<T>(opt: Option<T>) -> T {
/*!
* Moves a value out of an option type and returns it.
*
@ -182,12 +167,12 @@ pure fn unwrap<T>(+opt: Option<T>) -> T {
/// The ubiquitous option dance.
#[inline(always)]
fn swap_unwrap<T>(opt: &mut Option<T>) -> T {
pub fn swap_unwrap<T>(opt: &mut Option<T>) -> T {
if opt.is_none() { fail ~"option::swap_unwrap none" }
unwrap(util::replace(opt, None))
}
pure fn unwrap_expect<T>(+opt: Option<T>, reason: &str) -> T {
pub pure fn unwrap_expect<T>(opt: Option<T>, reason: &str) -> T {
//! As unwrap, but with a specified failure message.
if opt.is_none() { fail reason.to_unique(); }
unwrap(move opt)
@ -195,22 +180,10 @@ pure fn unwrap_expect<T>(+opt: Option<T>, reason: &str) -> T {
// Some of these should change to be &Option<T>, some should not. See below.
impl<T> Option<T> {
/**
* Update an optional value by optionally running its content through a
* function that returns an option.
*/
pure fn chain<U>(f: fn(T) -> Option<U>) -> Option<U> { chain(&self, f) }
/// Applies a function to the contained value or returns a default
pure fn map_default<U>(+def: U, f: fn(T) -> U) -> U
{ map_default(&self, move def, f) }
/// Performs an operation on the contained value or does nothing
pure fn iter(f: fn(T)) { iter(&self, f) }
/// Returns true if the option equals `none`
pure fn is_none() -> bool { is_none(&self) }
/// Returns true if the option contains some value
pure fn is_some() -> bool { is_some(&self) }
/// Maps a `some` value from one type to another
pure fn map<U>(f: fn(T) -> U) -> Option<U> { map(&self, f) }
}
impl<T> &Option<T> {
@ -222,12 +195,12 @@ impl<T> &Option<T> {
chain_ref(self, f)
}
/// Applies a function to the contained value or returns a default
pure fn map_default_ref<U>(+def: U, f: fn(x: &T) -> U) -> U
{ map_default_ref(self, move def, f) }
pure fn map_default<U>(def: U, f: fn(x: &T) -> U) -> U
{ map_default(self, move def, f) }
/// Performs an operation on the contained value by reference
pure fn iter_ref(f: fn(x: &T)) { iter_ref(self, f) }
pure fn iter(f: fn(x: &T)) { iter(self, f) }
/// Maps a `some` value from one type to another by reference
pure fn map_ref<U>(f: fn(x: &T) -> U) -> Option<U> { map_ref(self, f) }
pure fn map<U>(f: fn(x: &T) -> U) -> Option<U> { map(self, f) }
/// Gets an immutable reference to the value inside a `some`.
pure fn get_ref() -> &self/T { get_ref(self) }
}
@ -241,7 +214,7 @@ impl<T: Copy> Option<T> {
* Fails if the value equals `none`
*/
pure fn get() -> T { get(&self) }
pure fn get_default(+def: T) -> T { get_default(&self, def) }
pure fn get_default(def: T) -> T { get_default(&self, def) }
/**
* Gets the value out of an option, printing a specified message on
* failure
@ -250,9 +223,9 @@ impl<T: Copy> Option<T> {
*
* Fails if the value equals `none`
*/
pure fn expect(+reason: ~str) -> T { expect(&self, reason) }
pure fn expect(reason: ~str) -> T { expect(&self, reason) }
/// Applies a function zero or more times until the result is none.
pure fn while_some(blk: fn(+v: T) -> Option<T>) { while_some(self, blk) }
pure fn while_some(blk: fn(v: T) -> Option<T>) { while_some(self, blk) }
}
impl<T: Eq> Option<T> : Eq {
@ -264,11 +237,11 @@ impl<T: Eq> Option<T> : Eq {
Some(_) => false
}
}
Some(self_contents) => {
Some(ref self_contents) => {
match (*other) {
None => false,
Some(ref other_contents) =>
self_contents.eq(other_contents)
(*self_contents).eq(other_contents)
}
}
}
@ -279,20 +252,20 @@ impl<T: Eq> Option<T> : Eq {
#[test]
fn test_unwrap_ptr() {
let x = ~0;
let addr_x = ptr::addr_of(*x);
let addr_x = ptr::p2::addr_of(&(*x));
let opt = Some(x);
let y = unwrap(opt);
let addr_y = ptr::addr_of(*y);
let addr_y = ptr::p2::addr_of(&(*y));
assert addr_x == addr_y;
}
#[test]
fn test_unwrap_str() {
let x = ~"test";
let addr_x = str::as_buf(x, |buf, _len| ptr::addr_of(buf));
let opt = Some(x);
let y = unwrap(opt);
let addr_y = str::as_buf(y, |buf, _len| ptr::addr_of(buf));
let addr_x = str::as_buf(x, |buf, _len| buf);
let opt = Some(move x);
let y = unwrap(move opt);
let addr_y = str::as_buf(y, |buf, _len| buf);
assert addr_x == addr_y;
}

View file

@ -1,5 +1,5 @@
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
// tjc: re-forbid
#[forbid(deprecated_pattern)];
/*!
@ -21,34 +21,23 @@
*/
use libc::{c_char, c_void, c_int, c_uint, size_t, ssize_t,
mode_t, pid_t, FILE};
use libc::{close, fclose};
mode_t, pid_t, FILE};
pub use libc::{close, fclose};
use option::{Some, None};
use consts::*;
pub use consts::*;
use task::TaskBuilder;
export close, fclose, fsync_fd, waitpid;
export env, getenv, setenv, fdopen, pipe;
export getcwd, dll_filename, self_exe_path;
export exe_suffix, dll_suffix, sysname, arch, family;
export homedir, tmpdir, list_dir, list_dir_path, path_is_dir, path_exists,
make_absolute, make_dir, remove_dir, change_dir, remove_file,
copy_file;
export last_os_error;
export set_exit_status;
export walk_dir;
// FIXME: move these to str perhaps? #2620
export as_c_charp, fill_charp_buf;
extern mod rustrt {
#[legacy_exports];
fn rust_get_argc() -> c_int;
fn rust_get_argv() -> **c_char;
fn rust_getcwd() -> ~str;
fn rust_path_is_dir(path: *libc::c_char) -> c_int;
fn rust_path_exists(path: *libc::c_char) -> c_int;
fn rust_list_files(path: ~str) -> ~[~str];
fn rust_list_files2(&&path: ~str) -> ~[~str];
fn rust_process_wait(handle: c_int) -> c_int;
fn last_os_error() -> ~str;
fn rust_set_exit_status(code: libc::intptr_t);
@ -57,15 +46,15 @@ extern mod rustrt {
const tmpbuf_sz : uint = 1000u;
fn getcwd() -> Path {
pub fn getcwd() -> Path {
Path(rustrt::rust_getcwd())
}
fn as_c_charp<T>(s: &str, f: fn(*c_char) -> T) -> T {
pub fn as_c_charp<T>(s: &str, f: fn(*c_char) -> T) -> T {
str::as_c_str(s, |b| f(b as *c_char))
}
fn fill_charp_buf(f: fn(*mut c_char, size_t) -> bool)
pub fn fill_charp_buf(f: fn(*mut c_char, size_t) -> bool)
-> Option<~str> {
let buf = vec::to_mut(vec::from_elem(tmpbuf_sz, 0u8 as c_char));
do vec::as_mut_buf(buf) |b, sz| {
@ -79,29 +68,23 @@ fn fill_charp_buf(f: fn(*mut c_char, size_t) -> bool)
#[cfg(windows)]
mod win32 {
#[legacy_exports];
use dword = libc::types::os::arch::extra::DWORD;
use libc::DWORD;
fn fill_utf16_buf_and_decode(f: fn(*mut u16, dword) -> dword)
pub fn fill_utf16_buf_and_decode(f: fn(*mut u16, DWORD) -> DWORD)
-> Option<~str> {
// FIXME: remove these when export globs work properly. #1238
use libc::funcs::extra::kernel32::*;
use libc::consts::os::extra::*;
let mut n = tmpbuf_sz as dword;
let mut n = tmpbuf_sz as DWORD;
let mut res = None;
let mut done = false;
while !done {
let buf = vec::to_mut(vec::from_elem(n as uint, 0u16));
do vec::as_mut_buf(buf) |b, _sz| {
let k : dword = f(b, tmpbuf_sz as dword);
if k == (0 as dword) {
let k : DWORD = f(b, tmpbuf_sz as DWORD);
if k == (0 as DWORD) {
done = true;
} else if (k == n &&
GetLastError() ==
ERROR_INSUFFICIENT_BUFFER as dword) {
n *= (2 as dword);
libc::GetLastError() ==
libc::ERROR_INSUFFICIENT_BUFFER as DWORD) {
n *= (2 as DWORD);
} else {
let sub = vec::slice(buf, 0u, k as uint);
res = option::Some(str::from_utf16(sub));
@ -112,7 +95,7 @@ mod win32 {
return res;
}
fn as_utf16_p<T>(s: &str, f: fn(*u16) -> T) -> T {
pub fn as_utf16_p<T>(s: &str, f: fn(*u16) -> T) -> T {
let mut t = str::to_utf16(s);
// Null terminate before passing on.
t += ~[0u16];
@ -120,28 +103,22 @@ mod win32 {
}
}
fn getenv(n: &str) -> Option<~str> {
pub fn getenv(n: &str) -> Option<~str> {
global_env::getenv(n)
}
fn setenv(n: &str, v: &str) {
pub fn setenv(n: &str, v: &str) {
global_env::setenv(n, v)
}
fn env() -> ~[(~str,~str)] {
pub fn env() -> ~[(~str,~str)] {
global_env::env()
}
mod global_env {
#[legacy_exports];
//! Internal module for serializing access to getenv/setenv
export getenv;
export setenv;
export env;
extern mod rustrt {
#[legacy_exports];
fn rust_global_env_chan_ptr() -> *libc::uintptr_t;
}
@ -151,7 +128,7 @@ mod global_env {
MsgEnv(comm::Chan<~[(~str,~str)]>)
}
fn getenv(n: &str) -> Option<~str> {
pub fn getenv(n: &str) -> Option<~str> {
let env_ch = get_global_env_chan();
let po = comm::Port();
comm::send(env_ch, MsgGetEnv(str::from_slice(n),
@ -159,7 +136,7 @@ mod global_env {
comm::recv(po)
}
fn setenv(n: &str, v: &str) {
pub fn setenv(n: &str, v: &str) {
let env_ch = get_global_env_chan();
let po = comm::Port();
comm::send(env_ch, MsgSetEnv(str::from_slice(n),
@ -168,7 +145,7 @@ mod global_env {
comm::recv(po)
}
fn env() -> ~[(~str,~str)] {
pub fn env() -> ~[(~str,~str)] {
let env_ch = get_global_env_chan();
let po = comm::Port();
comm::send(env_ch, MsgEnv(comm::Chan(po)));
@ -191,11 +168,11 @@ mod global_env {
do private::weaken_task |weak_po| {
loop {
match comm::select2(msg_po, weak_po) {
either::Left(MsgGetEnv(n, resp_ch)) => {
comm::send(resp_ch, impl_::getenv(n))
either::Left(MsgGetEnv(ref n, resp_ch)) => {
comm::send(resp_ch, impl_::getenv(*n))
}
either::Left(MsgSetEnv(n, v, resp_ch)) => {
comm::send(resp_ch, impl_::setenv(n, v))
either::Left(MsgSetEnv(ref n, ref v, resp_ch)) => {
comm::send(resp_ch, impl_::setenv(*n, *v))
}
either::Left(MsgEnv(resp_ch)) => {
comm::send(resp_ch, impl_::env())
@ -208,24 +185,22 @@ mod global_env {
}
mod impl_ {
#[legacy_exports];
extern mod rustrt {
#[legacy_exports];
fn rust_env_pairs() -> ~[~str];
}
fn env() -> ~[(~str,~str)] {
pub fn env() -> ~[(~str,~str)] {
let mut pairs = ~[];
for vec::each(rustrt::rust_env_pairs()) |p| {
let vs = str::splitn_char(*p, '=', 1u);
assert vec::len(vs) == 2u;
vec::push(pairs, (copy vs[0], copy vs[1]));
pairs.push((copy vs[0], copy vs[1]));
}
move pairs
}
#[cfg(unix)]
fn getenv(n: &str) -> Option<~str> {
pub fn getenv(n: &str) -> Option<~str> {
unsafe {
let s = str::as_c_str(n, libc::getenv);
return if ptr::null::<u8>() == cast::reinterpret_cast(&s) {
@ -238,39 +213,32 @@ mod global_env {
}
#[cfg(windows)]
fn getenv(n: &str) -> Option<~str> {
use libc::types::os::arch::extra::*;
use libc::funcs::extra::kernel32::*;
pub fn getenv(n: &str) -> Option<~str> {
use win32::*;
do as_utf16_p(n) |u| {
do fill_utf16_buf_and_decode() |buf, sz| {
GetEnvironmentVariableW(u, buf, sz)
libc::GetEnvironmentVariableW(u, buf, sz)
}
}
}
#[cfg(unix)]
fn setenv(n: &str, v: &str) {
// FIXME: remove this when export globs work properly. #1238
use libc::funcs::posix01::unistd::setenv;
pub fn setenv(n: &str, v: &str) {
do str::as_c_str(n) |nbuf| {
do str::as_c_str(v) |vbuf| {
setenv(nbuf, vbuf, 1i32);
libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1i32);
}
}
}
#[cfg(windows)]
fn setenv(n: &str, v: &str) {
// FIXME: remove imports when export globs work properly. #1238
use libc::funcs::extra::kernel32::*;
pub fn setenv(n: &str, v: &str) {
use win32::*;
do as_utf16_p(n) |nbuf| {
do as_utf16_p(v) |vbuf| {
SetEnvironmentVariableW(nbuf, vbuf);
libc::SetEnvironmentVariableW(nbuf, vbuf);
}
}
}
@ -278,7 +246,7 @@ mod global_env {
}
}
fn fdopen(fd: c_int) -> *FILE {
pub fn fdopen(fd: c_int) -> *FILE {
return do as_c_charp("r") |modebuf| {
libc::fdopen(fd, modebuf)
};
@ -288,13 +256,13 @@ fn fdopen(fd: c_int) -> *FILE {
// fsync related
#[cfg(windows)]
fn fsync_fd(fd: c_int, _level: io::fsync::Level) -> c_int {
pub fn fsync_fd(fd: c_int, _level: io::fsync::Level) -> c_int {
use libc::funcs::extra::msvcrt::*;
return commit(fd);
}
#[cfg(target_os = "linux")]
fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
use libc::funcs::posix01::unistd::*;
match level {
io::fsync::FSync
@ -304,7 +272,7 @@ fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
}
#[cfg(target_os = "macos")]
fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
use libc::consts::os::extra::*;
use libc::funcs::posix88::fcntl::*;
use libc::funcs::posix01::unistd::*;
@ -321,52 +289,50 @@ fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
}
#[cfg(target_os = "freebsd")]
fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int {
pub fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int {
use libc::funcs::posix01::unistd::*;
return fsync(fd);
}
#[cfg(windows)]
fn waitpid(pid: pid_t) -> c_int {
pub fn waitpid(pid: pid_t) -> c_int {
return rustrt::rust_process_wait(pid);
}
#[cfg(unix)]
fn waitpid(pid: pid_t) -> c_int {
pub fn waitpid(pid: pid_t) -> c_int {
use libc::funcs::posix01::wait::*;
let status = 0 as c_int;
assert (waitpid(pid, ptr::mut_addr_of(status),
assert (waitpid(pid, ptr::mut_addr_of(&status),
0 as c_int) != (-1 as c_int));
return status;
}
#[cfg(unix)]
fn pipe() -> {in: c_int, out: c_int} {
pub fn pipe() -> {in: c_int, out: c_int} {
let fds = {mut in: 0 as c_int,
mut out: 0 as c_int };
assert (libc::pipe(ptr::mut_addr_of(fds.in)) == (0 as c_int));
assert (libc::pipe(ptr::mut_addr_of(&(fds.in))) == (0 as c_int));
return {in: fds.in, out: fds.out};
}
#[cfg(windows)]
fn pipe() -> {in: c_int, out: c_int} {
// FIXME: remove this when export globs work properly. #1238
use libc::consts::os::extra::*;
pub fn pipe() -> {in: c_int, out: c_int} {
// Windows pipes work subtly differently than unix pipes, and their
// inheritance has to be handled in a different way that I do not fully
// understand. Here we explicitly make the pipe non-inheritable, which
// means to pass it to a subprocess they need to be duplicated first, as
// in rust_run_program.
let fds = { mut in: 0 as c_int,
mut out: 0 as c_int };
let res = libc::pipe(ptr::mut_addr_of(fds.in),
mut out: 0 as c_int };
let res = libc::pipe(ptr::mut_addr_of(&(fds.in)),
1024 as c_uint,
(O_BINARY | O_NOINHERIT) as c_int);
(libc::O_BINARY | libc::O_NOINHERIT) as c_int);
assert (res == 0 as c_int);
assert (fds.in != -1 as c_int && fds.in != 0 as c_int);
assert (fds.out != -1 as c_int && fds.in != 0 as c_int);
@ -378,7 +344,7 @@ fn dup2(src: c_int, dst: c_int) -> c_int {
}
fn dll_filename(base: &str) -> ~str {
pub fn dll_filename(base: &str) -> ~str {
return pre() + str::from_slice(base) + dll_suffix();
#[cfg(unix)]
@ -389,7 +355,7 @@ fn dll_filename(base: &str) -> ~str {
}
fn self_exe_path() -> Option<Path> {
pub fn self_exe_path() -> Option<Path> {
#[cfg(target_os = "freebsd")]
fn load_self() -> Option<~str> {
@ -401,7 +367,7 @@ fn self_exe_path() -> Option<Path> {
KERN_PROC as c_int,
KERN_PROC_PATHNAME as c_int, -1 as c_int];
sysctl(vec::raw::to_ptr(mib), vec::len(mib) as c_uint,
buf as *mut c_void, ptr::mut_addr_of(sz),
buf as *mut c_void, ptr::mut_addr_of(&sz),
ptr::null(), 0u as size_t) == (0 as c_int)
}
}
@ -419,27 +385,22 @@ fn self_exe_path() -> Option<Path> {
#[cfg(target_os = "macos")]
fn load_self() -> Option<~str> {
// FIXME: remove imports when export globs work properly. #1238
use libc::funcs::extra::*;
do fill_charp_buf() |buf, sz| {
_NSGetExecutablePath(buf, ptr::mut_addr_of(sz as u32))
== (0 as c_int)
libc::funcs::extra::_NSGetExecutablePath(
buf, ptr::mut_addr_of(&(sz as u32))) == (0 as c_int)
}
}
#[cfg(windows)]
fn load_self() -> Option<~str> {
// FIXME: remove imports when export globs work properly. #1238
use libc::types::os::arch::extra::*;
use libc::funcs::extra::kernel32::*;
use win32::*;
do fill_utf16_buf_and_decode() |buf, sz| {
GetModuleFileNameW(0u as dword, buf, sz)
libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
}
}
do load_self().map |pth| {
Path(pth).dir_path()
Path(*pth).dir_path()
}
}
@ -457,10 +418,10 @@ fn self_exe_path() -> Option<Path> {
*
* Otherwise, homedir returns option::none.
*/
fn homedir() -> Option<Path> {
pub fn homedir() -> Option<Path> {
return match getenv(~"HOME") {
Some(p) => if !str::is_empty(p) {
Some(Path(p))
Some(ref p) => if !str::is_empty(*p) {
Some(Path(*p))
} else {
secondary()
},
@ -474,7 +435,7 @@ fn homedir() -> Option<Path> {
#[cfg(windows)]
fn secondary() -> Option<Path> {
do option::chain(&getenv(~"USERPROFILE")) |p| {
do option::chain(getenv(~"USERPROFILE")) |p| {
if !str::is_empty(p) {
Some(Path(p))
} else {
@ -494,12 +455,12 @@ fn homedir() -> Option<Path> {
* 'USERPROFILE' environment variable if any are set and not the empty
* string. Otherwise, tmpdir returns the path to the Windows directory.
*/
fn tmpdir() -> Path {
pub fn tmpdir() -> Path {
return lookup();
fn getenv_nonempty(v: &str) -> Option<Path> {
match getenv(v) {
Some(x) =>
Some(move x) =>
if str::is_empty(x) {
None
} else {
@ -528,7 +489,7 @@ fn tmpdir() -> Path {
}
}
/// Recursively walk a directory structure
fn walk_dir(p: &Path, f: fn((&Path)) -> bool) {
pub fn walk_dir(p: &Path, f: fn((&Path)) -> bool) {
walk_dir_(p, f);
@ -557,21 +518,19 @@ fn walk_dir(p: &Path, f: fn((&Path)) -> bool) {
}
/// Indicates whether a path represents a directory
fn path_is_dir(p: &Path) -> bool {
pub fn path_is_dir(p: &Path) -> bool {
do str::as_c_str(p.to_str()) |buf| {
rustrt::rust_path_is_dir(buf) != 0 as c_int
}
}
/// Indicates whether a path exists
fn path_exists(p: &Path) -> bool {
pub fn path_exists(p: &Path) -> bool {
do str::as_c_str(p.to_str()) |buf| {
rustrt::rust_path_exists(buf) != 0 as c_int
}
}
// FIXME (#2622): under Windows, we should prepend the current drive letter
// to paths that start with a slash.
/**
* Convert a relative path to an absolute path
*
@ -582,7 +541,7 @@ fn path_exists(p: &Path) -> bool {
// NB: this is here rather than in path because it is a form of environment
// querying; what it does depends on the process working directory, not just
// the input paths.
fn make_absolute(p: &Path) -> Path {
pub fn make_absolute(p: &Path) -> Path {
if p.is_absolute {
copy *p
} else {
@ -592,19 +551,18 @@ fn make_absolute(p: &Path) -> Path {
/// Creates a directory at the specified path
fn make_dir(p: &Path, mode: c_int) -> bool {
pub fn make_dir(p: &Path, mode: c_int) -> bool {
return mkdir(p, mode);
#[cfg(windows)]
fn mkdir(p: &Path, _mode: c_int) -> bool {
// FIXME: remove imports when export globs work properly. #1238
use libc::types::os::arch::extra::*;
use libc::funcs::extra::kernel32::*;
use win32::*;
// FIXME: turn mode into something useful? #2623
do as_utf16_p(p.to_str()) |buf| {
CreateDirectoryW(buf, unsafe { cast::reinterpret_cast(&0) })
!= (0 as BOOL)
libc::CreateDirectoryW(buf, unsafe {
cast::reinterpret_cast(&0)
})
!= (0 as libc::BOOL)
}
}
@ -618,7 +576,7 @@ fn make_dir(p: &Path, mode: c_int) -> bool {
/// Lists the contents of a directory
#[allow(non_implicitly_copyable_typarams)]
fn list_dir(p: &Path) -> ~[~str] {
pub fn list_dir(p: &Path) -> ~[~str] {
#[cfg(unix)]
fn star(p: &Path) -> Path { copy *p }
@ -626,8 +584,8 @@ fn list_dir(p: &Path) -> ~[~str] {
#[cfg(windows)]
fn star(p: &Path) -> Path { p.push("*") }
do rustrt::rust_list_files(star(p).to_str()).filter |filename| {
filename != ~"." && filename != ~".."
do rustrt::rust_list_files2(star(p).to_str()).filter |filename| {
*filename != ~"." && *filename != ~".."
}
}
@ -636,22 +594,19 @@ fn list_dir(p: &Path) -> ~[~str] {
*
* This version prepends each entry with the directory.
*/
fn list_dir_path(p: &Path) -> ~[~Path] {
pub fn list_dir_path(p: &Path) -> ~[~Path] {
os::list_dir(p).map(|f| ~p.push(*f))
}
/// Removes a directory at the specified path
fn remove_dir(p: &Path) -> bool {
pub fn remove_dir(p: &Path) -> bool {
return rmdir(p);
#[cfg(windows)]
fn rmdir(p: &Path) -> bool {
// FIXME: remove imports when export globs work properly. #1238
use libc::funcs::extra::kernel32::*;
use libc::types::os::arch::extra::*;
use win32::*;
return do as_utf16_p(p.to_str()) |buf| {
RemoveDirectoryW(buf) != (0 as BOOL)
libc::RemoveDirectoryW(buf) != (0 as libc::BOOL)
};
}
@ -663,17 +618,14 @@ fn remove_dir(p: &Path) -> bool {
}
}
fn change_dir(p: &Path) -> bool {
pub fn change_dir(p: &Path) -> bool {
return chdir(p);
#[cfg(windows)]
fn chdir(p: &Path) -> bool {
// FIXME: remove imports when export globs work properly. #1238
use libc::funcs::extra::kernel32::*;
use libc::types::os::arch::extra::*;
use win32::*;
return do as_utf16_p(p.to_str()) |buf| {
SetCurrentDirectoryW(buf) != (0 as BOOL)
libc::SetCurrentDirectoryW(buf) != (0 as libc::BOOL)
};
}
@ -686,18 +638,16 @@ fn change_dir(p: &Path) -> bool {
}
/// Copies a file from one location to another
fn copy_file(from: &Path, to: &Path) -> bool {
pub fn copy_file(from: &Path, to: &Path) -> bool {
return do_copy_file(from, to);
#[cfg(windows)]
fn do_copy_file(from: &Path, to: &Path) -> bool {
// FIXME: remove imports when export globs work properly. #1238
use libc::funcs::extra::kernel32::*;
use libc::types::os::arch::extra::*;
use win32::*;
return do as_utf16_p(from.to_str()) |fromp| {
do as_utf16_p(to.to_str()) |top| {
CopyFileW(fromp, top, (0 as BOOL)) != (0 as BOOL)
libc::CopyFileW(fromp, top, (0 as libc::BOOL)) !=
(0 as libc::BOOL)
}
}
}
@ -748,18 +698,14 @@ fn copy_file(from: &Path, to: &Path) -> bool {
}
/// Deletes an existing file
fn remove_file(p: &Path) -> bool {
pub fn remove_file(p: &Path) -> bool {
return unlink(p);
#[cfg(windows)]
fn unlink(p: &Path) -> bool {
// FIXME (similar to Issue #2006): remove imports when export globs
// work properly.
use libc::funcs::extra::kernel32::*;
use libc::types::os::arch::extra::*;
use win32::*;
return do as_utf16_p(p.to_str()) |buf| {
DeleteFileW(buf) != (0 as BOOL)
libc::DeleteFileW(buf) != (0 as libc::BOOL)
};
}
@ -772,7 +718,7 @@ fn remove_file(p: &Path) -> bool {
}
/// Get a string representing the platform-dependent last error
fn last_os_error() -> ~str {
pub fn last_os_error() -> ~str {
rustrt::last_os_error()
}
@ -784,67 +730,175 @@ fn last_os_error() -> ~str {
* and is supervised by the scheduler then any user-specified exit status is
* ignored and the process exits with the default failure status
*/
fn set_exit_status(code: int) {
pub fn set_exit_status(code: int) {
rustrt::rust_set_exit_status(code as libc::intptr_t);
}
#[cfg(unix)]
fn family() -> ~str { ~"unix" }
unsafe fn load_argc_and_argv(argc: c_int, argv: **c_char) -> ~[~str] {
let mut args = ~[];
for uint::range(0, argc as uint) |i| {
vec::push(&mut args, str::raw::from_c_str(*argv.offset(i)));
}
return args;
}
/**
* Returns the command line arguments
*
* Returns a list of the command line arguments.
*/
#[cfg(target_os = "macos")]
fn real_args() -> ~[~str] {
unsafe {
let (argc, argv) = (*_NSGetArgc() as c_int,
*_NSGetArgv() as **c_char);
load_argc_and_argv(argc, argv)
}
}
#[cfg(target_os = "linux")]
#[cfg(target_os = "freebsd")]
fn real_args() -> ~[~str] {
unsafe {
let argc = rustrt::rust_get_argc();
let argv = rustrt::rust_get_argv();
load_argc_and_argv(argc, argv)
}
}
#[cfg(windows)]
fn family() -> ~str { ~"windows" }
fn real_args() -> ~[~str] {
let mut nArgs: c_int = 0;
let lpArgCount = ptr::to_mut_unsafe_ptr(&mut nArgs);
let lpCmdLine = GetCommandLineW();
let szArgList = CommandLineToArgvW(lpCmdLine, lpArgCount);
let mut args = ~[];
for uint::range(0, nArgs as uint) |i| {
unsafe {
// Determine the length of this argument.
let ptr = *szArgList.offset(i);
let mut len = 0;
while *ptr.offset(len) != 0 { len += 1; }
// Push it onto the list.
vec::push(&mut args,
vec::raw::buf_as_slice(ptr, len,
str::from_utf16));
}
}
unsafe {
LocalFree(cast::transmute(szArgList));
}
return args;
}
type LPCWSTR = *u16;
#[cfg(windows)]
#[link_name="kernel32"]
#[abi="stdcall"]
extern {
fn GetCommandLineW() -> LPCWSTR;
fn LocalFree(ptr: *c_void);
}
#[cfg(windows)]
#[link_name="shell32"]
#[abi="stdcall"]
extern {
fn CommandLineToArgvW(lpCmdLine: LPCWSTR, pNumArgs: *mut c_int) -> **u16;
}
struct OverriddenArgs {
val: ~[~str]
}
fn overridden_arg_key(_v: @OverriddenArgs) {}
pub fn args() -> ~[~str] {
unsafe {
match task::local_data::local_data_get(overridden_arg_key) {
None => real_args(),
Some(args) => copy args.val
}
}
}
pub fn set_args(new_args: ~[~str]) {
unsafe {
let overridden_args = @OverriddenArgs { val: copy new_args };
task::local_data::local_data_set(overridden_arg_key, overridden_args);
}
}
#[cfg(target_os = "macos")]
extern {
// These functions are in crt_externs.h.
pub fn _NSGetArgc() -> *c_int;
pub fn _NSGetArgv() -> ***c_char;
}
#[cfg(unix)]
pub fn family() -> ~str { ~"unix" }
#[cfg(windows)]
pub fn family() -> ~str { ~"windows" }
#[cfg(target_os = "macos")]
mod consts {
#[legacy_exports];
fn sysname() -> ~str { ~"macos" }
fn exe_suffix() -> ~str { ~"" }
fn dll_suffix() -> ~str { ~".dylib" }
pub fn sysname() -> ~str { ~"macos" }
pub fn exe_suffix() -> ~str { ~"" }
pub fn dll_suffix() -> ~str { ~".dylib" }
}
#[cfg(target_os = "freebsd")]
mod consts {
#[legacy_exports];
fn sysname() -> ~str { ~"freebsd" }
fn exe_suffix() -> ~str { ~"" }
fn dll_suffix() -> ~str { ~".so" }
pub fn sysname() -> ~str { ~"freebsd" }
pub fn exe_suffix() -> ~str { ~"" }
pub fn dll_suffix() -> ~str { ~".so" }
}
#[cfg(target_os = "linux")]
mod consts {
#[legacy_exports];
fn sysname() -> ~str { ~"linux" }
fn exe_suffix() -> ~str { ~"" }
fn dll_suffix() -> ~str { ~".so" }
pub fn sysname() -> ~str { ~"linux" }
pub fn exe_suffix() -> ~str { ~"" }
pub fn dll_suffix() -> ~str { ~".so" }
}
#[cfg(target_os = "win32")]
mod consts {
#[legacy_exports];
fn sysname() -> ~str { ~"win32" }
fn exe_suffix() -> ~str { ~".exe" }
fn dll_suffix() -> ~str { ~".dll" }
pub fn sysname() -> ~str { ~"win32" }
pub fn exe_suffix() -> ~str { ~".exe" }
pub fn dll_suffix() -> ~str { ~".dll" }
}
#[cfg(target_arch = "x86")]
fn arch() -> ~str { ~"x86" }
pub fn arch() -> ~str { ~"x86" }
#[cfg(target_arch = "x86_64")]
fn arch() -> ~str { ~"x86_64" }
pub fn arch() -> ~str { ~"x86_64" }
#[cfg(target_arch = "arm")]
fn arch() -> str { ~"arm" }
pub fn arch() -> str { ~"arm" }
#[cfg(test)]
#[allow(non_implicitly_copyable_typarams)]
mod tests {
#[legacy_exports];
#[test]
fn last_os_error() {
pub fn last_os_error() {
log(debug, last_os_error());
}
#[test]
pub fn test_args() {
let a = real_args();
assert a.len() >= 1;
}
fn make_rand_name() -> ~str {
let rng: rand::Rng = rand::Rng();
let n = ~"TEST" + rng.gen_str(10u);
@ -919,10 +973,10 @@ mod tests {
let mut e = env();
setenv(n, ~"VALUE");
assert !vec::contains(e, (copy n, ~"VALUE"));
assert !vec::contains(e, &(copy n, ~"VALUE"));
e = env();
assert vec::contains(e, (n, ~"VALUE"));
assert vec::contains(e, &(n, ~"VALUE"));
}
#[test]
@ -946,7 +1000,7 @@ mod tests {
setenv(~"HOME", ~"");
assert os::homedir().is_none();
oldhome.iter(|s| setenv(~"HOME", s));
oldhome.iter(|s| setenv(~"HOME", *s));
}
#[test]
@ -973,9 +1027,9 @@ mod tests {
setenv(~"USERPROFILE", ~"/home/PaloAlto");
assert os::homedir() == Some(Path("/home/MountainView"));
option::iter(&oldhome, |s| setenv(~"HOME", s));
option::iter(&oldhome, |s| setenv(~"HOME", *s));
option::iter(&olduserprofile,
|s| setenv(~"USERPROFILE", s));
|s| setenv(~"USERPROFILE", *s));
}
#[test]

View file

@ -10,19 +10,19 @@ Cross-platform file path handling
use cmp::Eq;
struct WindowsPath {
pub struct WindowsPath {
host: Option<~str>,
device: Option<~str>,
is_absolute: bool,
components: ~[~str],
}
struct PosixPath {
pub struct PosixPath {
is_absolute: bool,
components: ~[~str],
}
trait GenericPath {
pub trait GenericPath {
static pure fn from_str((&str)) -> self;
@ -45,18 +45,18 @@ trait GenericPath {
}
#[cfg(windows)]
type Path = WindowsPath;
pub type Path = WindowsPath;
#[cfg(windows)]
pure fn Path(s: &str) -> Path {
pub pure fn Path(s: &str) -> Path {
from_str::<WindowsPath>(s)
}
#[cfg(unix)]
type Path = PosixPath;
pub type Path = PosixPath;
#[cfg(unix)]
pure fn Path(s: &str) -> Path {
pub pure fn Path(s: &str) -> Path {
from_str::<PosixPath>(s)
}
@ -167,7 +167,7 @@ impl PosixPath : GenericPath {
if t.len() == 0 {
match self.filestem() {
None => copy self,
Some(s) => self.with_filename(s)
Some(ref s) => self.with_filename(*s)
}
} else {
let t = ~"." + str::from_slice(t);
@ -206,7 +206,7 @@ impl PosixPath : GenericPath {
let mut ss = str::split_nonempty(
*e,
|c| windows::is_sep(c as u8));
unsafe { vec::push_all_move(v, move ss); }
unsafe { v.push_all_move(move ss); }
}
PosixPath { components: move v, ..self }
}
@ -214,14 +214,14 @@ impl PosixPath : GenericPath {
pure fn push(s: &str) -> PosixPath {
let mut v = copy self.components;
let mut ss = str::split_nonempty(s, |c| windows::is_sep(c as u8));
unsafe { vec::push_all_move(v, move ss); }
unsafe { v.push_all_move(move ss); }
PosixPath { components: move v, ..self }
}
pure fn pop() -> PosixPath {
let mut cs = copy self.components;
if cs.len() != 0 {
unsafe { vec::pop(cs); }
unsafe { cs.pop(); }
}
return PosixPath { components: move cs, ..self }
}
@ -239,11 +239,11 @@ impl WindowsPath : ToStr {
fn to_str() -> ~str {
let mut s = ~"";
match self.host {
Some(h) => { s += "\\\\"; s += h; }
Some(ref h) => { s += "\\\\"; s += *h; }
None => { }
}
match self.device {
Some(d) => { s += d; s += ":"; }
Some(ref d) => { s += *d; s += ":"; }
None => { }
}
if self.is_absolute {
@ -358,7 +358,7 @@ impl WindowsPath : GenericPath {
if t.len() == 0 {
match self.filestem() {
None => copy self,
Some(s) => self.with_filename(s)
Some(ref s) => self.with_filename(*s)
}
} else {
let t = ~"." + str::from_slice(t);
@ -400,7 +400,7 @@ impl WindowsPath : GenericPath {
let mut ss = str::split_nonempty(
*e,
|c| windows::is_sep(c as u8));
unsafe { vec::push_all_move(v, move ss); }
unsafe { v.push_all_move(move ss); }
}
return WindowsPath { components: move v, ..self }
}
@ -408,14 +408,14 @@ impl WindowsPath : GenericPath {
pure fn push(s: &str) -> WindowsPath {
let mut v = copy self.components;
let mut ss = str::split_nonempty(s, |c| windows::is_sep(c as u8));
unsafe { vec::push_all_move(v, move ss); }
unsafe { v.push_all_move(move ss); }
return WindowsPath { components: move v, ..self }
}
pure fn pop() -> WindowsPath {
let mut cs = copy self.components;
if cs.len() != 0 {
unsafe { vec::pop(cs); }
unsafe { cs.pop(); }
}
return WindowsPath { components: move cs, ..self }
}
@ -429,7 +429,7 @@ impl WindowsPath : GenericPath {
}
pure fn normalize(components: &[~str]) -> ~[~str] {
pub pure fn normalize(components: &[~str]) -> ~[~str] {
let mut cs = ~[];
unsafe {
for components.each |c| {
@ -437,10 +437,10 @@ pure fn normalize(components: &[~str]) -> ~[~str] {
if *c == ~"." && components.len() > 1 { loop; }
if *c == ~"" { loop; }
if *c == ~".." && cs.len() != 0 {
vec::pop(cs);
cs.pop();
loop;
}
vec::push(cs, copy *c);
cs.push(copy *c);
}
}
}
@ -462,7 +462,6 @@ fn test_double_slash_collapsing()
}
mod posix {
#[legacy_exports];
#[cfg(test)]
fn mk(s: &str) -> PosixPath { from_str::<PosixPath>(s) }
@ -553,14 +552,13 @@ mod posix {
// Various windows helpers, and tests for the impl.
mod windows {
#[legacy_exports];
#[inline(always)]
pure fn is_sep(u: u8) -> bool {
pub pure fn is_sep(u: u8) -> bool {
u == '/' as u8 || u == '\\' as u8
}
pure fn extract_unc_prefix(s: &str) -> Option<(~str,~str)> {
pub pure fn extract_unc_prefix(s: &str) -> Option<(~str,~str)> {
if (s.len() > 1 &&
s[0] == '\\' as u8 &&
s[1] == '\\' as u8) {
@ -577,7 +575,7 @@ mod windows {
None
}
pure fn extract_drive_prefix(s: &str) -> Option<(~str,~str)> {
pub pure fn extract_drive_prefix(s: &str) -> Option<(~str,~str)> {
unsafe {
if (s.len() > 1 &&
libc::isalpha(s[0] as libc::c_int) != 0 &&

View file

@ -73,7 +73,7 @@ bounded and unbounded protocols allows for less code duplication.
*/
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
// tjc: re-forbid deprecated modes after snapshot
#[forbid(deprecated_pattern)];
use cmp::Eq;
@ -81,31 +81,11 @@ use cast::{forget, reinterpret_cast, transmute};
use either::{Either, Left, Right};
use option::unwrap;
// Things used by code generated by the pipe compiler.
export entangle, get_buffer, drop_buffer;
export SendPacketBuffered, RecvPacketBuffered;
export Packet, packet, mk_packet, entangle_buffer, HasBuffer, BufferHeader;
// export these so we can find them in the buffer_resource
// destructor. This is probably a symptom of #3005.
export atomic_add_acq, atomic_sub_rel;
// User-level things
export SendPacket, RecvPacket, send, recv, try_recv, peek;
export select, select2, selecti, select2i, selectable;
export spawn_service, spawn_service_recv;
export stream, Port, Chan, SharedChan, PortSet, Channel;
export oneshot, ChanOne, PortOne;
export recv_one, try_recv_one, send_one, try_send_one;
// Functions used by the protocol compiler
export rt;
#[doc(hidden)]
const SPIN_COUNT: uint = 0;
macro_rules! move_it (
{ $x:expr } => { unsafe { let y <- *ptr::addr_of($x); move y } }
{ $x:expr } => { unsafe { let y <- *ptr::addr_of(&($x)); move y } }
)
#[doc(hidden)]
@ -123,7 +103,7 @@ impl State : Eq {
pure fn ne(other: &State) -> bool { !self.eq(other) }
}
struct BufferHeader {
pub struct BufferHeader {
// Tracks whether this buffer needs to be freed. We can probably
// get away with restricting it to 0 or 1, if we're careful.
mut ref_count: int,
@ -132,7 +112,7 @@ struct BufferHeader {
// thing along.
}
fn BufferHeader() -> BufferHeader{
pub fn BufferHeader() -> BufferHeader{
BufferHeader {
ref_count: 0
}
@ -195,13 +175,13 @@ impl PacketHeader {
}
#[doc(hidden)]
type Packet<T: Send> = {
pub type Packet<T: Send> = {
header: PacketHeader,
mut payload: Option<T>,
};
#[doc(hidden)]
trait HasBuffer {
pub trait HasBuffer {
// XXX This should not have a trailing underscore
fn set_buffer_(b: *libc::c_void);
}
@ -213,7 +193,7 @@ impl<T: Send> Packet<T>: HasBuffer {
}
#[doc(hidden)]
fn mk_packet<T: Send>() -> Packet<T> {
pub fn mk_packet<T: Send>() -> Packet<T> {
{
header: PacketHeader(),
mut payload: None
@ -237,17 +217,17 @@ fn unibuffer<T: Send>() -> ~Buffer<Packet<T>> {
}
#[doc(hidden)]
fn packet<T: Send>() -> *Packet<T> {
pub fn packet<T: Send>() -> *Packet<T> {
let b = unibuffer();
let p = ptr::addr_of(b.data);
let p = ptr::addr_of(&(b.data));
// We'll take over memory management from here.
unsafe { forget(move b) }
p
}
#[doc(hidden)]
fn entangle_buffer<T: Send, Tstart: Send>(
+buffer: ~Buffer<T>,
pub fn entangle_buffer<T: Send, Tstart: Send>(
buffer: ~Buffer<T>,
init: fn(*libc::c_void, x: &T) -> *Packet<Tstart>)
-> (SendPacketBuffered<Tstart, T>, RecvPacketBuffered<Tstart, T>)
{
@ -256,52 +236,36 @@ fn entangle_buffer<T: Send, Tstart: Send>(
(SendPacketBuffered(p), RecvPacketBuffered(p))
}
#[cfg(stage0)]
#[abi = "rust-intrinsic"]
#[doc(hidden)]
extern mod rusti {
#[legacy_exports];
fn atomic_xchg(dst: &mut int, ++src: int) -> int;
fn atomic_xchg_acq(dst: &mut int, ++src: int) -> int;
fn atomic_xchg_rel(dst: &mut int, ++src: int) -> int;
fn atomic_xchg(dst: &mut int, src: int) -> int;
fn atomic_xchg_acq(dst: &mut int, src: int) -> int;
fn atomic_xchg_rel(dst: &mut int, src: int) -> int;
fn atomic_xadd_acq(dst: &mut int, ++src: int) -> int;
fn atomic_xsub_rel(dst: &mut int, ++src: int) -> int;
}
#[cfg(stage1)]
#[cfg(stage2)]
#[abi = "rust-intrinsic"]
#[doc(hidden)]
extern mod rusti {
#[legacy_exports];
fn atomic_xchg(dst: &mut int, +src: int) -> int;
fn atomic_xchg_acq(dst: &mut int, +src: int) -> int;
fn atomic_xchg_rel(dst: &mut int, +src: int) -> int;
fn atomic_xadd_acq(dst: &mut int, +src: int) -> int;
fn atomic_xsub_rel(dst: &mut int, +src: int) -> int;
fn atomic_xadd_acq(dst: &mut int, src: int) -> int;
fn atomic_xsub_rel(dst: &mut int, src: int) -> int;
}
// If I call the rusti versions directly from a polymorphic function,
// I get link errors. This is a bug that needs investigated more.
#[doc(hidden)]
fn atomic_xchng_rel(dst: &mut int, src: int) -> int {
pub fn atomic_xchng_rel(dst: &mut int, src: int) -> int {
rusti::atomic_xchg_rel(dst, src)
}
#[doc(hidden)]
fn atomic_add_acq(dst: &mut int, src: int) -> int {
pub fn atomic_add_acq(dst: &mut int, src: int) -> int {
rusti::atomic_xadd_acq(dst, src)
}
#[doc(hidden)]
fn atomic_sub_rel(dst: &mut int, src: int) -> int {
pub fn atomic_sub_rel(dst: &mut int, src: int) -> int {
rusti::atomic_xsub_rel(dst, src)
}
#[doc(hidden)]
fn swap_task(+dst: &mut *rust_task, src: *rust_task) -> *rust_task {
pub fn swap_task(dst: &mut *rust_task, src: *rust_task) -> *rust_task {
// It might be worth making both acquire and release versions of
// this.
unsafe {
@ -315,7 +279,6 @@ type rust_task = libc::c_void;
#[doc(hidden)]
extern mod rustrt {
#[legacy_exports];
#[rust_stack]
fn rust_get_task() -> *rust_task;
#[rust_stack]
@ -341,21 +304,21 @@ fn wait_event(this: *rust_task) -> *libc::c_void {
}
#[doc(hidden)]
fn swap_state_acq(+dst: &mut State, src: State) -> State {
fn swap_state_acq(dst: &mut State, src: State) -> State {
unsafe {
transmute(rusti::atomic_xchg_acq(transmute(move dst), src as int))
}
}
#[doc(hidden)]
fn swap_state_rel(+dst: &mut State, src: State) -> State {
fn swap_state_rel(dst: &mut State, src: State) -> State {
unsafe {
transmute(rusti::atomic_xchg_rel(transmute(move dst), src as int))
}
}
#[doc(hidden)]
unsafe fn get_buffer<T: Send>(p: *PacketHeader) -> ~Buffer<T> {
pub unsafe fn get_buffer<T: Send>(p: *PacketHeader) -> ~Buffer<T> {
transmute((*p).buf_header())
}
@ -380,7 +343,7 @@ struct BufferResource<T: Send> {
}
}
fn BufferResource<T: Send>(+b: ~Buffer<T>) -> BufferResource<T> {
fn BufferResource<T: Send>(b: ~Buffer<T>) -> BufferResource<T> {
//let p = ptr::addr_of(*b);
//error!("take %?", p);
atomic_add_acq(&mut b.header.ref_count, 1);
@ -391,12 +354,12 @@ fn BufferResource<T: Send>(+b: ~Buffer<T>) -> BufferResource<T> {
}
#[doc(hidden)]
fn send<T: Send, Tbuffer: Send>(+p: SendPacketBuffered<T, Tbuffer>,
+payload: T) -> bool {
pub fn send<T: Send, Tbuffer: Send>(p: SendPacketBuffered<T, Tbuffer>,
payload: T) -> bool {
let header = p.header();
let p_ = p.unwrap();
let p = unsafe { &*p_ };
assert ptr::addr_of(p.header) == header;
assert ptr::addr_of(&(p.header)) == header;
assert p.payload.is_none();
p.payload <- Some(move payload);
let old_state = swap_state_rel(&mut p.header.state, Full);
@ -414,7 +377,7 @@ fn send<T: Send, Tbuffer: Send>(+p: SendPacketBuffered<T, Tbuffer>,
let old_task = swap_task(&mut p.header.blocked_task, ptr::null());
if !old_task.is_null() {
rustrt::task_signal_event(
old_task, ptr::addr_of(p.header) as *libc::c_void);
old_task, ptr::addr_of(&(p.header)) as *libc::c_void);
rustrt::rust_task_deref(old_task);
}
@ -435,7 +398,7 @@ fn send<T: Send, Tbuffer: Send>(+p: SendPacketBuffered<T, Tbuffer>,
Fails if the sender closes the connection.
*/
fn recv<T: Send, Tbuffer: Send>(+p: RecvPacketBuffered<T, Tbuffer>) -> T {
pub fn recv<T: Send, Tbuffer: Send>(p: RecvPacketBuffered<T, Tbuffer>) -> T {
option::unwrap_expect(try_recv(move p), "connection closed")
}
@ -445,7 +408,7 @@ Returns `none` if the sender has closed the connection without sending
a message, or `Some(T)` if a message was received.
*/
fn try_recv<T: Send, Tbuffer: Send>(+p: RecvPacketBuffered<T, Tbuffer>)
pub fn try_recv<T: Send, Tbuffer: Send>(p: RecvPacketBuffered<T, Tbuffer>)
-> Option<T>
{
let p_ = p.unwrap();
@ -539,7 +502,7 @@ fn try_recv<T: Send, Tbuffer: Send>(+p: RecvPacketBuffered<T, Tbuffer>)
}
/// Returns true if messages are available.
pure fn peek<T: Send, Tb: Send>(p: &RecvPacketBuffered<T, Tb>) -> bool {
pub pure fn peek<T: Send, Tb: Send>(p: &RecvPacketBuffered<T, Tb>) -> bool {
match unsafe {(*p.header()).state} {
Empty => false,
Blocked => fail ~"peeking on blocked packet",
@ -566,7 +529,7 @@ fn sender_terminate<T: Send>(p: *Packet<T>) {
if !old_task.is_null() {
rustrt::task_signal_event(
old_task,
ptr::addr_of(p.header) as *libc::c_void);
ptr::addr_of(&(p.header)) as *libc::c_void);
rustrt::rust_task_deref(old_task);
}
// The receiver will eventually clean up.
@ -691,9 +654,9 @@ Sometimes messages will be available on both endpoints at once. In
this case, `select2` may return either `left` or `right`.
*/
fn select2<A: Send, Ab: Send, B: Send, Bb: Send>(
+a: RecvPacketBuffered<A, Ab>,
+b: RecvPacketBuffered<B, Bb>)
pub fn select2<A: Send, Ab: Send, B: Send, Bb: Send>(
a: RecvPacketBuffered<A, Ab>,
b: RecvPacketBuffered<B, Bb>)
-> Either<(Option<A>, RecvPacketBuffered<B, Bb>),
(RecvPacketBuffered<A, Ab>, Option<B>)>
{
@ -716,12 +679,13 @@ impl *PacketHeader: Selectable {
}
/// Returns the index of an endpoint that is ready to receive.
fn selecti<T: Selectable>(endpoints: &[T]) -> uint {
pub fn selecti<T: Selectable>(endpoints: &[T]) -> uint {
wait_many(endpoints)
}
/// Returns 0 or 1 depending on which endpoint is ready to receive
fn select2i<A: Selectable, B: Selectable>(a: &A, b: &B) -> Either<(), ()> {
pub fn select2i<A: Selectable, B: Selectable>(a: &A, b: &B) ->
Either<(), ()> {
match wait_many([a.header(), b.header()]/_) {
0 => Left(()),
1 => Right(()),
@ -733,12 +697,12 @@ fn select2i<A: Selectable, B: Selectable>(a: &A, b: &B) -> Either<(), ()> {
list of the remaining endpoints.
*/
fn select<T: Send, Tb: Send>(+endpoints: ~[RecvPacketBuffered<T, Tb>])
pub fn select<T: Send, Tb: Send>(endpoints: ~[RecvPacketBuffered<T, Tb>])
-> (uint, Option<T>, ~[RecvPacketBuffered<T, Tb>])
{
let ready = wait_many(endpoints.map(|p| p.header()));
let mut remaining <- endpoints;
let port = vec::swap_remove(remaining, ready);
let port = remaining.swap_remove(ready);
let result = try_recv(move port);
(ready, move result, move remaining)
}
@ -747,14 +711,14 @@ fn select<T: Send, Tb: Send>(+endpoints: ~[RecvPacketBuffered<T, Tb>])
message.
*/
type SendPacket<T: Send> = SendPacketBuffered<T, Packet<T>>;
pub type SendPacket<T: Send> = SendPacketBuffered<T, Packet<T>>;
#[doc(hidden)]
fn SendPacket<T: Send>(p: *Packet<T>) -> SendPacket<T> {
pub fn SendPacket<T: Send>(p: *Packet<T>) -> SendPacket<T> {
SendPacketBuffered(p)
}
struct SendPacketBuffered<T: Send, Tbuffer: Send> {
pub struct SendPacketBuffered<T: Send, Tbuffer: Send> {
mut p: Option<*Packet<T>>,
mut buffer: Option<BufferResource<Tbuffer>>,
drop {
@ -773,14 +737,14 @@ struct SendPacketBuffered<T: Send, Tbuffer: Send> {
}
}
fn SendPacketBuffered<T: Send, Tbuffer: Send>(p: *Packet<T>)
pub fn SendPacketBuffered<T: Send, Tbuffer: Send>(p: *Packet<T>)
-> SendPacketBuffered<T, Tbuffer> {
//debug!("take send %?", p);
SendPacketBuffered {
p: Some(p),
buffer: unsafe {
Some(BufferResource(
get_buffer(ptr::addr_of((*p).header))))
get_buffer(ptr::addr_of(&((*p).header)))))
}
}
}
@ -796,7 +760,7 @@ impl<T: Send, Tbuffer: Send> SendPacketBuffered<T, Tbuffer> {
match self.p {
Some(packet) => unsafe {
let packet = &*packet;
let header = ptr::addr_of(packet.header);
let header = ptr::addr_of(&(packet.header));
//forget(packet);
header
},
@ -814,14 +778,14 @@ impl<T: Send, Tbuffer: Send> SendPacketBuffered<T, Tbuffer> {
/// Represents the receive end of a pipe. It can receive exactly one
/// message.
type RecvPacket<T: Send> = RecvPacketBuffered<T, Packet<T>>;
pub type RecvPacket<T: Send> = RecvPacketBuffered<T, Packet<T>>;
#[doc(hidden)]
fn RecvPacket<T: Send>(p: *Packet<T>) -> RecvPacket<T> {
pub fn RecvPacket<T: Send>(p: *Packet<T>) -> RecvPacket<T> {
RecvPacketBuffered(p)
}
struct RecvPacketBuffered<T: Send, Tbuffer: Send> {
pub struct RecvPacketBuffered<T: Send, Tbuffer: Send> {
mut p: Option<*Packet<T>>,
mut buffer: Option<BufferResource<Tbuffer>>,
drop {
@ -851,7 +815,7 @@ impl<T: Send, Tbuffer: Send> RecvPacketBuffered<T, Tbuffer> : Selectable {
match self.p {
Some(packet) => unsafe {
let packet = &*packet;
let header = ptr::addr_of(packet.header);
let header = ptr::addr_of(&(packet.header));
//forget(packet);
header
},
@ -867,20 +831,20 @@ impl<T: Send, Tbuffer: Send> RecvPacketBuffered<T, Tbuffer> : Selectable {
}
}
fn RecvPacketBuffered<T: Send, Tbuffer: Send>(p: *Packet<T>)
pub fn RecvPacketBuffered<T: Send, Tbuffer: Send>(p: *Packet<T>)
-> RecvPacketBuffered<T, Tbuffer> {
//debug!("take recv %?", p);
RecvPacketBuffered {
p: Some(p),
buffer: unsafe {
Some(BufferResource(
get_buffer(ptr::addr_of((*p).header))))
get_buffer(ptr::addr_of(&((*p).header)))))
}
}
}
#[doc(hidden)]
fn entangle<T: Send>() -> (SendPacket<T>, RecvPacket<T>) {
pub fn entangle<T: Send>() -> (SendPacket<T>, RecvPacket<T>) {
let p = packet();
(SendPacket(p), RecvPacket(p))
}
@ -892,10 +856,10 @@ endpoint. The send endpoint is returned to the caller and the receive
endpoint is passed to the new task.
*/
fn spawn_service<T: Send, Tb: Send>(
pub fn spawn_service<T: Send, Tb: Send>(
init: extern fn() -> (SendPacketBuffered<T, Tb>,
RecvPacketBuffered<T, Tb>),
+service: fn~(+v: RecvPacketBuffered<T, Tb>))
+service: fn~(v: RecvPacketBuffered<T, Tb>))
-> SendPacketBuffered<T, Tb>
{
let (client, server) = init();
@ -916,10 +880,10 @@ fn spawn_service<T: Send, Tb: Send>(
receive state.
*/
fn spawn_service_recv<T: Send, Tb: Send>(
pub fn spawn_service_recv<T: Send, Tb: Send>(
init: extern fn() -> (RecvPacketBuffered<T, Tb>,
SendPacketBuffered<T, Tb>),
+service: fn~(+v: SendPacketBuffered<T, Tb>))
+service: fn~(v: SendPacketBuffered<T, Tb>))
-> RecvPacketBuffered<T, Tb>
{
let (client, server) = init();
@ -945,19 +909,19 @@ proto! streamp (
)
/// A trait for things that can send multiple messages.
trait Channel<T: Send> {
pub trait Channel<T: Send> {
// It'd be nice to call this send, but it'd conflict with the
// built in send kind.
/// Sends a message.
fn send(+x: T);
fn send(x: T);
/// Sends a message, or report if the receiver has closed the connection.
fn try_send(+x: T) -> bool;
fn try_send(x: T) -> bool;
}
/// A trait for things that can receive multiple messages.
trait Recv<T: Send> {
pub trait Recv<T: Send> {
/// Receives a message, or fails if the connection closes.
fn recv() -> T;
@ -978,7 +942,7 @@ trait Recv<T: Send> {
type Chan_<T:Send> = { mut endp: Option<streamp::client::Open<T>> };
/// An endpoint that can send many messages.
enum Chan<T:Send> {
pub enum Chan<T:Send> {
Chan_(Chan_<T>)
}
@ -986,7 +950,7 @@ enum Chan<T:Send> {
type Port_<T:Send> = { mut endp: Option<streamp::server::Open<T>> };
/// An endpoint that can receive many messages.
enum Port<T:Send> {
pub enum Port<T:Send> {
Port_(Port_<T>)
}
@ -995,21 +959,21 @@ enum Port<T:Send> {
These allow sending or receiving an unlimited number of messages.
*/
fn stream<T:Send>() -> (Chan<T>, Port<T>) {
pub fn stream<T:Send>() -> (Chan<T>, Port<T>) {
let (c, s) = streamp::init();
(Chan_({ mut endp: Some(move c) }), Port_({ mut endp: Some(move s) }))
}
impl<T: Send> Chan<T>: Channel<T> {
fn send(+x: T) {
fn send(x: T) {
let mut endp = None;
endp <-> self.endp;
self.endp = Some(
streamp::client::data(unwrap(move endp), move x))
}
fn try_send(+x: T) -> bool {
fn try_send(x: T) -> bool {
let mut endp = None;
endp <-> self.endp;
match move streamp::client::try_data(unwrap(move endp), move x) {
@ -1047,7 +1011,7 @@ impl<T: Send> Port<T>: Recv<T> {
let mut endp = None;
endp <-> self.endp;
let peek = match endp {
Some(endp) => pipes::peek(&endp),
Some(ref endp) => pipes::peek(endp),
None => fail ~"peeking empty stream"
};
self.endp <-> endp;
@ -1058,18 +1022,18 @@ impl<T: Send> Port<T>: Recv<T> {
impl<T: Send> Port<T>: Selectable {
pure fn header() -> *PacketHeader unsafe {
match self.endp {
Some(endp) => endp.header(),
Some(ref endp) => endp.header(),
None => fail ~"peeking empty stream"
}
}
}
/// Treat many ports as one.
struct PortSet<T: Send> {
pub struct PortSet<T: Send> {
mut ports: ~[pipes::Port<T>],
}
fn PortSet<T: Send>() -> PortSet<T>{
pub fn PortSet<T: Send>() -> PortSet<T>{
PortSet {
ports: ~[]
}
@ -1077,8 +1041,8 @@ fn PortSet<T: Send>() -> PortSet<T>{
impl<T: Send> PortSet<T> : Recv<T> {
fn add(+port: pipes::Port<T>) {
vec::push(self.ports, move port)
fn add(port: pipes::Port<T>) {
self.ports.push(move port)
}
fn chan() -> Chan<T> {
@ -1101,7 +1065,7 @@ impl<T: Send> PortSet<T> : Recv<T> {
}
None => {
// Remove this port.
let _ = vec::swap_remove(ports, i);
let _ = ports.swap_remove(i);
}
}
}
@ -1124,10 +1088,10 @@ impl<T: Send> PortSet<T> : Recv<T> {
}
/// A channel that can be shared between many senders.
type SharedChan<T: Send> = private::Exclusive<Chan<T>>;
pub type SharedChan<T: Send> = private::Exclusive<Chan<T>>;
impl<T: Send> SharedChan<T>: Channel<T> {
fn send(+x: T) {
fn send(x: T) {
let mut xx = Some(move x);
do self.with_imm |chan| {
let mut x = None;
@ -1136,7 +1100,7 @@ impl<T: Send> SharedChan<T>: Channel<T> {
}
}
fn try_send(+x: T) -> bool {
fn try_send(x: T) -> bool {
let mut xx = Some(move x);
do self.with_imm |chan| {
let mut x = None;
@ -1147,12 +1111,12 @@ impl<T: Send> SharedChan<T>: Channel<T> {
}
/// Converts a `chan` into a `shared_chan`.
fn SharedChan<T:Send>(+c: Chan<T>) -> SharedChan<T> {
pub fn SharedChan<T:Send>(c: Chan<T>) -> SharedChan<T> {
private::exclusive(move c)
}
/// Receive a message from one of two endpoints.
trait Select2<T: Send, U: Send> {
pub trait Select2<T: Send, U: Send> {
/// Receive a message or return `none` if a connection closes.
fn try_select() -> Either<Option<T>, Option<U>>;
/// Receive a message or fail if a connection closes.
@ -1164,7 +1128,7 @@ impl<T: Send, U: Send, Left: Selectable Recv<T>, Right: Selectable Recv<U>>
fn select() -> Either<T, U> {
match self {
(lp, rp) => match select2i(&lp, &rp) {
(ref lp, ref rp) => match select2i(lp, rp) {
Left(()) => Left (lp.recv()),
Right(()) => Right(rp.recv())
}
@ -1173,7 +1137,7 @@ impl<T: Send, U: Send, Left: Selectable Recv<T>, Right: Selectable Recv<U>>
fn try_select() -> Either<Option<T>, Option<U>> {
match self {
(lp, rp) => match select2i(&lp, &rp) {
(ref lp, ref rp) => match select2i(lp, rp) {
Left(()) => Left (lp.try_recv()),
Right(()) => Right(rp.try_recv())
}
@ -1188,12 +1152,12 @@ proto! oneshot (
)
/// The send end of a oneshot pipe.
type ChanOne<T: Send> = oneshot::client::Oneshot<T>;
pub type ChanOne<T: Send> = oneshot::client::Oneshot<T>;
/// The receive end of a oneshot pipe.
type PortOne<T: Send> = oneshot::server::Oneshot<T>;
pub type PortOne<T: Send> = oneshot::server::Oneshot<T>;
/// Initialiase a (send-endpoint, recv-endpoint) oneshot pipe pair.
fn oneshot<T: Send>() -> (ChanOne<T>, PortOne<T>) {
pub fn oneshot<T: Send>() -> (ChanOne<T>, PortOne<T>) {
oneshot::init()
}
@ -1201,13 +1165,13 @@ fn oneshot<T: Send>() -> (ChanOne<T>, PortOne<T>) {
* Receive a message from a oneshot pipe, failing if the connection was
* closed.
*/
fn recv_one<T: Send>(+port: PortOne<T>) -> T {
pub fn recv_one<T: Send>(port: PortOne<T>) -> T {
let oneshot::send(message) = recv(move port);
move message
}
/// Receive a message from a oneshot pipe unless the connection was closed.
fn try_recv_one<T: Send> (+port: PortOne<T>) -> Option<T> {
pub fn try_recv_one<T: Send> (port: PortOne<T>) -> Option<T> {
let message = try_recv(move port);
if message.is_none() { None }
@ -1218,7 +1182,7 @@ fn try_recv_one<T: Send> (+port: PortOne<T>) -> Option<T> {
}
/// Send a message on a oneshot pipe, failing if the connection was closed.
fn send_one<T: Send>(+chan: ChanOne<T>, +data: T) {
pub fn send_one<T: Send>(chan: ChanOne<T>, data: T) {
oneshot::client::send(move chan, move data);
}
@ -1226,24 +1190,22 @@ fn send_one<T: Send>(+chan: ChanOne<T>, +data: T) {
* Send a message on a oneshot pipe, or return false if the connection was
* closed.
*/
fn try_send_one<T: Send>(+chan: ChanOne<T>, +data: T)
pub fn try_send_one<T: Send>(chan: ChanOne<T>, data: T)
-> bool {
oneshot::client::try_send(move chan, move data).is_some()
}
mod rt {
#[legacy_exports];
pub mod rt {
// These are used to hide the option constructors from the
// compiler because their names are changing
fn make_some<T>(+val: T) -> Option<T> { Some(move val) }
fn make_none<T>() -> Option<T> { None }
pub fn make_some<T>(val: T) -> Option<T> { Some(move val) }
pub fn make_none<T>() -> Option<T> { None }
}
#[cfg(test)]
mod test {
#[legacy_exports];
pub mod test {
#[test]
fn test_select2() {
pub fn test_select2() {
let (c1, p1) = pipes::stream();
let (c2, p2) = pipes::stream();
@ -1258,7 +1220,7 @@ mod test {
}
#[test]
fn test_oneshot() {
pub fn test_oneshot() {
let (c, p) = oneshot::init();
oneshot::client::send(c, ());

View file

@ -1,16 +1,9 @@
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
// tjc: re-forbid deprecated modes after snapshot
#[forbid(deprecated_pattern)];
#[doc(hidden)];
export chan_from_global_ptr, weaken_task;
export SharedMutableState, shared_mutable_state, clone_shared_mutable_state;
export get_shared_mutable_state, get_shared_immutable_state;
export unwrap_shared_mutable_state;
export Exclusive, exclusive, unwrap_exclusive;
use compare_and_swap = rustrt::rust_compare_and_swap_ptr;
use task::TaskBuilder;
use task::atomically;
@ -49,7 +42,7 @@ type GlobalPtr = *libc::uintptr_t;
* or, if no channel exists creates and installs a new channel and sets up a
* new task to receive from it.
*/
unsafe fn chan_from_global_ptr<T: Send>(
pub unsafe fn chan_from_global_ptr<T: Send>(
global: GlobalPtr,
task_fn: fn() -> task::TaskBuilder,
+f: fn~(comm::Port<T>)
@ -110,13 +103,13 @@ unsafe fn chan_from_global_ptr<T: Send>(
}
#[test]
fn test_from_global_chan1() {
pub fn test_from_global_chan1() {
// This is unreadable, right?
// The global channel
let globchan = 0u;
let globchanp = ptr::addr_of(globchan);
let globchan = 0;
let globchanp = ptr::p2::addr_of(&globchan);
// Create the global channel, attached to a new task
let ch = unsafe {
@ -147,25 +140,25 @@ fn test_from_global_chan1() {
}
#[test]
fn test_from_global_chan2() {
pub fn test_from_global_chan2() {
for iter::repeat(100u) {
for iter::repeat(100) {
// The global channel
let globchan = 0u;
let globchanp = ptr::addr_of(globchan);
let globchan = 0;
let globchanp = ptr::p2::addr_of(&globchan);
let resultpo = comm::Port();
let resultch = comm::Chan(resultpo);
// Spawn a bunch of tasks that all want to compete to
// create the global channel
for uint::range(0u, 10u) |i| {
for uint::range(0, 10) |i| {
do task::spawn {
let ch = unsafe {
do chan_from_global_ptr(
globchanp, task::task) |po| {
for uint::range(0u, 10u) |_j| {
for uint::range(0, 10) |_j| {
let ch = comm::recv(po);
comm::send(ch, {i});
}
@ -208,7 +201,7 @@ fn test_from_global_chan2() {
* * Weak tasks must not be supervised. A supervised task keeps
* a reference to its parent, so the parent will not die.
*/
unsafe fn weaken_task(f: fn(comm::Port<()>)) {
pub unsafe fn weaken_task(f: fn(comm::Port<()>)) {
let po = comm::Port();
let ch = comm::Chan(po);
unsafe {
@ -232,7 +225,7 @@ unsafe fn weaken_task(f: fn(comm::Port<()>)) {
}
#[test]
fn test_weaken_task_then_unweaken() {
pub fn test_weaken_task_then_unweaken() {
do task::try {
unsafe {
do weaken_task |_po| {
@ -242,7 +235,7 @@ fn test_weaken_task_then_unweaken() {
}
#[test]
fn test_weaken_task_wait() {
pub fn test_weaken_task_wait() {
do task::spawn_unlinked {
unsafe {
do weaken_task |po| {
@ -253,7 +246,7 @@ fn test_weaken_task_wait() {
}
#[test]
fn test_weaken_task_stress() {
pub fn test_weaken_task_stress() {
// Create a bunch of weak tasks
for iter::repeat(100u) {
do task::spawn {
@ -275,7 +268,7 @@ fn test_weaken_task_stress() {
#[test]
#[ignore(cfg(windows))]
fn test_weaken_task_fail() {
pub fn test_weaken_task_fail() {
let res = do task::try {
unsafe {
do weaken_task |_po| {
@ -283,7 +276,7 @@ fn test_weaken_task_fail() {
}
}
};
assert result::is_err(res);
assert result::is_err(&res);
}
/****************************************************************************
@ -347,7 +340,7 @@ fn ArcDestruct<T>(data: *libc::c_void) -> ArcDestruct<T> {
}
}
unsafe fn unwrap_shared_mutable_state<T: Send>(+rc: SharedMutableState<T>)
pub unsafe fn unwrap_shared_mutable_state<T: Send>(rc: SharedMutableState<T>)
-> T {
struct DeathThroes<T> {
mut ptr: Option<~ArcData<T>>,
@ -418,9 +411,10 @@ unsafe fn unwrap_shared_mutable_state<T: Send>(+rc: SharedMutableState<T>)
* Data races between tasks can result in crashes and, with sufficient
* cleverness, arbitrary type coercion.
*/
type SharedMutableState<T: Send> = ArcDestruct<T>;
pub type SharedMutableState<T: Send> = ArcDestruct<T>;
unsafe fn shared_mutable_state<T: Send>(+data: T) -> SharedMutableState<T> {
pub unsafe fn shared_mutable_state<T: Send>(data: T) ->
SharedMutableState<T> {
let data = ~ArcData { count: 1, unwrapper: 0, data: Some(move data) };
unsafe {
let ptr = cast::transmute(move data);
@ -429,7 +423,7 @@ unsafe fn shared_mutable_state<T: Send>(+data: T) -> SharedMutableState<T> {
}
#[inline(always)]
unsafe fn get_shared_mutable_state<T: Send>(rc: &a/SharedMutableState<T>)
pub unsafe fn get_shared_mutable_state<T: Send>(rc: &a/SharedMutableState<T>)
-> &a/mut T {
unsafe {
let ptr: ~ArcData<T> = cast::reinterpret_cast(&(*rc).data);
@ -441,8 +435,8 @@ unsafe fn get_shared_mutable_state<T: Send>(rc: &a/SharedMutableState<T>)
}
}
#[inline(always)]
unsafe fn get_shared_immutable_state<T: Send>(rc: &a/SharedMutableState<T>)
-> &a/T {
pub unsafe fn get_shared_immutable_state<T: Send>(
rc: &a/SharedMutableState<T>) -> &a/T {
unsafe {
let ptr: ~ArcData<T> = cast::reinterpret_cast(&(*rc).data);
assert ptr.count > 0;
@ -453,7 +447,7 @@ unsafe fn get_shared_immutable_state<T: Send>(rc: &a/SharedMutableState<T>)
}
}
unsafe fn clone_shared_mutable_state<T: Send>(rc: &SharedMutableState<T>)
pub unsafe fn clone_shared_mutable_state<T: Send>(rc: &SharedMutableState<T>)
-> SharedMutableState<T> {
unsafe {
let ptr: ~ArcData<T> = cast::reinterpret_cast(&(*rc).data);
@ -506,9 +500,9 @@ struct ExData<T: Send> { lock: LittleLock, mut failed: bool, mut data: T, }
/**
* An arc over mutable data that is protected by a lock. For library use only.
*/
struct Exclusive<T: Send> { x: SharedMutableState<ExData<T>> }
pub struct Exclusive<T: Send> { x: SharedMutableState<ExData<T>> }
fn exclusive<T:Send >(+user_data: T) -> Exclusive<T> {
pub fn exclusive<T:Send >(user_data: T) -> Exclusive<T> {
let data = ExData {
lock: LittleLock(), mut failed: false, mut data: user_data
};
@ -550,7 +544,7 @@ impl<T: Send> Exclusive<T> {
}
// FIXME(#2585) make this a by-move method on the exclusive
fn unwrap_exclusive<T: Send>(+arc: Exclusive<T>) -> T {
pub fn unwrap_exclusive<T: Send>(arc: Exclusive<T>) -> T {
let Exclusive { x: x } <- arc;
let inner = unsafe { unwrap_shared_mutable_state(move x) };
let ExData { data: data, _ } <- inner;
@ -558,11 +552,9 @@ fn unwrap_exclusive<T: Send>(+arc: Exclusive<T>) -> T {
}
#[cfg(test)]
mod tests {
#[legacy_exports];
pub mod tests {
#[test]
fn exclusive_arc() {
pub fn exclusive_arc() {
let mut futures = ~[];
let num_tasks = 10u;
@ -572,7 +564,7 @@ mod tests {
for uint::range(0u, num_tasks) |_i| {
let total = total.clone();
vec::push(futures, future::spawn(|| {
futures.push(future::spawn(|| {
for uint::range(0u, count) |_i| {
do total.with |count| {
**count += 1u;
@ -589,7 +581,7 @@ mod tests {
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn exclusive_poison() {
pub fn exclusive_poison() {
// Tests that if one task fails inside of an exclusive, subsequent
// accesses will also fail.
let x = exclusive(1);
@ -605,13 +597,13 @@ mod tests {
}
#[test]
fn exclusive_unwrap_basic() {
pub fn exclusive_unwrap_basic() {
let x = exclusive(~~"hello");
assert unwrap_exclusive(x) == ~~"hello";
}
#[test]
fn exclusive_unwrap_contended() {
pub fn exclusive_unwrap_contended() {
let x = exclusive(~~"hello");
let x2 = ~mut Some(x.clone());
do task::spawn {
@ -636,7 +628,7 @@ mod tests {
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn exclusive_unwrap_conflict() {
pub fn exclusive_unwrap_conflict() {
let x = exclusive(~~"hello");
let x2 = ~mut Some(x.clone());
let mut res = None;
@ -650,7 +642,7 @@ mod tests {
}
#[test] #[ignore(cfg(windows))]
fn exclusive_unwrap_deadlock() {
pub fn exclusive_unwrap_deadlock() {
// This is not guaranteed to get to the deadlock before being killed,
// but it will show up sometimes, and if the deadlock were not there,
// the test would nondeterministically fail.

View file

@ -1,33 +1,11 @@
//! Unsafe pointer utility functions
export addr_of;
export to_unsafe_ptr;
export to_const_unsafe_ptr;
export to_mut_unsafe_ptr;
export mut_addr_of;
export offset;
export const_offset;
export mut_offset;
export null;
export mut_null;
export is_null;
export is_not_null;
export memcpy;
export memmove;
export memset;
export to_uint;
export ref_eq;
export buf_len;
export position;
export Ptr;
use cmp::{Eq, Ord};
use libc::{c_void, size_t};
#[nolink]
#[abi = "cdecl"]
extern mod libc_ {
#[legacy_exports];
#[rust_stack]
fn memcpy(dest: *mut c_void, src: *const c_void,
n: libc::size_t) -> *c_void;
@ -43,25 +21,30 @@ extern mod libc_ {
#[abi = "rust-intrinsic"]
extern mod rusti {
#[legacy_exports];
fn addr_of<T>(val: T) -> *T;
fn addr_of<T>(&&val: T) -> *T;
}
/// Get an unsafe pointer to a value
#[inline(always)]
pure fn addr_of<T>(val: T) -> *T { unsafe { rusti::addr_of(val) } }
pub pure fn addr_of<T>(val: &T) -> *T { unsafe { rusti::addr_of(*val) } }
pub mod p2 {
/// Get an unsafe pointer to a value
#[inline(always)]
pub pure fn addr_of<T>(val: &T) -> *T { unsafe { rusti::addr_of(*val) } }
}
/// Get an unsafe mut pointer to a value
#[inline(always)]
pure fn mut_addr_of<T>(val: T) -> *mut T {
pub pure fn mut_addr_of<T>(val: &T) -> *mut T {
unsafe {
cast::reinterpret_cast(&rusti::addr_of(val))
cast::reinterpret_cast(&rusti::addr_of(*val))
}
}
/// Calculate the offset from a pointer
#[inline(always)]
fn offset<T>(ptr: *T, count: uint) -> *T {
pub pure fn offset<T>(ptr: *T, count: uint) -> *T {
unsafe {
(ptr as uint + count * sys::size_of::<T>()) as *T
}
@ -69,7 +52,7 @@ fn offset<T>(ptr: *T, count: uint) -> *T {
/// Calculate the offset from a const pointer
#[inline(always)]
fn const_offset<T>(ptr: *const T, count: uint) -> *const T {
pub pure fn const_offset<T>(ptr: *const T, count: uint) -> *const T {
unsafe {
(ptr as uint + count * sys::size_of::<T>()) as *T
}
@ -77,39 +60,39 @@ fn const_offset<T>(ptr: *const T, count: uint) -> *const T {
/// Calculate the offset from a mut pointer
#[inline(always)]
fn mut_offset<T>(ptr: *mut T, count: uint) -> *mut T {
pub pure fn mut_offset<T>(ptr: *mut T, count: uint) -> *mut T {
(ptr as uint + count * sys::size_of::<T>()) as *mut T
}
/// Return the offset of the first null pointer in `buf`.
#[inline(always)]
unsafe fn buf_len<T>(buf: **T) -> uint {
position(buf, |i| i == null())
pub unsafe fn buf_len<T>(buf: **T) -> uint {
position(buf, |i| *i == null())
}
/// Return the first offset `i` such that `f(buf[i]) == true`.
#[inline(always)]
unsafe fn position<T>(buf: *T, f: fn(T) -> bool) -> uint {
let mut i = 0u;
pub unsafe fn position<T>(buf: *T, f: fn(&T) -> bool) -> uint {
let mut i = 0;
loop {
if f(*offset(buf, i)) { return i; }
else { i += 1u; }
if f(&(*offset(buf, i))) { return i; }
else { i += 1; }
}
}
/// Create an unsafe null pointer
#[inline(always)]
pure fn null<T>() -> *T { unsafe { cast::reinterpret_cast(&0u) } }
pub pure fn null<T>() -> *T { unsafe { cast::reinterpret_cast(&0u) } }
/// Create an unsafe mutable null pointer
#[inline(always)]
pure fn mut_null<T>() -> *mut T { unsafe { cast::reinterpret_cast(&0u) } }
pub pure fn mut_null<T>() -> *mut T { unsafe { cast::reinterpret_cast(&0u) } }
/// Returns true if the pointer is equal to the null pointer.
pure fn is_null<T>(ptr: *const T) -> bool { ptr == null() }
pub pure fn is_null<T>(ptr: *const T) -> bool { ptr == null() }
/// Returns true if the pointer is not equal to the null pointer.
pure fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }
pub pure fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }
/**
* Copies data from one location to another
@ -118,7 +101,7 @@ pure fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }
* and destination may not overlap.
*/
#[inline(always)]
unsafe fn memcpy<T>(dst: *mut T, src: *const T, count: uint) {
pub unsafe fn memcpy<T>(dst: *mut T, src: *const T, count: uint) {
let n = count * sys::size_of::<T>();
libc_::memcpy(dst as *mut c_void, src as *c_void, n as size_t);
}
@ -130,13 +113,13 @@ unsafe fn memcpy<T>(dst: *mut T, src: *const T, count: uint) {
* and destination may overlap.
*/
#[inline(always)]
unsafe fn memmove<T>(dst: *mut T, src: *const T, count: uint) {
pub unsafe fn memmove<T>(dst: *mut T, src: *const T, count: uint) {
let n = count * sys::size_of::<T>();
libc_::memmove(dst as *mut c_void, src as *c_void, n as size_t);
}
#[inline(always)]
unsafe fn memset<T>(dst: *mut T, c: int, count: uint) {
pub unsafe fn memset<T>(dst: *mut T, c: int, count: uint) {
let n = count * sys::size_of::<T>();
libc_::memset(dst as *mut c_void, c as libc::c_int, n as size_t);
}
@ -148,7 +131,7 @@ unsafe fn memset<T>(dst: *mut T, c: int, count: uint) {
reinterpret_cast.
*/
#[inline(always)]
fn to_unsafe_ptr<T>(thing: &T) -> *T {
pub pure fn to_unsafe_ptr<T>(thing: &T) -> *T {
unsafe { cast::reinterpret_cast(&thing) }
}
@ -158,7 +141,7 @@ fn to_unsafe_ptr<T>(thing: &T) -> *T {
reinterpret_cast.
*/
#[inline(always)]
fn to_const_unsafe_ptr<T>(thing: &const T) -> *const T {
pub pure fn to_const_unsafe_ptr<T>(thing: &const T) -> *const T {
unsafe { cast::reinterpret_cast(&thing) }
}
@ -168,7 +151,7 @@ fn to_const_unsafe_ptr<T>(thing: &const T) -> *const T {
reinterpret_cast.
*/
#[inline(always)]
fn to_mut_unsafe_ptr<T>(thing: &mut T) -> *mut T {
pub pure fn to_mut_unsafe_ptr<T>(thing: &mut T) -> *mut T {
unsafe { cast::reinterpret_cast(&thing) }
}
@ -180,28 +163,35 @@ fn to_mut_unsafe_ptr<T>(thing: &mut T) -> *mut T {
(I couldn't think of a cutesy name for this one.)
*/
#[inline(always)]
fn to_uint<T>(thing: &T) -> uint unsafe {
pub fn to_uint<T>(thing: &T) -> uint unsafe {
cast::reinterpret_cast(&thing)
}
/// Determine if two borrowed pointers point to the same thing.
#[inline(always)]
fn ref_eq<T>(thing: &a/T, other: &b/T) -> bool {
pub fn ref_eq<T>(thing: &a/T, other: &b/T) -> bool {
to_uint(thing) == to_uint(other)
}
trait Ptr {
pub trait Ptr<T> {
pure fn is_null() -> bool;
pure fn is_not_null() -> bool;
pure fn offset(count: uint) -> self;
}
/// Extension methods for pointers
impl<T> *T: Ptr {
impl<T> *T: Ptr<T> {
/// Returns true if the pointer is equal to the null pointer.
#[inline(always)]
pure fn is_null() -> bool { is_null(self) }
/// Returns true if the pointer is not equal to the null pointer.
#[inline(always)]
pure fn is_not_null() -> bool { is_not_null(self) }
/// Calculates the offset from a pointer.
#[inline(always)]
pure fn offset(count: uint) -> *T { offset(self, count) }
}
// Equality for pointers
@ -253,11 +243,11 @@ impl<T:Ord> &const T : Ord {
}
#[test]
fn test() {
pub fn test() {
unsafe {
type Pair = {mut fst: int, mut snd: int};
let p = {mut fst: 10, mut snd: 20};
let pptr: *mut Pair = mut_addr_of(p);
let pptr: *mut Pair = mut_addr_of(&p);
let iptr: *mut int = cast::reinterpret_cast(&pptr);
assert (*iptr == 10);;
*iptr = 30;
@ -285,20 +275,20 @@ fn test() {
}
#[test]
fn test_position() {
pub fn test_position() {
use str::as_c_str;
use libc::c_char;
let s = ~"hello";
unsafe {
assert 2u == as_c_str(s, |p| position(p, |c| c == 'l' as c_char));
assert 4u == as_c_str(s, |p| position(p, |c| c == 'o' as c_char));
assert 5u == as_c_str(s, |p| position(p, |c| c == 0 as c_char));
assert 2u == as_c_str(s, |p| position(p, |c| *c == 'l' as c_char));
assert 4u == as_c_str(s, |p| position(p, |c| *c == 'o' as c_char));
assert 5u == as_c_str(s, |p| position(p, |c| *c == 0 as c_char));
}
}
#[test]
fn test_buf_len() {
pub fn test_buf_len() {
let s0 = ~"hello";
let s1 = ~"there";
let s2 = ~"thing";
@ -316,7 +306,7 @@ fn test_buf_len() {
}
#[test]
fn test_is_null() {
pub fn test_is_null() {
let p: *int = ptr::null();
assert p.is_null();
assert !p.is_not_null();

View file

@ -1,29 +1,29 @@
//! Random number generation
export Rng, seed, seeded_rng, Weighted, extensions;
export xorshift, seeded_xorshift;
// NB: transitional, de-mode-ing.
#[warn(deprecated_mode)];
#[forbid(deprecated_pattern)];
#[allow(non_camel_case_types)] // runtime type
enum rctx {}
#[abi = "cdecl"]
extern mod rustrt {
#[legacy_exports];
fn rand_seed() -> ~[u8];
fn rand_new() -> *rctx;
fn rand_new_seeded(seed: ~[u8]) -> *rctx;
fn rand_new_seeded2(&&seed: ~[u8]) -> *rctx;
fn rand_next(c: *rctx) -> u32;
fn rand_free(c: *rctx);
}
/// A random number generator
trait Rng {
pub trait Rng {
/// Return the next random integer
fn next() -> u32;
}
/// A value with a particular weight compared to other values
type Weighted<T> = { weight: uint, item: T };
pub type Weighted<T> = { weight: uint, item: T };
/// Extension methods for random number generators
impl Rng {
@ -123,7 +123,7 @@ impl Rng {
/**
* Return a char randomly chosen from chars, failing if chars is empty
*/
fn gen_char_from(chars: ~str) -> char {
fn gen_char_from(chars: &str) -> char {
assert !chars.is_empty();
self.choose(str::chars(chars))
}
@ -218,7 +218,7 @@ impl Rng {
let mut r = ~[];
for v.each |item| {
for uint::range(0u, item.weight) |_i| {
vec::push(r, item.item);
r.push(item.item);
}
}
move r
@ -260,12 +260,12 @@ impl @RandRes: Rng {
}
/// Create a new random seed for seeded_rng
fn seed() -> ~[u8] {
pub fn seed() -> ~[u8] {
rustrt::rand_seed()
}
/// Create a random number generator with a system specified seed
fn Rng() -> Rng {
pub fn Rng() -> Rng {
@RandRes(rustrt::rand_new()) as Rng
}
@ -275,8 +275,8 @@ fn Rng() -> Rng {
* all other generators constructed with the same seed. The seed may be any
* length.
*/
fn seeded_rng(seed: ~[u8]) -> Rng {
@RandRes(rustrt::rand_new_seeded(seed)) as Rng
pub fn seeded_rng(seed: &~[u8]) -> Rng {
@RandRes(rustrt::rand_new_seeded2(*seed)) as Rng
}
type XorShiftState = {
@ -299,40 +299,72 @@ impl XorShiftState: Rng {
}
}
fn xorshift() -> Rng {
pub fn xorshift() -> Rng {
// constants taken from http://en.wikipedia.org/wiki/Xorshift
seeded_xorshift(123456789u32, 362436069u32, 521288629u32, 88675123u32)
}
fn seeded_xorshift(x: u32, y: u32, z: u32, w: u32) -> Rng {
pub fn seeded_xorshift(x: u32, y: u32, z: u32, w: u32) -> Rng {
{mut x: x, mut y: y, mut z: z, mut w: w} as Rng
}
#[cfg(test)]
mod tests {
#[legacy_exports];
// used to make space in TLS for a random number generator
fn tls_rng_state(+_v: @RandRes) {}
/**
* Gives back a lazily initialized task-local random number generator,
* seeded by the system. Intended to be used in method chaining style, ie
* task_rng().gen_int().
*/
pub fn task_rng() -> Rng {
let r : Option<@RandRes>;
unsafe {
r = task::local_data::local_data_get(tls_rng_state);
}
match r {
None => {
let rng = @RandRes(rustrt::rand_new());
unsafe {
task::local_data::local_data_set(tls_rng_state, rng);
}
rng as Rng
}
Some(rng) => rng as Rng
}
}
/**
* Returns a random uint, using the task's based random number generator.
*/
pub fn random() -> uint {
task_rng().gen_uint()
}
#[cfg(test)]
pub mod tests {
#[test]
fn rng_seeded() {
pub fn rng_seeded() {
let seed = rand::seed();
let ra = rand::seeded_rng(seed);
let rb = rand::seeded_rng(seed);
let ra = rand::seeded_rng(&seed);
let rb = rand::seeded_rng(&seed);
assert ra.gen_str(100u) == rb.gen_str(100u);
}
#[test]
fn rng_seeded_custom_seed() {
pub fn rng_seeded_custom_seed() {
// much shorter than generated seeds which are 1024 bytes
let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
let ra = rand::seeded_rng(seed);
let rb = rand::seeded_rng(seed);
let ra = rand::seeded_rng(&seed);
let rb = rand::seeded_rng(&seed);
assert ra.gen_str(100u) == rb.gen_str(100u);
}
#[test]
fn rng_seeded_custom_seed2() {
pub fn rng_seeded_custom_seed2() {
let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
let ra = rand::seeded_rng(seed);
let ra = rand::seeded_rng(&seed);
// Regression test that isaac is actually using the above vector
let r = ra.next();
error!("%?", r);
@ -341,7 +373,7 @@ mod tests {
}
#[test]
fn gen_int_range() {
pub fn gen_int_range() {
let r = rand::Rng();
let a = r.gen_int_range(-3, 42);
assert a >= -3 && a < 42;
@ -352,12 +384,12 @@ mod tests {
#[test]
#[should_fail]
#[ignore(cfg(windows))]
fn gen_int_from_fail() {
pub fn gen_int_from_fail() {
rand::Rng().gen_int_range(5, -2);
}
#[test]
fn gen_uint_range() {
pub fn gen_uint_range() {
let r = rand::Rng();
let a = r.gen_uint_range(3u, 42u);
assert a >= 3u && a < 42u;
@ -368,12 +400,12 @@ mod tests {
#[test]
#[should_fail]
#[ignore(cfg(windows))]
fn gen_uint_range_fail() {
pub fn gen_uint_range_fail() {
rand::Rng().gen_uint_range(5u, 2u);
}
#[test]
fn gen_float() {
pub fn gen_float() {
let r = rand::Rng();
let a = r.gen_float();
let b = r.gen_float();
@ -381,14 +413,14 @@ mod tests {
}
#[test]
fn gen_weighted_bool() {
pub fn gen_weighted_bool() {
let r = rand::Rng();
assert r.gen_weighted_bool(0u) == true;
assert r.gen_weighted_bool(1u) == true;
}
#[test]
fn gen_str() {
pub fn gen_str() {
let r = rand::Rng();
log(debug, r.gen_str(10u));
log(debug, r.gen_str(10u));
@ -399,7 +431,7 @@ mod tests {
}
#[test]
fn gen_bytes() {
pub fn gen_bytes() {
let r = rand::Rng();
assert r.gen_bytes(0u).len() == 0u;
assert r.gen_bytes(10u).len() == 10u;
@ -407,13 +439,13 @@ mod tests {
}
#[test]
fn choose() {
pub fn choose() {
let r = rand::Rng();
assert r.choose([1, 1, 1]) == 1;
}
#[test]
fn choose_option() {
pub fn choose_option() {
let r = rand::Rng();
let x: Option<int> = r.choose_option([]);
assert x.is_none();
@ -421,7 +453,7 @@ mod tests {
}
#[test]
fn choose_weighted() {
pub fn choose_weighted() {
let r = rand::Rng();
assert r.choose_weighted(~[{weight: 1u, item: 42}]) == 42;
assert r.choose_weighted(~[
@ -431,7 +463,7 @@ mod tests {
}
#[test]
fn choose_weighted_option() {
pub fn choose_weighted_option() {
let r = rand::Rng();
assert r.choose_weighted_option(~[{weight: 1u, item: 42}]) ==
Some(42);
@ -444,7 +476,7 @@ mod tests {
}
#[test]
fn weighted_vec() {
pub fn weighted_vec() {
let r = rand::Rng();
let empty: ~[int] = ~[];
assert r.weighted_vec(~[]) == empty;
@ -456,12 +488,26 @@ mod tests {
}
#[test]
fn shuffle() {
pub fn shuffle() {
let r = rand::Rng();
let empty: ~[int] = ~[];
assert r.shuffle(~[]) == empty;
assert r.shuffle(~[1, 1, 1]) == ~[1, 1, 1];
}
#[test]
pub fn task_rng() {
let r = rand::task_rng();
r.gen_int();
assert r.shuffle(~[1, 1, 1]) == ~[1, 1, 1];
assert r.gen_uint_range(0u, 1u) == 0u;
}
#[test]
pub fn random() {
// not sure how to test this aside from just getting a number
let _n : uint = rand::random();
}
}

View file

@ -13,7 +13,7 @@ use libc::c_void;
* data structure, and implement both `MovePtr` for it as well as `TyVisitor`;
* then build a MovePtrAdaptor wrapped around your struct.
*/
trait MovePtr {
pub trait MovePtr {
fn move_ptr(adjustment: fn(*c_void) -> *c_void);
}
@ -27,7 +27,7 @@ fn align(size: uint, align: uint) -> uint {
struct MovePtrAdaptor<V: TyVisitor MovePtr> {
inner: V
}
pub fn MovePtrAdaptor<V: TyVisitor MovePtr>(+v: V) -> MovePtrAdaptor<V> {
pub fn MovePtrAdaptor<V: TyVisitor MovePtr>(v: V) -> MovePtrAdaptor<V> {
MovePtrAdaptor { inner: move v }
}

View file

@ -13,7 +13,8 @@ use cast::transmute;
use intrinsic::{TyDesc, TyVisitor, visit_tydesc};
use reflect::{MovePtr, MovePtrAdaptor};
use vec::raw::{VecRepr, UnboxedVecRepr, SliceRepr};
use box::raw::{BoxRepr, BoxHeaderRepr};
pub use box::raw::BoxRepr;
use box::raw::BoxHeaderRepr;
/// Helpers

View file

@ -1,10 +1,14 @@
//! A type representing either success or failure
// NB: transitionary, de-mode-ing.
// tjc: re-forbid deprecated modes after snapshot
#[forbid(deprecated_pattern)];
use cmp::Eq;
use either::Either;
/// The result type
enum Result<T, U> {
pub enum Result<T, U> {
/// Contains the successful result value
Ok(T),
/// Contains the error value
@ -18,11 +22,11 @@ enum Result<T, U> {
*
* If the result is an error
*/
pure fn get<T: Copy, U>(res: Result<T, U>) -> T {
match res {
Ok(t) => t,
Err(the_err) => unsafe {
fail fmt!("get called on error result: %?", the_err)
pub pure fn get<T: Copy, U>(res: &Result<T, U>) -> T {
match *res {
Ok(copy t) => t,
Err(ref the_err) => unsafe {
fail fmt!("get called on error result: %?", *the_err)
}
}
}
@ -34,11 +38,11 @@ pure fn get<T: Copy, U>(res: Result<T, U>) -> T {
*
* If the result is an error
*/
pure fn get_ref<T, U>(res: &a/Result<T, U>) -> &a/T {
pub pure fn get_ref<T, U>(res: &a/Result<T, U>) -> &a/T {
match *res {
Ok(ref t) => t,
Err(ref the_err) => unsafe {
fail fmt!("get_ref called on error result: %?", the_err)
fail fmt!("get_ref called on error result: %?", *the_err)
}
}
}
@ -50,23 +54,23 @@ pure fn get_ref<T, U>(res: &a/Result<T, U>) -> &a/T {
*
* If the result is not an error
*/
pure fn get_err<T, U: Copy>(res: Result<T, U>) -> U {
match res {
Err(u) => u,
pub pure fn get_err<T, U: Copy>(res: &Result<T, U>) -> U {
match *res {
Err(copy u) => u,
Ok(_) => fail ~"get_err called on ok result"
}
}
/// Returns true if the result is `ok`
pure fn is_ok<T, U>(res: Result<T, U>) -> bool {
match res {
pub pure fn is_ok<T, U>(res: &Result<T, U>) -> bool {
match *res {
Ok(_) => true,
Err(_) => false
}
}
/// Returns true if the result is `err`
pure fn is_err<T, U>(res: Result<T, U>) -> bool {
pub pure fn is_err<T, U>(res: &Result<T, U>) -> bool {
!is_ok(res)
}
@ -76,10 +80,11 @@ pure fn is_err<T, U>(res: Result<T, U>) -> bool {
* `ok` result variants are converted to `either::right` variants, `err`
* result variants are converted to `either::left`.
*/
pure fn to_either<T: Copy, U: Copy>(res: Result<U, T>) -> Either<T, U> {
match res {
Ok(res) => either::Right(res),
Err(fail_) => either::Left(fail_)
pub pure fn to_either<T: Copy, U: Copy>(res: &Result<U, T>)
-> Either<T, U> {
match *res {
Ok(copy res) => either::Right(res),
Err(copy fail_) => either::Left(fail_)
}
}
@ -97,11 +102,13 @@ pure fn to_either<T: Copy, U: Copy>(res: Result<U, T>) -> Either<T, U> {
* ok(parse_bytes(buf))
* }
*/
fn chain<T, U: Copy, V: Copy>(res: Result<T, V>, op: fn(T) -> Result<U, V>)
-> Result<U, V> {
match res {
Ok(t) => op(t),
Err(e) => Err(e)
pub fn chain<T, U: Copy, V: Copy>(res: Result<T, V>, op: fn(t: T)
-> Result<U, V>) -> Result<U, V> {
// XXX: Should be writable with move + match
if res.is_ok() {
op(unwrap(res))
} else {
Err(unwrap_err(res))
}
}
@ -113,13 +120,13 @@ fn chain<T, U: Copy, V: Copy>(res: Result<T, V>, op: fn(T) -> Result<U, V>)
* immediately returned. This function can be used to pass through a
* successful result while handling an error.
*/
fn chain_err<T: Copy, U: Copy, V: Copy>(
pub fn chain_err<T: Copy, U: Copy, V: Copy>(
res: Result<T, V>,
op: fn(V) -> Result<T, U>)
op: fn(t: V) -> Result<T, U>)
-> Result<T, U> {
match res {
Ok(t) => Ok(t),
Err(v) => op(v)
match move res {
Ok(move t) => Ok(t),
Err(move v) => op(v)
}
}
@ -137,9 +144,9 @@ fn chain_err<T: Copy, U: Copy, V: Copy>(
* print_buf(buf)
* }
*/
fn iter<T, E>(res: Result<T, E>, f: fn(T)) {
match res {
Ok(t) => f(t),
pub fn iter<T, E>(res: &Result<T, E>, f: fn((&T))) {
match *res {
Ok(ref t) => f(t),
Err(_) => ()
}
}
@ -152,10 +159,10 @@ fn iter<T, E>(res: Result<T, E>, f: fn(T)) {
* This function can be used to pass through a successful result while
* handling an error.
*/
fn iter_err<T, E>(res: Result<T, E>, f: fn(E)) {
match res {
pub fn iter_err<T, E>(res: &Result<T, E>, f: fn((&E))) {
match *res {
Ok(_) => (),
Err(e) => f(e)
Err(ref e) => f(e)
}
}
@ -173,11 +180,11 @@ fn iter_err<T, E>(res: Result<T, E>, f: fn(E)) {
* parse_bytes(buf)
* }
*/
fn map<T, E: Copy, U: Copy>(res: Result<T, E>, op: fn(T) -> U)
pub fn map<T, E: Copy, U: Copy>(res: &Result<T, E>, op: fn((&T)) -> U)
-> Result<U, E> {
match res {
Ok(t) => Ok(op(t)),
Err(e) => Err(e)
match *res {
Ok(ref t) => Ok(op(t)),
Err(copy e) => Err(e)
}
}
@ -189,63 +196,65 @@ fn map<T, E: Copy, U: Copy>(res: Result<T, E>, op: fn(T) -> U)
* is immediately returned. This function can be used to pass through a
* successful result while handling an error.
*/
fn map_err<T: Copy, E, F: Copy>(res: Result<T, E>, op: fn(E) -> F)
pub fn map_err<T: Copy, E, F: Copy>(res: &Result<T, E>, op: fn((&E)) -> F)
-> Result<T, F> {
match res {
Ok(t) => Ok(t),
Err(e) => Err(op(e))
match *res {
Ok(copy t) => Ok(t),
Err(ref e) => Err(op(e))
}
}
impl<T, E> Result<T, E> {
fn is_ok() -> bool { is_ok(self) }
fn is_ok() -> bool { is_ok(&self) }
fn is_err() -> bool { is_err(self) }
fn is_err() -> bool { is_err(&self) }
fn iter(f: fn(T)) {
fn iter(f: fn((&T))) {
match self {
Ok(t) => f(t),
Ok(ref t) => f(t),
Err(_) => ()
}
}
fn iter_err(f: fn(E)) {
fn iter_err(f: fn((&E))) {
match self {
Ok(_) => (),
Err(e) => f(e)
Err(ref e) => f(e)
}
}
}
impl<T: Copy, E> Result<T, E> {
fn get() -> T { get(self) }
fn get() -> T { get(&self) }
fn map_err<F:Copy>(op: fn(E) -> F) -> Result<T,F> {
fn map_err<F:Copy>(op: fn((&E)) -> F) -> Result<T,F> {
match self {
Ok(t) => Ok(t),
Err(e) => Err(op(e))
Ok(copy t) => Ok(t),
Err(ref e) => Err(op(e))
}
}
}
impl<T, E: Copy> Result<T, E> {
fn get_err() -> E { get_err(self) }
fn get_err() -> E { get_err(&self) }
fn map<U:Copy>(op: fn(T) -> U) -> Result<U,E> {
fn map<U:Copy>(op: fn((&T)) -> U) -> Result<U,E> {
match self {
Ok(t) => Ok(op(t)),
Err(e) => Err(e)
Ok(ref t) => Ok(op(t)),
Err(copy e) => Err(e)
}
}
}
impl<T: Copy, E: Copy> Result<T, E> {
fn chain<U:Copy>(op: fn(T) -> Result<U,E>) -> Result<U,E> {
chain(self, op)
fn chain<U:Copy>(op: fn(t: T) -> Result<U,E>) -> Result<U,E> {
// XXX: Bad copy
chain(copy self, op)
}
fn chain_err<F:Copy>(op: fn(E) -> Result<T,F>) -> Result<T,F> {
chain_err(self, op)
fn chain_err<F:Copy>(op: fn(t: E) -> Result<T,F>) -> Result<T,F> {
// XXX: Bad copy
chain_err(copy self, op)
}
}
@ -266,27 +275,27 @@ impl<T: Copy, E: Copy> Result<T, E> {
* assert incd == ~[2u, 3u, 4u];
* }
*/
fn map_vec<T,U:Copy,V:Copy>(
pub fn map_vec<T,U:Copy,V:Copy>(
ts: &[T], op: fn((&T)) -> Result<V,U>) -> Result<~[V],U> {
let mut vs: ~[V] = vec::with_capacity(vec::len(ts));
for vec::each(ts) |t| {
match op(t) {
Ok(v) => vec::push(vs, v),
Err(u) => return Err(u)
Ok(copy v) => vs.push(v),
Err(copy u) => return Err(u)
}
}
return Ok(move vs);
}
fn map_opt<T,U:Copy,V:Copy>(
o_t: Option<T>, op: fn(T) -> Result<V,U>) -> Result<Option<V>,U> {
pub fn map_opt<T,U:Copy,V:Copy>(
o_t: &Option<T>, op: fn((&T)) -> Result<V,U>) -> Result<Option<V>,U> {
match o_t {
match *o_t {
None => Ok(None),
Some(t) => match op(t) {
Ok(v) => Ok(Some(v)),
Err(e) => Err(e)
Some(ref t) => match op(t) {
Ok(copy v) => Ok(Some(v)),
Err(copy e) => Err(e)
}
}
}
@ -300,17 +309,17 @@ fn map_opt<T,U:Copy,V:Copy>(
* used in 'careful' code contexts where it is both appropriate and easy
* to accommodate an error like the vectors being of different lengths.
*/
fn map_vec2<S,T,U:Copy,V:Copy>(ss: &[S], ts: &[T],
op: fn(S,T) -> Result<V,U>) -> Result<~[V],U> {
pub fn map_vec2<S,T,U:Copy,V:Copy>(ss: &[S], ts: &[T],
op: fn((&S),(&T)) -> Result<V,U>) -> Result<~[V],U> {
assert vec::same_length(ss, ts);
let n = vec::len(ts);
let mut vs = vec::with_capacity(n);
let mut i = 0u;
while i < n {
match op(ss[i],ts[i]) {
Ok(v) => vec::push(vs, v),
Err(u) => return Err(u)
match op(&ss[i],&ts[i]) {
Ok(copy v) => vs.push(v),
Err(copy u) => return Err(u)
}
i += 1u;
}
@ -322,16 +331,16 @@ fn map_vec2<S,T,U:Copy,V:Copy>(ss: &[S], ts: &[T],
* error. This could be implemented using `map2()` but it is more efficient
* on its own as no result vector is built.
*/
fn iter_vec2<S,T,U:Copy>(ss: &[S], ts: &[T],
op: fn(S,T) -> Result<(),U>) -> Result<(),U> {
pub fn iter_vec2<S,T,U:Copy>(ss: &[S], ts: &[T],
op: fn((&S),(&T)) -> Result<(),U>) -> Result<(),U> {
assert vec::same_length(ss, ts);
let n = vec::len(ts);
let mut i = 0u;
while i < n {
match op(ss[i],ts[i]) {
match op(&ss[i],&ts[i]) {
Ok(()) => (),
Err(u) => return Err(u)
Err(copy u) => return Err(u)
}
i += 1u;
}
@ -339,7 +348,7 @@ fn iter_vec2<S,T,U:Copy>(ss: &[S], ts: &[T],
}
/// Unwraps a result, assuming it is an `ok(T)`
fn unwrap<T, U>(+res: Result<T, U>) -> T {
pub fn unwrap<T, U>(res: Result<T, U>) -> T {
match move res {
Ok(move t) => move t,
Err(_) => fail ~"unwrap called on an err result"
@ -347,7 +356,7 @@ fn unwrap<T, U>(+res: Result<T, U>) -> T {
}
/// Unwraps a result, assuming it is an `err(U)`
fn unwrap_err<T, U>(+res: Result<T, U>) -> U {
pub fn unwrap_err<T, U>(res: Result<T, U>) -> U {
match move res {
Err(move u) => move u,
Ok(_) => fail ~"unwrap called on an ok result"
@ -357,15 +366,15 @@ fn unwrap_err<T, U>(+res: Result<T, U>) -> U {
impl<T:Eq,U:Eq> Result<T,U> : Eq {
pure fn eq(other: &Result<T,U>) -> bool {
match self {
Ok(e0a) => {
Ok(ref e0a) => {
match (*other) {
Ok(e0b) => e0a == e0b,
Ok(ref e0b) => *e0a == *e0b,
_ => false
}
}
Err(e0a) => {
Err(ref e0a) => {
match (*other) {
Err(e0b) => e0a == e0b,
Err(ref e0b) => *e0a == *e0b,
_ => false
}
}
@ -380,7 +389,7 @@ mod tests {
#[legacy_exports];
fn op1() -> result::Result<int, ~str> { result::Ok(666) }
fn op2(&&i: int) -> result::Result<uint, ~str> {
fn op2(i: int) -> result::Result<uint, ~str> {
result::Ok(i as uint + 1u)
}
@ -388,12 +397,12 @@ mod tests {
#[test]
fn chain_success() {
assert get(chain(op1(), op2)) == 667u;
assert get(&chain(op1(), op2)) == 667u;
}
#[test]
fn chain_failure() {
assert get_err(chain(op3(), op2)) == ~"sadface";
assert get_err(&chain(op3(), op2)) == ~"sadface";
}
#[test]

View file

@ -11,10 +11,9 @@ use libc::uintptr_t;
use gc::{cleanup_stack_for_failure, gc, Word};
#[allow(non_camel_case_types)]
type rust_task = c_void;
pub type rust_task = c_void;
extern mod rustrt {
#[legacy_exports];
#[rust_stack]
fn rust_upcall_fail(expr: *c_char, file: *c_char, line: size_t);
@ -35,13 +34,23 @@ extern mod rustrt {
// 'rt_', otherwise the compiler won't find it. To fix this, see
// gather_rust_rtcalls.
#[rt(fail_)]
fn rt_fail_(expr: *c_char, file: *c_char, line: size_t) {
pub fn rt_fail_(expr: *c_char, file: *c_char, line: size_t) {
cleanup_stack_for_failure();
rustrt::rust_upcall_fail(expr, file, line);
}
#[rt(fail_bounds_check)]
pub fn rt_fail_bounds_check(file: *c_char, line: size_t,
index: size_t, len: size_t) {
let msg = fmt!("index out of bounds: the len is %d but the index is %d",
len as int, index as int);
do str::as_buf(msg) |p, _len| {
rt_fail_(p as *c_char, file, line);
}
}
#[rt(exchange_malloc)]
fn rt_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char {
pub fn rt_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char {
return rustrt::rust_upcall_exchange_malloc(td, size);
}
@ -49,12 +58,12 @@ fn rt_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char {
// inside a landing pad may corrupt the state of the exception handler. If a
// problem occurs, call exit instead.
#[rt(exchange_free)]
fn rt_exchange_free(ptr: *c_char) {
pub fn rt_exchange_free(ptr: *c_char) {
rustrt::rust_upcall_exchange_free(ptr);
}
#[rt(malloc)]
fn rt_malloc(td: *c_char, size: uintptr_t) -> *c_char {
pub fn rt_malloc(td: *c_char, size: uintptr_t) -> *c_char {
return rustrt::rust_upcall_malloc(td, size);
}
@ -62,7 +71,7 @@ fn rt_malloc(td: *c_char, size: uintptr_t) -> *c_char {
// inside a landing pad may corrupt the state of the exception handler. If a
// problem occurs, call exit instead.
#[rt(free)]
fn rt_free(ptr: *c_char) {
pub fn rt_free(ptr: *c_char) {
rustrt::rust_upcall_free(ptr);
}

View file

@ -1,5 +1,5 @@
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
// tjc: re-forbid deprecated modes after snapshot
#[forbid(deprecated_pattern)];
//! Process spawning
@ -7,16 +7,8 @@ use option::{Some, None};
use libc::{pid_t, c_void, c_int};
use io::ReaderUtil;
export Program;
export run_program;
export start_program;
export program_output;
export spawn_process;
export waitpid;
#[abi = "cdecl"]
extern mod rustrt {
#[legacy_exports];
fn rust_run_program(argv: **libc::c_char, envp: *c_void,
dir: *libc::c_char,
in_fd: c_int, out_fd: c_int, err_fd: c_int)
@ -24,7 +16,7 @@ extern mod rustrt {
}
/// A value representing a child process
trait Program {
pub trait Program {
/// Returns the process id of the program
fn get_id() -> pid_t;
@ -68,7 +60,7 @@ trait Program {
*
* The process id of the spawned process
*/
fn spawn_process(prog: &str, args: &[~str],
pub fn spawn_process(prog: &str, args: &[~str],
env: &Option<~[(~str,~str)]>,
dir: &Option<~str>,
in_fd: c_int, out_fd: c_int, err_fd: c_int)
@ -89,10 +81,10 @@ fn with_argv<T>(prog: &str, args: &[~str],
let mut tmps = ~[];
for vec::each(args) |arg| {
let t = @copy *arg;
vec::push(tmps, t);
vec::push_all(argptrs, str::as_c_str(*t, |b| ~[b]));
tmps.push(t);
argptrs.push_all(str::as_c_str(*t, |b| ~[b]));
}
vec::push(argptrs, ptr::null());
argptrs.push(ptr::null());
vec::as_imm_buf(argptrs, |buf, _len| cb(buf))
}
@ -102,17 +94,17 @@ fn with_envp<T>(env: &Option<~[(~str,~str)]>,
// On posixy systems we can pass a char** for envp, which is
// a null-terminated array of "k=v\n" strings.
match *env {
Some(es) if !vec::is_empty(es) => {
Some(ref es) if !vec::is_empty(*es) => {
let mut tmps = ~[];
let mut ptrs = ~[];
for vec::each(es) |e| {
for vec::each(*es) |e| {
let (k,v) = copy *e;
let t = @(fmt!("%s=%s", k, v));
vec::push(tmps, t);
vec::push_all(ptrs, str::as_c_str(*t, |b| ~[b]));
tmps.push(t);
ptrs.push_all(str::as_c_str(*t, |b| ~[b]));
}
vec::push(ptrs, ptr::null());
ptrs.push(ptr::null());
vec::as_imm_buf(ptrs, |p, _len|
unsafe { cb(::cast::reinterpret_cast(&p)) }
)
@ -149,7 +141,7 @@ fn with_envp<T>(env: &Option<~[(~str,~str)]>,
fn with_dirp<T>(d: &Option<~str>,
cb: fn(*libc::c_char) -> T) -> T {
match *d {
Some(dir) => str::as_c_str(dir, cb),
Some(ref dir) => str::as_c_str(*dir, cb),
None => cb(ptr::null())
}
}
@ -166,7 +158,7 @@ fn with_dirp<T>(d: &Option<~str>,
*
* The process id
*/
fn run_program(prog: &str, args: &[~str]) -> int {
pub fn run_program(prog: &str, args: &[~str]) -> int {
let pid = spawn_process(prog, args, &None, &None,
0i32, 0i32, 0i32);
if pid == -1 as pid_t { fail; }
@ -189,7 +181,7 @@ fn run_program(prog: &str, args: &[~str]) -> int {
*
* A class with a <program> field
*/
fn start_program(prog: &str, args: &[~str]) -> Program {
pub fn start_program(prog: &str, args: &[~str]) -> Program {
let pipe_input = os::pipe();
let pipe_output = os::pipe();
let pipe_err = os::pipe();
@ -232,7 +224,7 @@ fn start_program(prog: &str, args: &[~str]) -> Program {
drop { destroy_repr(&self.r); }
}
fn ProgRes(+r: ProgRepr) -> ProgRes {
fn ProgRes(r: ProgRepr) -> ProgRes {
ProgRes {
r: r
}
@ -278,7 +270,7 @@ fn read_all(rd: io::Reader) -> ~str {
* A record, {status: int, out: str, err: str} containing the exit code,
* the contents of stdout and the contents of stderr.
*/
fn program_output(prog: &str, args: &[~str]) ->
pub fn program_output(prog: &str, args: &[~str]) ->
{status: int, out: ~str, err: ~str} {
let pipe_in = os::pipe();
@ -320,11 +312,11 @@ fn program_output(prog: &str, args: &[~str]) ->
while count > 0 {
let stream = comm::recv(p);
match stream {
(1, s) => {
outs = copy s;
(1, copy s) => {
outs = s;
}
(2, s) => {
errs = copy s;
(2, copy s) => {
errs = s;
}
(n, _) => {
fail(fmt!("program_output received an unexpected file \
@ -336,7 +328,7 @@ fn program_output(prog: &str, args: &[~str]) ->
return {status: status, out: move outs, err: move errs};
}
fn writeclose(fd: c_int, s: &str) {
fn writeclose(fd: c_int, s: ~str) {
use io::WriterUtil;
error!("writeclose %d, %s", fd as int, s);
@ -359,7 +351,7 @@ fn readclose(fd: c_int) -> ~str {
}
/// Waits for a process to exit and returns the exit code
fn waitpid(pid: pid_t) -> int {
pub fn waitpid(pid: pid_t) -> int {
return waitpid_os(pid);
#[cfg(windows)]
@ -402,20 +394,19 @@ fn waitpid(pid: pid_t) -> int {
#[cfg(test)]
mod tests {
#[legacy_exports];
use io::WriterUtil;
// Regression test for memory leaks
#[ignore(cfg(windows))] // FIXME (#2626)
fn test_leaks() {
pub fn test_leaks() {
run::run_program("echo", []);
run::start_program("echo", []);
run::program_output("echo", []);
}
#[test]
fn test_pipes() {
#[allow(non_implicitly_copyable_typarams)]
pub fn test_pipes() {
let pipe_in = os::pipe();
let pipe_out = os::pipe();
let pipe_err = os::pipe();
@ -430,7 +421,7 @@ mod tests {
if pid == -1i32 { fail; }
let expected = ~"test";
writeclose(pipe_in.out, expected);
writeclose(pipe_in.out, copy expected);
let actual = readclose(pipe_out.in);
readclose(pipe_err.in);
os::waitpid(pid);
@ -441,7 +432,7 @@ mod tests {
}
#[test]
fn waitpid() {
pub fn waitpid() {
let pid = run::spawn_process("false", [],
&None, &None,
0i32, 0i32, 0i32);

View file

@ -12,10 +12,10 @@ use cmp::Eq;
use hash::Hash;
use to_bytes::IterBytes;
trait SendMap<K:Eq Hash, V: Copy> {
pub trait SendMap<K:Eq Hash, V: Copy> {
// FIXME(#3148) ^^^^ once find_ref() works, we can drop V:copy
fn insert(&mut self, +k: K, +v: V) -> bool;
fn insert(&mut self, k: K, +v: V) -> bool;
fn remove(&mut self, k: &K) -> bool;
fn clear(&mut self);
pure fn len(&const self) -> uint;
@ -31,17 +31,15 @@ trait SendMap<K:Eq Hash, V: Copy> {
}
/// Open addressing with linear probing.
mod linear {
#[legacy_exports];
export LinearMap, linear_map, linear_map_with_capacity, public_methods;
pub mod linear {
const initial_capacity: uint = 32u; // 2^5
struct Bucket<K:Eq Hash,V> {
hash: uint,
key: K,
value: V,
}
struct LinearMap<K:Eq Hash,V> {
pub struct LinearMap<K:Eq Hash,V> {
k0: u64,
k1: u64,
resize_at: uint,
@ -60,11 +58,11 @@ mod linear {
((capacity as float) * 3. / 4.) as uint
}
fn LinearMap<K:Eq Hash,V>() -> LinearMap<K,V> {
pub fn LinearMap<K:Eq Hash,V>() -> LinearMap<K,V> {
linear_map_with_capacity(32)
}
fn linear_map_with_capacity<K:Eq Hash,V>(
pub fn linear_map_with_capacity<K:Eq Hash,V>(
initial_capacity: uint) -> LinearMap<K,V> {
let r = rand::Rng();
linear_map_with_capacity_and_keys(r.gen_u64(), r.gen_u64(),
@ -137,7 +135,7 @@ mod linear {
k: &K) -> SearchResult {
let _ = for self.bucket_sequence(hash) |i| {
match buckets[i] {
Some(bkt) => if bkt.hash == hash && *k == bkt.key {
Some(ref bkt) => if bkt.hash == hash && *k == bkt.key {
return FoundEntry(i);
},
None => return FoundHole(i)
@ -163,7 +161,7 @@ mod linear {
}
}
fn insert_opt_bucket(&mut self, +bucket: Option<Bucket<K,V>>) {
fn insert_opt_bucket(&mut self, bucket: Option<Bucket<K,V>>) {
match move bucket {
Some(Bucket {hash: move hash,
key: move key,
@ -177,7 +175,7 @@ mod linear {
/// Inserts the key value pair into the buckets.
/// Assumes that there will be a bucket.
/// True if there was no previous entry with that key
fn insert_internal(&mut self, hash: uint, +k: K, +v: V) -> bool {
fn insert_internal(&mut self, hash: uint, k: K, v: V) -> bool {
match self.bucket_for_key_with_hash(self.buckets, hash, &k) {
TableFull => { fail ~"Internal logic error"; }
FoundHole(idx) => {
@ -208,7 +206,7 @@ mod linear {
}
impl<K:Hash IterBytes Eq,V> LinearMap<K,V> {
fn insert(&mut self, +k: K, +v: V) -> bool {
fn insert(&mut self, k: K, v: V) -> bool {
if self.size >= self.resize_at {
// n.b.: We could also do this after searching, so
// that we do not resize if this call to insert is
@ -285,18 +283,9 @@ mod linear {
FoundEntry(idx) => {
match self.buckets[idx] {
Some(ref bkt) => {
let ptr = unsafe {
// FIXME(#3148)--region inference
// fails to capture needed deps.
// Here, the bucket value is known to
// live as long as self, because self
// is immutable. But the region
// inference stupidly infers a
// lifetime for `ref bkt` that is
// shorter than it needs to be.
cast::copy_lifetime(self, &bkt.value)
};
Some(ptr)
// FIXME(#3148)---should be inferred
let bkt: &self/Bucket<K,V> = bkt;
Some(&bkt.value)
}
None => {
fail ~"LinearMap::find: internal logic error"
@ -344,7 +333,7 @@ mod linear {
// FIXME (#3148): Once we rewrite found_entry, this
// failure case won't be necessary
match self.buckets[idx] {
Some(bkt) => {Some(copy bkt.value)}
Some(Bucket {value: copy value, _}) => {Some(value)}
None => fail ~"LinearMap::find: internal logic error"
}
}
@ -366,13 +355,11 @@ mod linear {
}
#[test]
mod test {
#[legacy_exports];
pub mod test {
use linear::LinearMap;
#[test]
fn inserts() {
pub fn inserts() {
let mut m = ~LinearMap();
assert m.insert(1, 2);
assert m.insert(2, 4);
@ -381,7 +368,7 @@ mod test {
}
#[test]
fn overwrite() {
pub fn overwrite() {
let mut m = ~LinearMap();
assert m.insert(1, 2);
assert m.get(&1) == 2;
@ -390,7 +377,7 @@ mod test {
}
#[test]
fn conflicts() {
pub fn conflicts() {
let mut m = linear::linear_map_with_capacity(4);
assert m.insert(1, 2);
assert m.insert(5, 3);
@ -401,7 +388,7 @@ mod test {
}
#[test]
fn conflict_remove() {
pub fn conflict_remove() {
let mut m = linear::linear_map_with_capacity(4);
assert m.insert(1, 2);
assert m.insert(5, 3);
@ -412,7 +399,7 @@ mod test {
}
#[test]
fn empty() {
pub fn empty() {
let mut m = linear::linear_map_with_capacity(4);
assert m.insert(1, 2);
assert !m.is_empty();
@ -421,7 +408,7 @@ mod test {
}
#[test]
fn iterate() {
pub fn iterate() {
let mut m = linear::linear_map_with_capacity(4);
for uint::range(0, 32) |i| {
assert m.insert(i, i*2);
@ -435,7 +422,7 @@ mod test {
}
#[test]
fn find_ref() {
pub fn find_ref() {
let mut m = ~LinearMap();
assert m.find_ref(&1).is_none();
m.insert(1, 2);

View file

@ -1,7 +1,10 @@
#[doc(hidden)]; // FIXME #3538
#[legacy_modes]; // tjc: remove after snapshot
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
// XXX: Can't do this because frame_address needs a deprecated mode.
//#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];
use cast::reinterpret_cast;
@ -74,7 +77,7 @@ fn breakpoint() {
rustrt::rust_dbg_breakpoint()
}
fn frame_address(f: fn(*u8)) {
fn frame_address(f: fn(++x: *u8)) {
rusti::frame_address(f)
}
@ -86,5 +89,5 @@ extern mod rustrt {
#[abi = "rust-intrinsic"]
extern mod rusti {
#[legacy_exports];
fn frame_address(f: fn(*u8));
fn frame_address(f: fn(++x: *u8));
}

File diff suppressed because it is too large Load diff

View file

@ -7,21 +7,10 @@
use cmp::{Eq, Ord};
use libc::c_void;
export FreeGlue;
export TypeDesc;
export Closure;
export get_type_desc;
export size_of;
export min_align_of;
export pref_align_of;
export refcount;
export log_str;
export shape_eq, shape_lt, shape_le;
type FreeGlue = fn(*TypeDesc, *c_void);
pub type FreeGlue = fn(*TypeDesc, *c_void);
// Corresponds to runtime type_desc type
enum TypeDesc = {
pub enum TypeDesc = {
size: uint,
align: uint,
take_glue: uint,
@ -31,14 +20,13 @@ enum TypeDesc = {
};
/// The representation of a Rust closure
struct Closure {
pub struct Closure {
code: *(),
env: *(),
}
#[abi = "rust-intrinsic"]
extern mod rusti {
#[legacy_exports];
fn get_tydesc<T>() -> *();
fn size_of<T>() -> uint;
fn pref_align_of<T>() -> uint;
@ -47,15 +35,15 @@ extern mod rusti {
/// Compares contents of two pointers using the default method.
/// Equivalent to `*x1 == *x2`. Useful for hashtables.
pure fn shape_eq<T:Eq>(x1: &T, x2: &T) -> bool {
pub pure fn shape_eq<T:Eq>(x1: &T, x2: &T) -> bool {
*x1 == *x2
}
pure fn shape_lt<T:Ord>(x1: &T, x2: &T) -> bool {
pub pure fn shape_lt<T:Ord>(x1: &T, x2: &T) -> bool {
*x1 < *x2
}
pure fn shape_le<T:Ord>(x1: &T, x2: &T) -> bool {
pub pure fn shape_le<T:Ord>(x1: &T, x2: &T) -> bool {
*x1 <= *x2
}
@ -66,13 +54,13 @@ pure fn shape_le<T:Ord>(x1: &T, x2: &T) -> bool {
* performing dark magick.
*/
#[inline(always)]
pure fn get_type_desc<T>() -> *TypeDesc {
pub pure fn get_type_desc<T>() -> *TypeDesc {
unsafe { rusti::get_tydesc::<T>() as *TypeDesc }
}
/// Returns the size of a type
#[inline(always)]
pure fn size_of<T>() -> uint {
pub pure fn size_of<T>() -> uint {
unsafe { rusti::size_of::<T>() }
}
@ -83,26 +71,26 @@ pure fn size_of<T>() -> uint {
* than the preferred alignment.
*/
#[inline(always)]
pure fn min_align_of<T>() -> uint {
pub pure fn min_align_of<T>() -> uint {
unsafe { rusti::min_align_of::<T>() }
}
/// Returns the preferred alignment of a type
#[inline(always)]
pure fn pref_align_of<T>() -> uint {
pub pure fn pref_align_of<T>() -> uint {
unsafe { rusti::pref_align_of::<T>() }
}
/// Returns the refcount of a shared box (as just before calling this)
#[inline(always)]
pure fn refcount<T>(+t: @T) -> uint {
pub pure fn refcount<T>(t: @T) -> uint {
unsafe {
let ref_ptr: *uint = cast::reinterpret_cast(&t);
*ref_ptr - 1
}
}
pure fn log_str<T>(t: &T) -> ~str {
pub pure fn log_str<T>(t: &T) -> ~str {
unsafe {
do io::with_str_writer |wr| {
repr::write_repr(wr, t)
@ -111,11 +99,10 @@ pure fn log_str<T>(t: &T) -> ~str {
}
#[cfg(test)]
mod tests {
#[legacy_exports];
pub mod tests {
#[test]
fn size_of_basic() {
pub fn size_of_basic() {
assert size_of::<u8>() == 1u;
assert size_of::<u16>() == 2u;
assert size_of::<u32>() == 4u;
@ -125,20 +112,20 @@ mod tests {
#[test]
#[cfg(target_arch = "x86")]
#[cfg(target_arch = "arm")]
fn size_of_32() {
pub fn size_of_32() {
assert size_of::<uint>() == 4u;
assert size_of::<*uint>() == 4u;
}
#[test]
#[cfg(target_arch = "x86_64")]
fn size_of_64() {
pub fn size_of_64() {
assert size_of::<uint>() == 8u;
assert size_of::<*uint>() == 8u;
}
#[test]
fn align_of_basic() {
pub fn align_of_basic() {
assert pref_align_of::<u8>() == 1u;
assert pref_align_of::<u16>() == 2u;
assert pref_align_of::<u32>() == 4u;
@ -147,20 +134,20 @@ mod tests {
#[test]
#[cfg(target_arch = "x86")]
#[cfg(target_arch = "arm")]
fn align_of_32() {
pub fn align_of_32() {
assert pref_align_of::<uint>() == 4u;
assert pref_align_of::<*uint>() == 4u;
}
#[test]
#[cfg(target_arch = "x86_64")]
fn align_of_64() {
pub fn align_of_64() {
assert pref_align_of::<uint>() == 8u;
assert pref_align_of::<*uint>() == 8u;
}
#[test]
fn synthesize_closure() unsafe {
pub fn synthesize_closure() unsafe {
let x = 10;
let f: fn(int) -> int = |y| x + y;

View file

@ -1,5 +1,5 @@
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
// tjc: re-forbid deprecated modes after snapshot
#[forbid(deprecated_pattern)];
/*!
@ -32,54 +32,11 @@ use result::Result;
use pipes::{stream, Chan, Port};
use local_data_priv::{local_get, local_set};
export Task;
export TaskResult;
export Notification;
export SchedMode;
export SchedOpts;
export TaskOpts;
export TaskBuilder;
export task;
export default_task_opts;
export get_opts;
export set_opts;
export set_sched_mode;
export add_wrapper;
export run;
export future_result;
export run_listener;
export run_with;
export spawn;
export spawn_unlinked;
export spawn_supervised;
export spawn_with;
export spawn_listener;
export spawn_conversation;
export spawn_sched;
export try;
export yield;
export failing;
export get_task;
export unkillable, rekillable;
export atomically;
export local_data;
export SingleThreaded;
export ThreadPerCore;
export ThreadPerTask;
export ManualThreads;
export PlatformThread;
use rt::task_id;
use rt::rust_task;
/// A handle to a task
enum Task {
pub enum Task {
TaskHandle(task_id)
}
@ -99,7 +56,7 @@ impl Task : cmp::Eq {
* If you wish for this result's delivery to block until all linked and/or
* children tasks complete, recommend using a result future.
*/
enum TaskResult {
pub enum TaskResult {
Success,
Failure,
}
@ -115,7 +72,7 @@ impl TaskResult : Eq {
}
/// A message type for notifying of task lifecycle events
enum Notification {
pub enum Notification {
/// Sent when a task exits with the task handle and result
Exit(Task, TaskResult)
}
@ -134,7 +91,7 @@ impl Notification : cmp::Eq {
}
/// Scheduler modes
enum SchedMode {
pub enum SchedMode {
/// All tasks run in the same OS thread
SingleThreaded,
/// Tasks are distributed among available CPUs
@ -207,7 +164,7 @@ impl SchedMode : cmp::Eq {
* default these foreign stacks have unspecified size, but with this
* option their size can be precisely specified.
*/
type SchedOpts = {
pub type SchedOpts = {
mode: SchedMode,
foreign_stack_size: Option<uint>
};
@ -239,7 +196,7 @@ type SchedOpts = {
* into foreign code that blocks. Without doing so in a different
* scheduler other tasks will be impeded or even blocked indefinitely.
*/
type TaskOpts = {
pub type TaskOpts = {
linked: bool,
supervised: bool,
mut notify_chan: Option<Chan<Notification>>,
@ -260,7 +217,7 @@ type TaskOpts = {
// the run function move them in.
// FIXME (#2585): Replace the 'consumed' bit with move mode on self
enum TaskBuilder = {
pub enum TaskBuilder = {
opts: TaskOpts,
gen_body: fn@(+v: fn~()) -> fn~(),
can_not_copy: Option<util::NonCopyable>,
@ -272,10 +229,10 @@ enum TaskBuilder = {
* configuration methods can be chained.
* For example, task().unlinked().spawn is equivalent to spawn_unlinked.
*/
fn task() -> TaskBuilder {
pub fn task() -> TaskBuilder {
TaskBuilder({
opts: default_task_opts(),
gen_body: |body| move body, // Identity function
gen_body: |+body| move body, // Identity function
can_not_copy: None,
mut consumed: false,
})
@ -390,7 +347,7 @@ impl TaskBuilder {
* # Failure
* Fails if a future_result was already set for this task.
*/
fn future_result(blk: fn(+v: future::Future<TaskResult>)) -> TaskBuilder {
fn future_result(blk: fn(v: future::Future<TaskResult>)) -> TaskBuilder {
// FIXME (#1087, #1857): Once linked failure and notification are
// handled in the library, I can imagine implementing this by just
// registering an arbitrary number of task::on_exit handlers and
@ -473,7 +430,7 @@ impl TaskBuilder {
}
/**
* Creates and exucutes a new child task
* Creates and executes a new child task
*
* Sets up a new task with its own call stack and schedules it to run
* the provided unique closure. The task has the properties and behavior
@ -502,9 +459,9 @@ impl TaskBuilder {
spawn::spawn_raw(move opts, x.gen_body(move f));
}
/// Runs a task, while transfering ownership of one argument to the child.
fn spawn_with<A: Send>(+arg: A, +f: fn~(+v: A)) {
fn spawn_with<A: Send>(arg: A, +f: fn~(+v: A)) {
let arg = ~mut Some(move arg);
do self.spawn |move arg, move f|{
do self.spawn |move arg, move f| {
f(option::swap_unwrap(arg))
}
}
@ -516,7 +473,7 @@ impl TaskBuilder {
* child task, passes the port to child's body, and returns a channel
* linked to the port to the parent.
*
* This encapsulates Some boilerplate handshaking logic that would
* This encapsulates some boilerplate handshaking logic that would
* otherwise be required to establish communication from the parent
* to the child.
*/
@ -580,7 +537,7 @@ impl TaskBuilder {
/* Task construction */
fn default_task_opts() -> TaskOpts {
pub fn default_task_opts() -> TaskOpts {
/*!
* The default task options
*
@ -598,7 +555,7 @@ fn default_task_opts() -> TaskOpts {
/* Spawn convenience functions */
fn spawn(+f: fn~()) {
pub fn spawn(+f: fn~()) {
/*!
* Creates and executes a new child task
*
@ -611,7 +568,7 @@ fn spawn(+f: fn~()) {
task().spawn(move f)
}
fn spawn_unlinked(+f: fn~()) {
pub fn spawn_unlinked(+f: fn~()) {
/*!
* Creates a child task unlinked from the current one. If either this
* task or the child task fails, the other will not be killed.
@ -620,7 +577,7 @@ fn spawn_unlinked(+f: fn~()) {
task().unlinked().spawn(move f)
}
fn spawn_supervised(+f: fn~()) {
pub fn spawn_supervised(+f: fn~()) {
/*!
* Creates a child task unlinked from the current one. If either this
* task or the child task fails, the other will not be killed.
@ -629,7 +586,7 @@ fn spawn_supervised(+f: fn~()) {
task().supervised().spawn(move f)
}
fn spawn_with<A:Send>(+arg: A, +f: fn~(+v: A)) {
pub fn spawn_with<A:Send>(+arg: A, +f: fn~(+v: A)) {
/*!
* Runs a task, while transfering ownership of one argument to the
* child.
@ -643,7 +600,7 @@ fn spawn_with<A:Send>(+arg: A, +f: fn~(+v: A)) {
task().spawn_with(move arg, move f)
}
fn spawn_listener<A:Send>(+f: fn~(comm::Port<A>)) -> comm::Chan<A> {
pub fn spawn_listener<A:Send>(+f: fn~(comm::Port<A>)) -> comm::Chan<A> {
/*!
* Runs a new task while providing a channel from the parent to the child
*
@ -653,7 +610,7 @@ fn spawn_listener<A:Send>(+f: fn~(comm::Port<A>)) -> comm::Chan<A> {
task().spawn_listener(move f)
}
fn spawn_conversation<A: Send, B: Send>
pub fn spawn_conversation<A: Send, B: Send>
(+f: fn~(comm::Port<A>, comm::Chan<B>))
-> (comm::Port<B>, comm::Chan<A>) {
/*!
@ -665,7 +622,7 @@ fn spawn_conversation<A: Send, B: Send>
task().spawn_conversation(move f)
}
fn spawn_sched(mode: SchedMode, +f: fn~()) {
pub fn spawn_sched(mode: SchedMode, +f: fn~()) {
/*!
* Creates a new scheduler and executes a task on it
*
@ -682,7 +639,7 @@ fn spawn_sched(mode: SchedMode, +f: fn~()) {
task().sched_mode(mode).spawn(move f)
}
fn try<T:Send>(+f: fn~() -> T) -> Result<T,()> {
pub fn try<T:Send>(+f: fn~() -> T) -> Result<T,()> {
/*!
* Execute a function in another task and return either the return value
* of the function or result::err.
@ -696,7 +653,7 @@ fn try<T:Send>(+f: fn~() -> T) -> Result<T,()> {
/* Lifecycle functions */
fn yield() {
pub fn yield() {
//! Yield control to the task scheduler
let task_ = rt::rust_get_task();
@ -706,13 +663,13 @@ fn yield() {
}
}
fn failing() -> bool {
pub fn failing() -> bool {
//! True if the running task has failed
rt::rust_task_is_unwinding(rt::rust_get_task())
}
fn get_task() -> Task {
pub fn get_task() -> Task {
//! Get a handle to the running task
TaskHandle(rt::get_task_id())
@ -733,7 +690,7 @@ fn get_task() -> Task {
* }
* ~~~
*/
unsafe fn unkillable<U>(f: fn() -> U) -> U {
pub unsafe fn unkillable<U>(f: fn() -> U) -> U {
struct AllowFailure {
t: *rust_task,
drop { rt::rust_task_allow_kill(self.t); }
@ -752,7 +709,7 @@ unsafe fn unkillable<U>(f: fn() -> U) -> U {
}
/// The inverse of unkillable. Only ever to be used nested in unkillable().
unsafe fn rekillable<U>(f: fn() -> U) -> U {
pub unsafe fn rekillable<U>(f: fn() -> U) -> U {
struct DisallowFailure {
t: *rust_task,
drop { rt::rust_task_inhibit_kill(self.t); }
@ -774,7 +731,7 @@ unsafe fn rekillable<U>(f: fn() -> U) -> U {
* A stronger version of unkillable that also inhibits scheduling operations.
* For use with exclusive ARCs, which use pthread mutexes directly.
*/
unsafe fn atomically<U>(f: fn() -> U) -> U {
pub unsafe fn atomically<U>(f: fn() -> U) -> U {
struct DeferInterrupts {
t: *rust_task,
drop {
@ -1102,7 +1059,6 @@ fn test_spawn_sched_childs_on_same_sched() {
#[nolink]
#[cfg(test)]
extern mod testrt {
#[legacy_exports];
fn rust_dbg_lock_create() -> *libc::c_void;
fn rust_dbg_lock_destroy(lock: *libc::c_void);
fn rust_dbg_lock_lock(lock: *libc::c_void);
@ -1175,10 +1131,10 @@ fn avoid_copying_the_body(spawnfn: fn(+v: fn~())) {
let ch = comm::Chan(p);
let x = ~1;
let x_in_parent = ptr::addr_of(*x) as uint;
let x_in_parent = ptr::p2::addr_of(&(*x)) as uint;
do spawnfn {
let x_in_child = ptr::addr_of(*x) as uint;
let x_in_child = ptr::p2::addr_of(&(*x)) as uint;
comm::send(ch, x_in_child);
}
@ -1193,7 +1149,7 @@ fn test_avoid_copying_the_body_spawn() {
#[test]
fn test_avoid_copying_the_body_spawn_listener() {
do avoid_copying_the_body |f| {
do avoid_copying_the_body |+f| {
spawn_listener(fn~(move f, _po: comm::Port<int>) {
f();
});
@ -1211,7 +1167,7 @@ fn test_avoid_copying_the_body_task_spawn() {
#[test]
fn test_avoid_copying_the_body_spawn_listener_1() {
do avoid_copying_the_body |f| {
do avoid_copying_the_body |+f| {
task().spawn_listener(fn~(move f, _po: comm::Port<int>) {
f();
});

View file

@ -16,12 +16,6 @@ magic.
*/
export LocalDataKey;
export local_data_pop;
export local_data_get;
export local_data_set;
export local_data_modify;
use local_data_priv::{
local_pop,
local_get,
@ -43,13 +37,13 @@ use local_data_priv::{
*
* These two cases aside, the interface is safe.
*/
type LocalDataKey<T: Owned> = &fn(+v: @T);
pub type LocalDataKey<T: Owned> = &fn(v: @T);
/**
* Remove a task-local data value from the table, returning the
* reference that was originally created to insert it.
*/
unsafe fn local_data_pop<T: Owned>(
pub unsafe fn local_data_pop<T: Owned>(
key: LocalDataKey<T>) -> Option<@T> {
local_pop(rt::rust_get_task(), key)
@ -58,7 +52,7 @@ unsafe fn local_data_pop<T: Owned>(
* Retrieve a task-local data value. It will also be kept alive in the
* table until explicitly removed.
*/
unsafe fn local_data_get<T: Owned>(
pub unsafe fn local_data_get<T: Owned>(
key: LocalDataKey<T>) -> Option<@T> {
local_get(rt::rust_get_task(), key)
@ -67,8 +61,8 @@ unsafe fn local_data_get<T: Owned>(
* Store a value in task-local data. If this key already has a value,
* that value is overwritten (and its destructor is run).
*/
unsafe fn local_data_set<T: Owned>(
key: LocalDataKey<T>, +data: @T) {
pub unsafe fn local_data_set<T: Owned>(
key: LocalDataKey<T>, data: @T) {
local_set(rt::rust_get_task(), key, data)
}
@ -76,7 +70,7 @@ unsafe fn local_data_set<T: Owned>(
* Modify a task-local data value. If the function returns 'None', the
* data is removed (and its reference dropped).
*/
unsafe fn local_data_modify<T: Owned>(
pub unsafe fn local_data_modify<T: Owned>(
key: LocalDataKey<T>,
modify_fn: fn(Option<@T>) -> Option<@T>) {
@ -84,8 +78,8 @@ unsafe fn local_data_modify<T: Owned>(
}
#[test]
fn test_tls_multitask() unsafe {
fn my_key(+_x: @~str) { }
pub fn test_tls_multitask() unsafe {
fn my_key(_x: @~str) { }
local_data_set(my_key, @~"parent data");
do task::spawn unsafe {
assert local_data_get(my_key).is_none(); // TLS shouldn't carry over.
@ -100,16 +94,16 @@ fn test_tls_multitask() unsafe {
}
#[test]
fn test_tls_overwrite() unsafe {
fn my_key(+_x: @~str) { }
pub fn test_tls_overwrite() unsafe {
fn my_key(_x: @~str) { }
local_data_set(my_key, @~"first data");
local_data_set(my_key, @~"next data"); // Shouldn't leak.
assert *(local_data_get(my_key).get()) == ~"next data";
}
#[test]
fn test_tls_pop() unsafe {
fn my_key(+_x: @~str) { }
pub fn test_tls_pop() unsafe {
fn my_key(_x: @~str) { }
local_data_set(my_key, @~"weasel");
assert *(local_data_pop(my_key).get()) == ~"weasel";
// Pop must remove the data from the map.
@ -117,18 +111,18 @@ fn test_tls_pop() unsafe {
}
#[test]
fn test_tls_modify() unsafe {
fn my_key(+_x: @~str) { }
pub fn test_tls_modify() unsafe {
fn my_key(_x: @~str) { }
local_data_modify(my_key, |data| {
match data {
Some(@val) => fail ~"unwelcome value: " + val,
Some(@ref val) => fail ~"unwelcome value: " + *val,
None => Some(@~"first data")
}
});
local_data_modify(my_key, |data| {
match data {
Some(@~"first data") => Some(@~"next data"),
Some(@val) => fail ~"wrong value: " + val,
Some(@ref val) => fail ~"wrong value: " + *val,
None => fail ~"missing value"
}
});
@ -136,23 +130,23 @@ fn test_tls_modify() unsafe {
}
#[test]
fn test_tls_crust_automorestack_memorial_bug() unsafe {
pub fn test_tls_crust_automorestack_memorial_bug() unsafe {
// This might result in a stack-canary clobber if the runtime fails to set
// sp_limit to 0 when calling the cleanup extern - it might automatically
// jump over to the rust stack, which causes next_c_sp to get recorded as
// Something within a rust stack segment. Then a subsequent upcall (esp.
// for logging, think vsnprintf) would run on a stack smaller than 1 MB.
fn my_key(+_x: @~str) { }
fn my_key(_x: @~str) { }
do task::spawn {
unsafe { local_data_set(my_key, @~"hax"); }
}
}
#[test]
fn test_tls_multiple_types() unsafe {
fn str_key(+_x: @~str) { }
fn box_key(+_x: @@()) { }
fn int_key(+_x: @int) { }
pub fn test_tls_multiple_types() unsafe {
fn str_key(_x: @~str) { }
fn box_key(_x: @@()) { }
fn int_key(_x: @int) { }
do task::spawn unsafe {
local_data_set(str_key, @~"string data");
local_data_set(box_key, @@());
@ -161,10 +155,10 @@ fn test_tls_multiple_types() unsafe {
}
#[test]
fn test_tls_overwrite_multiple_types() {
fn str_key(+_x: @~str) { }
fn box_key(+_x: @@()) { }
fn int_key(+_x: @int) { }
pub fn test_tls_overwrite_multiple_types() {
fn str_key(_x: @~str) { }
fn box_key(_x: @@()) { }
fn int_key(_x: @int) { }
do task::spawn unsafe {
local_data_set(str_key, @~"string data");
local_data_set(int_key, @42);
@ -177,10 +171,10 @@ fn test_tls_overwrite_multiple_types() {
#[test]
#[should_fail]
#[ignore(cfg(windows))]
fn test_tls_cleanup_on_failure() unsafe {
fn str_key(+_x: @~str) { }
fn box_key(+_x: @@()) { }
fn int_key(+_x: @int) { }
pub fn test_tls_cleanup_on_failure() unsafe {
fn str_key(_x: @~str) { }
fn box_key(_x: @@()) { }
fn int_key(_x: @int) { }
local_data_set(str_key, @~"parent data");
local_data_set(box_key, @@());
do task::spawn unsafe { // spawn_linked

View file

@ -3,7 +3,7 @@
use local_data::LocalDataKey;
use rt::rust_task;
trait LocalData { }
pub trait LocalData { }
impl<T: Owned> @T: LocalData { }
impl LocalData: Eq {
@ -17,11 +17,11 @@ impl LocalData: Eq {
// We use dvec because it's the best data structure in core. If TLS is used
// heavily in future, this could be made more efficient with a proper map.
type TaskLocalElement = (*libc::c_void, *libc::c_void, LocalData);
pub type TaskLocalElement = (*libc::c_void, *libc::c_void, LocalData);
// Has to be a pointer at outermost layer; the foreign call returns void *.
type TaskLocalMap = @dvec::DVec<Option<TaskLocalElement>>;
pub type TaskLocalMap = @dvec::DVec<Option<TaskLocalElement>>;
extern fn cleanup_task_local_map(map_ptr: *libc::c_void) unsafe {
pub extern fn cleanup_task_local_map(map_ptr: *libc::c_void) unsafe {
assert !map_ptr.is_null();
// Get and keep the single reference that was created at the beginning.
let _map: TaskLocalMap = cast::reinterpret_cast(&map_ptr);
@ -29,7 +29,7 @@ extern fn cleanup_task_local_map(map_ptr: *libc::c_void) unsafe {
}
// Gets the map from the runtime. Lazily initialises if not done so already.
unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap {
pub unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap {
// Relies on the runtime initialising the pointer to null.
// NOTE: The map's box lives in TLS invisibly referenced once. Each time
@ -52,7 +52,7 @@ unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap {
}
}
unsafe fn key_to_key_value<T: Owned>(
pub unsafe fn key_to_key_value<T: Owned>(
key: LocalDataKey<T>) -> *libc::c_void {
// Keys are closures, which are (fnptr,envptr) pairs. Use fnptr.
@ -62,25 +62,25 @@ unsafe fn key_to_key_value<T: Owned>(
}
// If returning Some(..), returns with @T with the map's reference. Careful!
unsafe fn local_data_lookup<T: Owned>(
pub unsafe fn local_data_lookup<T: Owned>(
map: TaskLocalMap, key: LocalDataKey<T>)
-> Option<(uint, *libc::c_void)> {
let key_value = key_to_key_value(key);
let map_pos = (*map).position(|entry|
match entry {
match *entry {
Some((k,_,_)) => k == key_value,
None => false
}
);
do map_pos.map |index| {
// .get() is guaranteed because of "None { false }" above.
let (_, data_ptr, _) = (*map)[index].get();
(index, data_ptr)
let (_, data_ptr, _) = (*map)[*index].get();
(*index, data_ptr)
}
}
unsafe fn local_get_helper<T: Owned>(
pub unsafe fn local_get_helper<T: Owned>(
task: *rust_task, key: LocalDataKey<T>,
do_pop: bool) -> Option<@T> {
@ -91,7 +91,7 @@ unsafe fn local_get_helper<T: Owned>(
// was referenced in the local_data box, though, not here, so before
// overwriting the local_data_box we need to give an extra reference.
// We must also give an extra reference when not removing.
let (index, data_ptr) = result;
let (index, data_ptr) = *result;
let data: @T = cast::transmute(move data_ptr);
cast::bump_box_refcount(data);
if do_pop {
@ -102,22 +102,22 @@ unsafe fn local_get_helper<T: Owned>(
}
unsafe fn local_pop<T: Owned>(
pub unsafe fn local_pop<T: Owned>(
task: *rust_task,
key: LocalDataKey<T>) -> Option<@T> {
local_get_helper(task, key, true)
}
unsafe fn local_get<T: Owned>(
pub unsafe fn local_get<T: Owned>(
task: *rust_task,
key: LocalDataKey<T>) -> Option<@T> {
local_get_helper(task, key, false)
}
unsafe fn local_set<T: Owned>(
task: *rust_task, key: LocalDataKey<T>, +data: @T) {
pub unsafe fn local_set<T: Owned>(
task: *rust_task, key: LocalDataKey<T>, data: @T) {
let map = get_task_local_map(task);
// Store key+data as *voids. Data is invisibly referenced once; key isn't.
@ -148,7 +148,7 @@ unsafe fn local_set<T: Owned>(
}
}
unsafe fn local_modify<T: Owned>(
pub unsafe fn local_modify<T: Owned>(
task: *rust_task, key: LocalDataKey<T>,
modify_fn: fn(Option<@T>) -> Option<@T>) {

View file

@ -7,16 +7,16 @@ The task interface to the runtime
#[doc(hidden)]; // FIXME #3538
#[allow(non_camel_case_types)] // runtime type
type sched_id = int;
pub type sched_id = int;
#[allow(non_camel_case_types)] // runtime type
type task_id = int;
pub type task_id = int;
// These are both opaque runtime/compiler types that we don't know the
// structure of and should only deal with via unsafe pointer
#[allow(non_camel_case_types)] // runtime type
type rust_task = libc::c_void;
pub type rust_task = libc::c_void;
#[allow(non_camel_case_types)] // runtime type
type rust_closure = libc::c_void;
pub type rust_closure = libc::c_void;
extern {
#[rust_stack]

View file

@ -66,28 +66,28 @@ use rt::rust_task;
use rt::rust_closure;
macro_rules! move_it (
{ $x:expr } => { unsafe { let y <- *ptr::addr_of($x); move y } }
{ $x:expr } => { unsafe { let y <- *ptr::addr_of(&($x)); move y } }
)
type TaskSet = send_map::linear::LinearMap<*rust_task,()>;
pub type TaskSet = send_map::linear::LinearMap<*rust_task,()>;
fn new_taskset() -> TaskSet {
pub fn new_taskset() -> TaskSet {
send_map::linear::LinearMap()
}
fn taskset_insert(tasks: &mut TaskSet, task: *rust_task) {
pub fn taskset_insert(tasks: &mut TaskSet, task: *rust_task) {
let didnt_overwrite = tasks.insert(task, ());
assert didnt_overwrite;
}
fn taskset_remove(tasks: &mut TaskSet, task: *rust_task) {
pub fn taskset_remove(tasks: &mut TaskSet, task: *rust_task) {
let was_present = tasks.remove(&task);
assert was_present;
}
fn taskset_each(tasks: &TaskSet, blk: fn(+v: *rust_task) -> bool) {
pub fn taskset_each(tasks: &TaskSet, blk: fn(v: *rust_task) -> bool) {
tasks.each_key(|k| blk(*k))
}
// One of these per group of linked-failure tasks.
type TaskGroupData = {
pub type TaskGroupData = {
// All tasks which might kill this group. When this is empty, the group
// can be "GC"ed (i.e., its link in the ancestor list can be removed).
mut members: TaskSet,
@ -95,12 +95,12 @@ type TaskGroupData = {
// tasks in this group.
mut descendants: TaskSet,
};
type TaskGroupArc = private::Exclusive<Option<TaskGroupData>>;
pub type TaskGroupArc = private::Exclusive<Option<TaskGroupData>>;
type TaskGroupInner = &mut Option<TaskGroupData>;
pub type TaskGroupInner = &mut Option<TaskGroupData>;
// A taskgroup is 'dead' when nothing can cause it to fail; only members can.
pure fn taskgroup_is_dead(tg: &TaskGroupData) -> bool {
pub pure fn taskgroup_is_dead(tg: &TaskGroupData) -> bool {
(&tg.members).is_empty()
}
@ -111,7 +111,7 @@ pure fn taskgroup_is_dead(tg: &TaskGroupData) -> bool {
// taskgroup which was spawned-unlinked. Tasks from intermediate generations
// have references to the middle of the list; when intermediate generations
// die, their node in the list will be collected at a descendant's spawn-time.
type AncestorNode = {
pub type AncestorNode = {
// Since the ancestor list is recursive, we end up with references to
// exclusives within other exclusives. This is dangerous business (if
// circular references arise, deadlock and memory leaks are imminent).
@ -124,16 +124,16 @@ type AncestorNode = {
// Recursive rest of the list.
mut ancestors: AncestorList,
};
enum AncestorList = Option<private::Exclusive<AncestorNode>>;
pub enum AncestorList = Option<private::Exclusive<AncestorNode>>;
// Accessors for taskgroup arcs and ancestor arcs that wrap the unsafety.
#[inline(always)]
fn access_group<U>(x: &TaskGroupArc, blk: fn(TaskGroupInner) -> U) -> U {
pub fn access_group<U>(x: &TaskGroupArc, blk: fn(TaskGroupInner) -> U) -> U {
unsafe { x.with(blk) }
}
#[inline(always)]
fn access_ancestors<U>(x: &private::Exclusive<AncestorNode>,
pub fn access_ancestors<U>(x: &private::Exclusive<AncestorNode>,
blk: fn(x: &mut AncestorNode) -> U) -> U {
unsafe { x.with(blk) }
}
@ -146,9 +146,9 @@ fn access_ancestors<U>(x: &private::Exclusive<AncestorNode>,
// (3) As a bonus, coalesces away all 'dead' taskgroup nodes in the list.
// FIXME(#2190): Change Option<fn@(...)> to Option<fn&(...)>, to save on
// allocations. Once that bug is fixed, changing the sigil should suffice.
fn each_ancestor(list: &mut AncestorList,
bail_opt: Option<fn@(TaskGroupInner)>,
forward_blk: fn(TaskGroupInner) -> bool)
pub fn each_ancestor(list: &mut AncestorList,
bail_opt: Option<fn@(TaskGroupInner)>,
forward_blk: fn(TaskGroupInner) -> bool)
-> bool {
// "Kickoff" call - there was no last generation.
return !coalesce(list, bail_opt, forward_blk, uint::max_value);
@ -200,7 +200,7 @@ fn each_ancestor(list: &mut AncestorList,
// the end of the list, which doesn't make sense to coalesce.
return do (**ancestors).map_default((None,false)) |ancestor_arc| {
// NB: Takes a lock! (this ancestor node)
do access_ancestors(&ancestor_arc) |nobe| {
do access_ancestors(ancestor_arc) |nobe| {
// Check monotonicity
assert last_generation > nobe.generation;
/*##########################################################*
@ -240,7 +240,7 @@ fn each_ancestor(list: &mut AncestorList,
if need_unwind && !nobe_is_dead {
do bail_opt.iter |bail_blk| {
do with_parent_tg(&mut nobe.parent_group) |tg_opt| {
bail_blk(tg_opt)
(*bail_blk)(tg_opt)
}
}
}
@ -271,7 +271,7 @@ fn each_ancestor(list: &mut AncestorList,
}
// One of these per task.
struct TCB {
pub struct TCB {
me: *rust_task,
// List of tasks with whose fates this one's is intertwined.
tasks: TaskGroupArc, // 'none' means the group has failed.
@ -303,8 +303,8 @@ struct TCB {
}
}
fn TCB(me: *rust_task, +tasks: TaskGroupArc, +ancestors: AncestorList,
is_main: bool, +notifier: Option<AutoNotify>) -> TCB {
pub fn TCB(me: *rust_task, tasks: TaskGroupArc, ancestors: AncestorList,
is_main: bool, notifier: Option<AutoNotify>) -> TCB {
let notifier = move notifier;
notifier.iter(|x| { x.failed = false; });
@ -318,7 +318,7 @@ fn TCB(me: *rust_task, +tasks: TaskGroupArc, +ancestors: AncestorList,
}
}
struct AutoNotify {
pub struct AutoNotify {
notify_chan: Chan<Notification>,
mut failed: bool,
drop {
@ -327,15 +327,15 @@ struct AutoNotify {
}
}
fn AutoNotify(+chan: Chan<Notification>) -> AutoNotify {
pub fn AutoNotify(chan: Chan<Notification>) -> AutoNotify {
AutoNotify {
notify_chan: chan,
failed: true // Un-set above when taskgroup successfully made.
}
}
fn enlist_in_taskgroup(state: TaskGroupInner, me: *rust_task,
is_member: bool) -> bool {
pub fn enlist_in_taskgroup(state: TaskGroupInner, me: *rust_task,
is_member: bool) -> bool {
let newstate = util::replace(state, None);
// If 'None', the group was failing. Can't enlist.
if newstate.is_some() {
@ -350,7 +350,8 @@ fn enlist_in_taskgroup(state: TaskGroupInner, me: *rust_task,
}
// NB: Runs in destructor/post-exit context. Can't 'fail'.
fn leave_taskgroup(state: TaskGroupInner, me: *rust_task, is_member: bool) {
pub fn leave_taskgroup(state: TaskGroupInner, me: *rust_task,
is_member: bool) {
let newstate = util::replace(state, None);
// If 'None', already failing and we've already gotten a kill signal.
if newstate.is_some() {
@ -362,7 +363,7 @@ fn leave_taskgroup(state: TaskGroupInner, me: *rust_task, is_member: bool) {
}
// NB: Runs in destructor/post-exit context. Can't 'fail'.
fn kill_taskgroup(state: TaskGroupInner, me: *rust_task, is_main: bool) {
pub fn kill_taskgroup(state: TaskGroupInner, me: *rust_task, is_main: bool) {
// NB: We could do the killing iteration outside of the group arc, by
// having "let mut newstate" here, swapping inside, and iterating after.
// But that would let other exiting tasks fall-through and exit while we
@ -377,13 +378,13 @@ fn kill_taskgroup(state: TaskGroupInner, me: *rust_task, is_main: bool) {
// see 'None' if Somebody already failed and we got a kill signal.)
if newstate.is_some() {
let group = option::unwrap(move newstate);
for taskset_each(&group.members) |+sibling| {
for taskset_each(&group.members) |sibling| {
// Skip self - killing ourself won't do much good.
if sibling != me {
rt::rust_task_kill_other(sibling);
}
}
for taskset_each(&group.descendants) |+child| {
for taskset_each(&group.descendants) |child| {
assert child != me;
rt::rust_task_kill_other(child);
}
@ -404,8 +405,8 @@ macro_rules! taskgroup_key (
() => (cast::transmute((-2 as uint, 0u)))
)
fn gen_child_taskgroup(linked: bool, supervised: bool)
-> (TaskGroupArc, AncestorList, bool) {
pub fn gen_child_taskgroup(linked: bool, supervised: bool)
-> (TaskGroupArc, AncestorList, bool) {
let spawner = rt::rust_get_task();
/*######################################################################*
* Step 1. Get spawner's taskgroup info.
@ -451,7 +452,9 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
// it should be enabled only in debug builds.
let new_generation =
match *old_ancestors {
Some(arc) => access_ancestors(&arc, |a| a.generation+1),
Some(ref arc) => {
access_ancestors(arc, |a| a.generation+1)
}
None => 0 // the actual value doesn't really matter.
};
assert new_generation < uint::max_value;
@ -484,7 +487,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
}
}
fn spawn_raw(+opts: TaskOpts, +f: fn~()) {
pub fn spawn_raw(opts: TaskOpts, +f: fn~()) {
let (child_tg, ancestors, is_main) =
gen_child_taskgroup(opts.linked, opts.supervised);
@ -509,8 +512,8 @@ fn spawn_raw(+opts: TaskOpts, +f: fn~()) {
let child_wrapper = make_child_wrapper(new_task, move child_tg,
move ancestors, is_main, move notify_chan, move f);
let fptr = ptr::addr_of(child_wrapper);
let closure: *rust_closure = cast::reinterpret_cast(&fptr);
let closure = cast::transmute(&child_wrapper);
// Getting killed between these two calls would free the child's
// closure. (Reordering them wouldn't help - then getting killed
@ -526,9 +529,9 @@ fn spawn_raw(+opts: TaskOpts, +f: fn~()) {
// (3a) If any of those fails, it leaves all groups, and does nothing.
// (3b) Otherwise it builds a task control structure and puts it in TLS,
// (4) ...and runs the provided body function.
fn make_child_wrapper(child: *rust_task, +child_arc: TaskGroupArc,
+ancestors: AncestorList, is_main: bool,
+notify_chan: Option<Chan<Notification>>,
fn make_child_wrapper(child: *rust_task, child_arc: TaskGroupArc,
ancestors: AncestorList, is_main: bool,
notify_chan: Option<Chan<Notification>>,
+f: fn~()) -> fn~() {
let child_data = ~mut Some((move child_arc, move ancestors));
return fn~(move notify_chan, move child_data, move f) {
@ -541,8 +544,8 @@ fn spawn_raw(+opts: TaskOpts, +f: fn~()) {
//let mut notifier = None;//notify_chan.map(|c| AutoNotify(c));
let notifier = match notify_chan {
Some(notify_chan_value) => {
let moved_ncv = move_it!(notify_chan_value);
Some(ref notify_chan_value) => {
let moved_ncv = move_it!(*notify_chan_value);
Some(AutoNotify(move moved_ncv))
}
_ => None

View file

@ -10,7 +10,7 @@ The `ToBytes` and `IterBytes` traits
use io::Writer;
type Cb = fn(buf: &[const u8]) -> bool;
pub type Cb = fn(buf: &[const u8]) -> bool;
/**
* A trait to implement in order to make a type hashable;
@ -19,7 +19,7 @@ type Cb = fn(buf: &[const u8]) -> bool;
* modified when default methods and trait inheritence are
* completed.
*/
trait IterBytes {
pub trait IterBytes {
/**
* Call the provided callback `f` one or more times with
* byte-slices that should be used when computing a hash
@ -211,7 +211,7 @@ impl<A: IterBytes> @[A]: IterBytes {
}
}
pure fn iter_bytes_2<A: IterBytes, B: IterBytes>(a: &A, b: &B,
pub pure fn iter_bytes_2<A: IterBytes, B: IterBytes>(a: &A, b: &B,
lsb0: bool, z: Cb) {
let mut flag = true;
a.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag});
@ -219,7 +219,7 @@ pure fn iter_bytes_2<A: IterBytes, B: IterBytes>(a: &A, b: &B,
b.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag});
}
pure fn iter_bytes_3<A: IterBytes,
pub pure fn iter_bytes_3<A: IterBytes,
B: IterBytes,
C: IterBytes>(a: &A, b: &B, c: &C,
lsb0: bool, z: Cb) {
@ -231,7 +231,7 @@ pure fn iter_bytes_3<A: IterBytes,
c.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag});
}
pure fn iter_bytes_4<A: IterBytes,
pub pure fn iter_bytes_4<A: IterBytes,
B: IterBytes,
C: IterBytes,
D: IterBytes>(a: &A, b: &B, c: &C,
@ -247,7 +247,7 @@ pure fn iter_bytes_4<A: IterBytes,
d.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag});
}
pure fn iter_bytes_5<A: IterBytes,
pub pure fn iter_bytes_5<A: IterBytes,
B: IterBytes,
C: IterBytes,
D: IterBytes,
@ -266,7 +266,7 @@ pure fn iter_bytes_5<A: IterBytes,
e.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag});
}
pure fn iter_bytes_6<A: IterBytes,
pub pure fn iter_bytes_6<A: IterBytes,
B: IterBytes,
C: IterBytes,
D: IterBytes,
@ -288,7 +288,7 @@ pure fn iter_bytes_6<A: IterBytes,
f.iter_bytes(lsb0, |bytes| {flag = z(bytes); flag});
}
pure fn iter_bytes_7<A: IterBytes,
pub pure fn iter_bytes_7<A: IterBytes,
B: IterBytes,
C: IterBytes,
D: IterBytes,
@ -345,7 +345,7 @@ impl<A: IterBytes> Option<A>: IterBytes {
#[inline(always)]
pure fn iter_bytes(lsb0: bool, f: Cb) {
match self {
Some(a) => iter_bytes_2(&0u8, &a, lsb0, f),
Some(ref a) => iter_bytes_2(&0u8, a, lsb0, f),
None => 1u8.iter_bytes(lsb0, f)
}
}

View file

@ -8,7 +8,7 @@ The `ToStr` trait for converting to strings
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];
trait ToStr { fn to_str() -> ~str; }
pub trait ToStr { fn to_str() -> ~str; }
impl int: ToStr {
fn to_str() -> ~str { int::str(self) }
@ -101,7 +101,6 @@ impl<A: ToStr> ~A: ToStr {
#[cfg(test)]
#[allow(non_implicitly_copyable_typarams)]
mod tests {
#[legacy_exports];
#[test]
fn test_simple_types() {
assert 1.to_str() == ~"1";

View file

@ -6,7 +6,7 @@
use cmp::{Eq, Ord};
trait TupleOps<T,U> {
pub trait TupleOps<T,U> {
pure fn first() -> T;
pure fn second() -> U;
pure fn swap() -> (U, T);
@ -34,49 +34,54 @@ impl<T: Copy, U: Copy> (T, U): TupleOps<T,U> {
}
trait ExtendedTupleOps<A,B> {
fn zip() -> ~[(A, B)];
fn map<C>(f: fn(A, B) -> C) -> ~[C];
pub trait ExtendedTupleOps<A,B> {
fn zip(&self) -> ~[(A, B)];
fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C];
}
impl<A: Copy, B: Copy> (&[A], &[B]): ExtendedTupleOps<A,B> {
fn zip() -> ~[(A, B)] {
let (a, b) = self;
vec::zip_slice(a, b)
fn zip(&self) -> ~[(A, B)] {
match *self {
(ref a, ref b) => {
vec::zip_slice(*a, *b)
}
}
}
fn map<C>(f: fn(A, B) -> C) -> ~[C] {
let (a, b) = self;
vec::map2(a, b, f)
fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C] {
match *self {
(ref a, ref b) => {
vec::map2(*a, *b, f)
}
}
}
}
impl<A: Copy, B: Copy> (~[A], ~[B]): ExtendedTupleOps<A,B> {
fn zip() -> ~[(A, B)] {
// FIXME #2543: Bad copy
let (a, b) = copy self;
vec::zip(move a, move b)
fn zip(&self) -> ~[(A, B)] {
match *self {
(ref a, ref b) => {
vec::zip_slice(*a, *b)
}
}
}
fn map<C>(f: fn(A, B) -> C) -> ~[C] {
// FIXME #2543: Bad copy
let (a, b) = copy self;
vec::map2(a, b, f)
fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C] {
match *self {
(ref a, ref b) => {
vec::map2(*a, *b, f)
}
}
}
}
impl<A: Eq, B: Eq> (A, B) : Eq {
pure fn eq(other: &(A, B)) -> bool {
// XXX: This would be a lot less wordy with ref bindings, but I don't
// trust that they work yet.
match self {
(self_a, self_b) => {
match (*other) {
(ref other_a, ref other_b) => {
self_a.eq(other_a) && self_b.eq(other_b)
}
(ref self_a, ref self_b) => match other {
&(ref other_a, ref other_b) => {
(*self_a).eq(other_a) && (*self_b).eq(other_b)
}
}
}
@ -106,16 +111,11 @@ impl<A: Ord, B: Ord> (A, B) : Ord {
impl<A: Eq, B: Eq, C: Eq> (A, B, C) : Eq {
pure fn eq(other: &(A, B, C)) -> bool {
// XXX: This would be a lot less wordy with ref bindings, but I don't
// trust that they work yet.
match self {
(self_a, self_b, self_c) => {
match (*other) {
(ref other_a, ref other_b, ref other_c) => {
self_a.eq(other_a) &&
self_b.eq(other_b) &&
self_c.eq(other_c)
}
(ref self_a, ref self_b, ref self_c) => match other {
&(ref other_a, ref other_b, ref other_c) => {
(*self_a).eq(other_a) && (*self_b).eq(other_b)
&& (*self_c).eq(other_c)
}
}
}

View file

@ -6,49 +6,36 @@ use T = inst::T;
use cmp::{Eq, Ord};
use from_str::FromStr;
export min_value, max_value;
export min, max;
export add, sub, mul, div, rem;
export lt, le, eq, ne, ge, gt;
export is_positive, is_negative;
export is_nonpositive, is_nonnegative;
export range;
export compl;
export to_str, to_str_bytes;
export from_str, from_str_radix, str, parse_bytes;
export num, ord, eq, times, timesi;
export bits, bytes;
pub const bits : uint = inst::bits;
pub const bytes : uint = (inst::bits / 8);
const bits : uint = inst::bits;
const bytes : uint = (inst::bits / 8);
pub const min_value: T = 0 as T;
pub const max_value: T = 0 as T - 1 as T;
const min_value: T = 0 as T;
const max_value: T = 0 as T - 1 as T;
pub pure fn min(x: T, y: T) -> T { if x < y { x } else { y } }
pub pure fn max(x: T, y: T) -> T { if x > y { x } else { y } }
pure fn min(x: T, y: T) -> T { if x < y { x } else { y } }
pure fn max(x: T, y: T) -> T { if x > y { x } else { y } }
pub pure fn add(x: T, y: T) -> T { x + y }
pub pure fn sub(x: T, y: T) -> T { x - y }
pub pure fn mul(x: T, y: T) -> T { x * y }
pub pure fn div(x: T, y: T) -> T { x / y }
pub pure fn rem(x: T, y: T) -> T { x % y }
pure fn add(x: T, y: T) -> T { x + y }
pure fn sub(x: T, y: T) -> T { x - y }
pure fn mul(x: T, y: T) -> T { x * y }
pure fn div(x: T, y: T) -> T { x / y }
pure fn rem(x: T, y: T) -> T { x % y }
pub pure fn lt(x: T, y: T) -> bool { x < y }
pub pure fn le(x: T, y: T) -> bool { x <= y }
pub pure fn eq(x: T, y: T) -> bool { x == y }
pub pure fn ne(x: T, y: T) -> bool { x != y }
pub pure fn ge(x: T, y: T) -> bool { x >= y }
pub pure fn gt(x: T, y: T) -> bool { x > y }
pure fn lt(x: T, y: T) -> bool { x < y }
pure fn le(x: T, y: T) -> bool { x <= y }
pure fn eq(x: T, y: T) -> bool { x == y }
pure fn ne(x: T, y: T) -> bool { x != y }
pure fn ge(x: T, y: T) -> bool { x >= y }
pure fn gt(x: T, y: T) -> bool { x > y }
pure fn is_positive(x: T) -> bool { x > 0 as T }
pure fn is_negative(x: T) -> bool { x < 0 as T }
pure fn is_nonpositive(x: T) -> bool { x <= 0 as T }
pure fn is_nonnegative(x: T) -> bool { x >= 0 as T }
pub pure fn is_positive(x: T) -> bool { x > 0 as T }
pub pure fn is_negative(x: T) -> bool { x < 0 as T }
pub pure fn is_nonpositive(x: T) -> bool { x <= 0 as T }
pub pure fn is_nonnegative(x: T) -> bool { x >= 0 as T }
#[inline(always)]
/// Iterate over the range [`lo`..`hi`)
pure fn range(lo: T, hi: T, it: fn(T) -> bool) {
pub pure fn range(lo: T, hi: T, it: fn(T) -> bool) {
let mut i = lo;
while i < hi {
if !it(i) { break }
@ -57,7 +44,7 @@ pure fn range(lo: T, hi: T, it: fn(T) -> bool) {
}
/// Computes the bitwise complement
pure fn compl(i: T) -> T {
pub pure fn compl(i: T) -> T {
max_value ^ i
}
@ -74,11 +61,11 @@ impl T : Eq {
}
impl T: num::Num {
pure fn add(&&other: T) -> T { return self + other; }
pure fn sub(&&other: T) -> T { return self - other; }
pure fn mul(&&other: T) -> T { return self * other; }
pure fn div(&&other: T) -> T { return self / other; }
pure fn modulo(&&other: T) -> T { return self % other; }
pure fn add(other: &T) -> T { return self + *other; }
pure fn sub(other: &T) -> T { return self - *other; }
pure fn mul(other: &T) -> T { return self * *other; }
pure fn div(other: &T) -> T { return self / *other; }
pure fn modulo(other: &T) -> T { return self % *other; }
pure fn neg() -> T { return -self; }
pure fn to_int() -> int { return self as int; }
@ -126,7 +113,7 @@ impl T: iter::TimesIx {
*
* `buf` must not be empty
*/
fn parse_bytes(buf: &[const u8], radix: uint) -> Option<T> {
pub fn parse_bytes(buf: &[const u8], radix: uint) -> Option<T> {
if vec::len(buf) == 0u { return None; }
let mut i = vec::len(buf) - 1u;
let mut power = 1u as T;
@ -143,14 +130,14 @@ fn parse_bytes(buf: &[const u8], radix: uint) -> Option<T> {
}
/// Parse a string to an int
fn from_str(s: &str) -> Option<T> { parse_bytes(str::to_bytes(s), 10u) }
pub fn from_str(s: &str) -> Option<T> { parse_bytes(str::to_bytes(s), 10u) }
impl T : FromStr {
static fn from_str(s: &str) -> Option<T> { from_str(s) }
}
/// Parse a string as an unsigned integer.
fn from_str_radix(buf: &str, radix: u64) -> Option<u64> {
pub fn from_str_radix(buf: &str, radix: u64) -> Option<u64> {
if str::len(buf) == 0u { return None; }
let mut i = str::len(buf) - 1u;
let mut power = 1u64, n = 0u64;
@ -172,7 +159,7 @@ fn from_str_radix(buf: &str, radix: u64) -> Option<u64> {
*
* Fails if `radix` < 2 or `radix` > 16
*/
pure fn to_str(num: T, radix: uint) -> ~str {
pub pure fn to_str(num: T, radix: uint) -> ~str {
do to_str_bytes(false, num, radix) |slice| {
do vec::as_imm_buf(slice) |p, len| {
unsafe { str::raw::from_buf_len(p, len) }
@ -181,7 +168,7 @@ pure fn to_str(num: T, radix: uint) -> ~str {
}
/// Low-level helper routine for string conversion.
pure fn to_str_bytes<U>(neg: bool, num: T, radix: uint,
pub pure fn to_str_bytes<U>(neg: bool, num: T, radix: uint,
f: fn(v: &[u8]) -> U) -> U {
#[inline(always)]
@ -239,17 +226,16 @@ pure fn to_str_bytes<U>(neg: bool, num: T, radix: uint,
*ptr::mut_offset(mp, i) = '-' as u8;
}
vec::raw::form_slice(ptr::offset(p, i),
len - i, f)
vec::raw::buf_as_slice(ptr::offset(p, i), len - i, f)
}
}
}
/// Convert to a string
fn str(i: T) -> ~str { return to_str(i, 10u); }
pub fn str(i: T) -> ~str { return to_str(i, 10u); }
#[test]
fn test_to_str() {
pub fn test_to_str() {
assert to_str(0 as T, 10u) == ~"0";
assert to_str(1 as T, 10u) == ~"1";
assert to_str(2 as T, 10u) == ~"2";
@ -261,7 +247,7 @@ fn test_to_str() {
#[test]
#[ignore]
fn test_from_str() {
pub fn test_from_str() {
assert from_str(~"0") == Some(0u as T);
assert from_str(~"3") == Some(3u as T);
assert from_str(~"10") == Some(10u as T);
@ -275,7 +261,7 @@ fn test_from_str() {
#[test]
#[ignore]
fn test_parse_bytes() {
pub fn test_parse_bytes() {
use str::to_bytes;
assert parse_bytes(to_bytes(~"123"), 10u) == Some(123u as T);
assert parse_bytes(to_bytes(~"1001"), 2u) == Some(9u as T);
@ -291,19 +277,19 @@ fn test_parse_bytes() {
#[test]
#[should_fail]
#[ignore(cfg(windows))]
fn to_str_radix1() {
pub fn to_str_radix1() {
uint::to_str(100u, 1u);
}
#[test]
#[should_fail]
#[ignore(cfg(windows))]
fn to_str_radix17() {
pub fn to_str_radix17() {
uint::to_str(100u, 17u);
}
#[test]
fn test_times() {
pub fn test_times() {
use iter::Times;
let ten = 10 as T;
let mut accum = 0;

View file

@ -1,2 +1,2 @@
type T = u16;
const bits: uint = 16;
pub type T = u16;
pub const bits: uint = 16;

View file

@ -1,2 +1,2 @@
type T = u32;
const bits: uint = 32;
pub type T = u32;
pub const bits: uint = 32;

View file

@ -1,2 +1,2 @@
type T = u64;
const bits: uint = 64;
pub type T = u64;
pub const bits: uint = 64;

View file

@ -1,7 +1,7 @@
type T = u8;
const bits: uint = 8;
pub type T = u8;
pub const bits: uint = 8;
// Type-specific functions here. These must be reexported by the
// parent module so that they appear in core::u8 and not core::u8::u8;
pure fn is_ascii(x: T) -> bool { return 0 as T == x & 128 as T; }
pub pure fn is_ascii(x: T) -> bool { return 0 as T == x & 128 as T; }

View file

@ -1,11 +1,11 @@
type T = uint;
pub type T = uint;
#[cfg(target_arch = "x86")]
#[cfg(target_arch = "arm")]
const bits: uint = 32;
pub const bits: uint = 32;
#[cfg(target_arch = "x86_64")]
const bits: uint = 64;
pub const bits: uint = 64;
/**
* Divide two numbers, return the result, rounded up.
@ -19,7 +19,7 @@ const bits: uint = 64;
*
* The smallest integer `q` such that `x/y <= q`.
*/
pure fn div_ceil(x: uint, y: uint) -> uint {
pub pure fn div_ceil(x: uint, y: uint) -> uint {
let div = x / y;
if x % y == 0u { div }
else { div + 1u }
@ -37,7 +37,7 @@ pure fn div_ceil(x: uint, y: uint) -> uint {
*
* The integer `q` closest to `x/y`.
*/
pure fn div_round(x: uint, y: uint) -> uint {
pub pure fn div_round(x: uint, y: uint) -> uint {
let div = x / y;
if x % y * 2u < y { div }
else { div + 1u }
@ -58,7 +58,7 @@ pure fn div_round(x: uint, y: uint) -> uint {
* The smallest integer `q` such that `x/y <= q`. This
* is either `x/y` or `x/y + 1`.
*/
pure fn div_floor(x: uint, y: uint) -> uint { return x / y; }
pub pure fn div_floor(x: uint, y: uint) -> uint { return x / y; }
/**
* Iterate over the range [`lo`..`hi`), or stop when requested
@ -75,7 +75,7 @@ pure fn div_floor(x: uint, y: uint) -> uint { return x / y; }
* `true` If execution proceeded correctly, `false` if it was interrupted,
* that is if `it` returned `false` at any point.
*/
pure fn iterate(lo: uint, hi: uint, it: fn(uint) -> bool) -> bool {
pub pure fn iterate(lo: uint, hi: uint, it: fn(uint) -> bool) -> bool {
let mut i = lo;
while i < hi {
if (!it(i)) { return false; }
@ -86,7 +86,7 @@ pure fn iterate(lo: uint, hi: uint, it: fn(uint) -> bool) -> bool {
/// Returns the smallest power of 2 greater than or equal to `n`
#[inline(always)]
fn next_power_of_two(n: uint) -> uint {
pub fn next_power_of_two(n: uint) -> uint {
let halfbits: uint = sys::size_of::<uint>() * 4u;
let mut tmp: uint = n - 1u;
let mut shift: uint = 1u;

View file

@ -3,9 +3,8 @@
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];
mod general_category {
#[legacy_exports];
pure fn Cc(c: char) -> bool {
pub mod general_category {
pub pure fn Cc(c: char) -> bool {
return match c {
'\x00' .. '\x1f'
| '\x7f' .. '\x9f' => true,
@ -13,7 +12,7 @@ mod general_category {
};
}
pure fn Cf(c: char) -> bool {
pub pure fn Cf(c: char) -> bool {
return match c {
'\xad'
| '\u0600' .. '\u0603'
@ -32,21 +31,21 @@ mod general_category {
};
}
pure fn Co(c: char) -> bool {
pub pure fn Co(c: char) -> bool {
return match c {
'\ue000' .. '\uf8ff' => true,
_ => false
};
}
pure fn Cs(c: char) -> bool {
pub pure fn Cs(c: char) -> bool {
return match c {
'\ud800' .. '\udfff' => true,
_ => false
};
}
pure fn Ll(c: char) -> bool {
pub pure fn Ll(c: char) -> bool {
return match c {
'\x61' .. '\x7a'
| '\xaa'
@ -651,7 +650,7 @@ mod general_category {
};
}
pure fn Lm(c: char) -> bool {
pub pure fn Lm(c: char) -> bool {
return match c {
'\u02b0' .. '\u02c1'
| '\u02c6' .. '\u02d1'
@ -707,7 +706,7 @@ mod general_category {
};
}
pure fn Lo(c: char) -> bool {
pub pure fn Lo(c: char) -> bool {
return match c {
'\u01bb'
| '\u01c0' .. '\u01c3'
@ -893,7 +892,7 @@ mod general_category {
};
}
pure fn Lt(c: char) -> bool {
pub pure fn Lt(c: char) -> bool {
return match c {
'\u01c5'
| '\u01c8'
@ -910,7 +909,7 @@ mod general_category {
};
}
pure fn Lu(c: char) -> bool {
pub pure fn Lu(c: char) -> bool {
return match c {
'\x41' .. '\x5a'
| '\xc0' .. '\xd6'
@ -1502,7 +1501,7 @@ mod general_category {
};
}
pure fn Mc(c: char) -> bool {
pub pure fn Mc(c: char) -> bool {
return match c {
'\u0903'
| '\u093b'
@ -1613,7 +1612,7 @@ mod general_category {
};
}
pure fn Me(c: char) -> bool {
pub pure fn Me(c: char) -> bool {
return match c {
'\u0488' .. '\u0489'
| '\u20dd' .. '\u20e0'
@ -1624,7 +1623,7 @@ mod general_category {
};
}
pure fn Mn(c: char) -> bool {
pub pure fn Mn(c: char) -> bool {
return match c {
'\u0300' .. '\u036f'
| '\u0483' .. '\u0487'
@ -1817,7 +1816,7 @@ mod general_category {
};
}
pure fn Nd(c: char) -> bool {
pub pure fn Nd(c: char) -> bool {
return match c {
'\x30' .. '\x39'
| '\u0660' .. '\u0669'
@ -1861,7 +1860,7 @@ mod general_category {
};
}
pure fn Nl(c: char) -> bool {
pub pure fn Nl(c: char) -> bool {
return match c {
'\u16ee' .. '\u16f0'
| '\u2160' .. '\u2182'
@ -1880,7 +1879,7 @@ mod general_category {
};
}
pure fn No(c: char) -> bool {
pub pure fn No(c: char) -> bool {
return match c {
'\xb2' .. '\xb3'
| '\xb9'
@ -1928,7 +1927,7 @@ mod general_category {
};
}
pure fn Pc(c: char) -> bool {
pub pure fn Pc(c: char) -> bool {
return match c {
'\x5f'
| '\u203f' .. '\u2040'
@ -1941,7 +1940,7 @@ mod general_category {
};
}
pure fn Pd(c: char) -> bool {
pub pure fn Pd(c: char) -> bool {
return match c {
'\x2d'
| '\u058a'
@ -1963,7 +1962,7 @@ mod general_category {
};
}
pure fn Pe(c: char) -> bool {
pub pure fn Pe(c: char) -> bool {
return match c {
'\x29'
| '\x5d'
@ -2040,7 +2039,7 @@ mod general_category {
};
}
pure fn Pf(c: char) -> bool {
pub pure fn Pf(c: char) -> bool {
return match c {
'\xbb'
| '\u2019'
@ -2057,7 +2056,7 @@ mod general_category {
};
}
pure fn Pi(c: char) -> bool {
pub pure fn Pi(c: char) -> bool {
return match c {
'\xab'
| '\u2018'
@ -2075,7 +2074,7 @@ mod general_category {
};
}
pure fn Po(c: char) -> bool {
pub pure fn Po(c: char) -> bool {
return match c {
'\x21' .. '\x23'
| '\x25' .. '\x27'
@ -2208,7 +2207,7 @@ mod general_category {
};
}
pure fn Ps(c: char) -> bool {
pub pure fn Ps(c: char) -> bool {
return match c {
'\x28'
| '\x5b'
@ -2287,7 +2286,7 @@ mod general_category {
};
}
pure fn Sc(c: char) -> bool {
pub pure fn Sc(c: char) -> bool {
return match c {
'\x24'
| '\xa2' .. '\xa5'
@ -2310,7 +2309,7 @@ mod general_category {
};
}
pure fn Sk(c: char) -> bool {
pub pure fn Sk(c: char) -> bool {
return match c {
'\x5e'
| '\x60'
@ -2344,7 +2343,7 @@ mod general_category {
};
}
pure fn Sm(c: char) -> bool {
pub pure fn Sm(c: char) -> bool {
return match c {
'\x2b'
| '\x3c' .. '\x3e'
@ -2415,7 +2414,7 @@ mod general_category {
};
}
pure fn So(c: char) -> bool {
pub pure fn So(c: char) -> bool {
return match c {
'\xa6' .. '\xa7'
| '\xa9'
@ -2534,21 +2533,21 @@ mod general_category {
};
}
pure fn Zl(c: char) -> bool {
pub pure fn Zl(c: char) -> bool {
return match c {
'\u2028' => true,
_ => false
};
}
pure fn Zp(c: char) -> bool {
pub pure fn Zp(c: char) -> bool {
return match c {
'\u2029' => true,
_ => false
};
}
pure fn Zs(c: char) -> bool {
pub pure fn Zs(c: char) -> bool {
return match c {
'\x20'
| '\xa0'
@ -2567,7 +2566,7 @@ mod general_category {
mod derived_property {
#[legacy_exports];
/// Check if a character has the alphabetic unicode property
pure fn Alphabetic(c: char) -> bool {
pub pure fn Alphabetic(c: char) -> bool {
return match c {
'\x41' .. '\x5a'
| '\x61' .. '\x7a'
@ -3305,7 +3304,7 @@ mod derived_property {
};
}
pure fn XID_Continue(c: char) -> bool {
pub pure fn XID_Continue(c: char) -> bool {
return match c {
'\x30' .. '\x39'
| '\x41' .. '\x5a'
@ -4176,7 +4175,7 @@ mod derived_property {
};
}
pure fn XID_Start(c: char) -> bool {
pub pure fn XID_Start(c: char) -> bool {
return match c {
'\x41' .. '\x5a'
| '\x61' .. '\x7a'

View file

@ -5,25 +5,25 @@ Miscellaneous helpers for common patterns.
*/
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
// tjc: re-forbid deprecated modes after snapshot
#[forbid(deprecated_pattern)];
use cmp::Eq;
/// The identity function.
#[inline(always)]
pure fn id<T>(+x: T) -> T { move x }
pub pure fn id<T>(x: T) -> T { move x }
/// Ignores a value.
#[inline(always)]
pure fn ignore<T>(+_x: T) { }
pub pure fn ignore<T>(_x: T) { }
/// Sets `*ptr` to `new_value`, invokes `op()`, and then restores the
/// original value of `*ptr`.
#[inline(always)]
fn with<T: Copy, R>(
pub fn with<T: Copy, R>(
ptr: &mut T,
+new_value: T,
new_value: T,
op: &fn() -> R) -> R
{
// NDM: if swap operator were defined somewhat differently,
@ -41,7 +41,7 @@ fn with<T: Copy, R>(
* deinitialising or copying either one.
*/
#[inline(always)]
fn swap<T>(x: &mut T, y: &mut T) {
pub fn swap<T>(x: &mut T, y: &mut T) {
*x <-> *y;
}
@ -50,19 +50,19 @@ fn swap<T>(x: &mut T, y: &mut T) {
* value, without deinitialising or copying either one.
*/
#[inline(always)]
fn replace<T>(dest: &mut T, +src: T) -> T {
pub fn replace<T>(dest: &mut T, src: T) -> T {
let mut tmp <- src;
swap(dest, &mut tmp);
move tmp
}
/// A non-copyable dummy type.
struct NonCopyable {
pub struct NonCopyable {
i: (),
drop { }
}
fn NonCopyable() -> NonCopyable { NonCopyable { i: () } }
pub fn NonCopyable() -> NonCopyable { NonCopyable { i: () } }
/**
A utility function for indicating unreachable code. It will fail if
@ -88,7 +88,7 @@ fn choose_weighted_item(v: &[Item]) -> Item {
~~~
*/
fn unreachable() -> ! {
pub fn unreachable() -> ! {
fail ~"internal error: entered unreachable code";
}

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,5 @@
// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];
// tjc: forbid deprecated modes again after snap
/**
* Concurrency-enabled mechanisms for sharing mutable and/or immutable state
* between tasks.
@ -12,14 +11,9 @@ use private::{SharedMutableState, shared_mutable_state,
use sync::{Mutex, mutex_with_condvars,
RWlock, rwlock_with_condvars};
export ARC, clone, get;
export Condvar;
export MutexARC, mutex_arc_with_condvars, unwrap_mutex_arc;
export RWARC, rw_arc_with_condvars, RWWriteMode, RWReadMode;
export unwrap_rw_arc;
/// As sync::condvar, a mechanism for unlock-and-descheduling and signalling.
struct Condvar { is_mutex: bool, failed: &mut bool, cond: &sync::Condvar }
pub struct Condvar { is_mutex: bool, failed: &mut bool, cond: &sync::Condvar }
impl &Condvar {
/// Atomically exit the associated ARC and block until a signal is sent.
@ -72,7 +66,7 @@ impl &Condvar {
struct ARC<T: Const Send> { x: SharedMutableState<T> }
/// Create an atomically reference counted wrapper.
fn ARC<T: Const Send>(+data: T) -> ARC<T> {
pub fn ARC<T: Const Send>(data: T) -> ARC<T> {
ARC { x: unsafe { shared_mutable_state(move data) } }
}
@ -80,7 +74,7 @@ fn ARC<T: Const Send>(+data: T) -> ARC<T> {
* Access the underlying data in an atomically reference counted
* wrapper.
*/
fn get<T: Const Send>(rc: &a/ARC<T>) -> &a/T {
pub fn get<T: Const Send>(rc: &a/ARC<T>) -> &a/T {
unsafe { get_shared_immutable_state(&rc.x) }
}
@ -91,7 +85,7 @@ fn get<T: Const Send>(rc: &a/ARC<T>) -> &a/T {
* object. However, one of the `arc` objects can be sent to another task,
* allowing them to share the underlying data.
*/
fn clone<T: Const Send>(rc: &ARC<T>) -> ARC<T> {
pub fn clone<T: Const Send>(rc: &ARC<T>) -> ARC<T> {
ARC { x: unsafe { clone_shared_mutable_state(&rc.x) } }
}
@ -104,7 +98,7 @@ fn clone<T: Const Send>(rc: &ARC<T>) -> ARC<T> {
* unwrap from a task that holds another reference to the same ARC; it is
* guaranteed to deadlock.
*/
fn unwrap<T: Const Send>(+rc: ARC<T>) -> T {
fn unwrap<T: Const Send>(rc: ARC<T>) -> T {
let ARC { x: x } <- rc;
unsafe { unwrap_shared_mutable_state(move x) }
}
@ -119,14 +113,14 @@ struct MutexARCInner<T: Send> { lock: Mutex, failed: bool, data: T }
struct MutexARC<T: Send> { x: SharedMutableState<MutexARCInner<T>> }
/// Create a mutex-protected ARC with the supplied data.
fn MutexARC<T: Send>(+user_data: T) -> MutexARC<T> {
pub fn MutexARC<T: Send>(user_data: T) -> MutexARC<T> {
mutex_arc_with_condvars(move user_data, 1)
}
/**
* Create a mutex-protected ARC with the supplied data and a specified number
* of condvars (as sync::mutex_with_condvars).
*/
fn mutex_arc_with_condvars<T: Send>(+user_data: T,
pub fn mutex_arc_with_condvars<T: Send>(user_data: T,
num_condvars: uint) -> MutexARC<T> {
let data =
MutexARCInner { lock: mutex_with_condvars(num_condvars),
@ -197,7 +191,7 @@ impl<T: Send> &MutexARC<T> {
* Will additionally fail if another task has failed while accessing the arc.
*/
// FIXME(#2585) make this a by-move method on the arc
fn unwrap_mutex_arc<T: Send>(+arc: MutexARC<T>) -> T {
pub fn unwrap_mutex_arc<T: Send>(arc: MutexARC<T>) -> T {
let MutexARC { x: x } <- arc;
let inner = unsafe { unwrap_shared_mutable_state(move x) };
let MutexARCInner { failed: failed, data: data, _ } <- inner;
@ -253,14 +247,14 @@ struct RWARC<T: Const Send> {
}
/// Create a reader/writer ARC with the supplied data.
fn RWARC<T: Const Send>(+user_data: T) -> RWARC<T> {
pub fn RWARC<T: Const Send>(user_data: T) -> RWARC<T> {
rw_arc_with_condvars(move user_data, 1)
}
/**
* Create a reader/writer ARC with the supplied data and a specified number
* of condvars (as sync::rwlock_with_condvars).
*/
fn rw_arc_with_condvars<T: Const Send>(+user_data: T,
pub fn rw_arc_with_condvars<T: Const Send>(user_data: T,
num_condvars: uint) -> RWARC<T> {
let data =
RWARCInner { lock: rwlock_with_condvars(num_condvars),
@ -340,7 +334,7 @@ impl<T: Const Send> &RWARC<T> {
* }
* ~~~
*/
fn write_downgrade<U>(blk: fn(+v: RWWriteMode<T>) -> U) -> U {
fn write_downgrade<U>(blk: fn(v: RWWriteMode<T>) -> U) -> U {
let state = unsafe { get_shared_mutable_state(&self.x) };
do borrow_rwlock(state).write_downgrade |write_mode| {
check_poison(false, state.failed);
@ -350,7 +344,7 @@ impl<T: Const Send> &RWARC<T> {
}
/// To be called inside of the write_downgrade block.
fn downgrade(+token: RWWriteMode/&a<T>) -> RWReadMode/&a<T> {
fn downgrade(token: RWWriteMode/&a<T>) -> RWReadMode/&a<T> {
// The rwlock should assert that the token belongs to us for us.
let state = unsafe { get_shared_immutable_state(&self.x) };
let RWWriteMode((data, t, _poison)) <- token;
@ -375,7 +369,7 @@ impl<T: Const Send> &RWARC<T> {
* in write mode.
*/
// FIXME(#2585) make this a by-move method on the arc
fn unwrap_rw_arc<T: Const Send>(+arc: RWARC<T>) -> T {
pub fn unwrap_rw_arc<T: Const Send>(arc: RWARC<T>) -> T {
let RWARC { x: x, _ } <- arc;
let inner = unsafe { unwrap_shared_mutable_state(move x) };
let RWARCInner { failed: failed, data: data, _ } <- inner;
@ -396,10 +390,10 @@ fn borrow_rwlock<T: Const Send>(state: &r/mut RWARCInner<T>) -> &r/RWlock {
// FIXME (#3154) ice with struct/&<T> prevents these from being structs.
/// The "write permission" token used for RWARC.write_downgrade().
enum RWWriteMode<T: Const Send> =
pub enum RWWriteMode<T: Const Send> =
(&mut T, sync::RWlockWriteMode, PoisonOnFail);
/// The "read permission" token used for RWARC.write_downgrade().
enum RWReadMode<T:Const Send> = (&T, sync::RWlockReadMode);
pub enum RWReadMode<T:Const Send> = (&T, sync::RWlockReadMode);
impl<T: Const Send> &RWWriteMode<T> {
/// Access the pre-downgrade RWARC in write mode.
@ -648,7 +642,7 @@ mod tests {
let mut children = ~[];
for 5.times {
let arc3 = ~arc.clone();
do task::task().future_result(|+r| vec::push(children, r)).spawn {
do task::task().future_result(|+r| children.push(r)).spawn {
do arc3.read |num| {
assert *num >= 0;
}
@ -676,7 +670,7 @@ mod tests {
let mut reader_convos = ~[];
for 10.times {
let ((rc1,rp1),(rc2,rp2)) = (pipes::stream(),pipes::stream());
vec::push(reader_convos, (rc1,rp2));
reader_convos.push((rc1,rp2));
let arcn = ~arc.clone();
do task::spawn {
rp1.recv(); // wait for downgrader to give go-ahead
@ -719,7 +713,7 @@ mod tests {
// send to other readers
for vec::each(reader_convos) |x| {
match *x {
(rc, _) => rc.send(()),
(ref rc, _) => rc.send(()),
}
}
}
@ -728,7 +722,7 @@ mod tests {
// complete handshake with other readers
for vec::each(reader_convos) |x| {
match *x {
(_, rp) => rp.recv(),
(_, ref rp) => rp.recv(),
}
}
wc1.send(()); // tell writer to try again

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