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

This commit is contained in:
Simon BD 2012-10-22 18:33:41 -05:00
commit cc0f2c6bb2
401 changed files with 11020 additions and 10248 deletions

View file

@ -41,6 +41,7 @@ Erick Tryzelaar <erick.tryzelaar@gmail.com>
Erik Rose <erik@mozilla.com>
Evan McClanahan <evan@evanmcc.com>
Francisco Souza <f@souza.cc>
Gabriel <g2p.code@gmail.com>
Gareth Daniel Smith <garethdanielsmith@gmail.com>
Glenn Willen <gwillen@nerdnet.org>
Gonçalo Cabrita <_@gmcabrita.com>
@ -49,6 +50,7 @@ Grahame Bowland <grahame@angrygoats.net>
Haitao Li <lihaitao@gmail.com>
Ian D. Bollinger <ian.bollinger@gmail.com>
Ivano Coppola <rgbfirefox@gmail.com>
Jacob Harris Cryer Kragh <jhckragh@gmail.com>
Jacob Parker <j3parker@csclub.uwaterloo.ca>
Jason Orendorff <jorendorff@mozilla.com>
Jed Davis <jld@panix.com>
@ -71,7 +73,9 @@ Kevin Cantu <me@kevincantu.org>
Lennart Kudling
Lindsey Kuper <lindsey@rockstargirl.org>
Luca Bruno <lucab@debian.org>
Luqman Aden <laden@csclub.uwaterloo.ca>
Magnus Auvinen <magnus.auvinen@gmail.com>
Mahmut Bulut <mahmutbulut0@gmail.com>
Margaret Meyerhofer <mmeyerho@andrew.cmu.edu>
Marijn Haverbeke <marijnh@gmail.com>
Matt Brubeck <mbrubeck@limpet.net>

View file

@ -132,7 +132,7 @@ LIBSYNTAX_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,syntax)
# version-string calculation
CFG_GIT_DIR := $(CFG_SRC_DIR).git
CFG_RELEASE = 0.4
CFG_RELEASE = 0.5
CFG_VERSION = $(CFG_RELEASE)
ifneq ($(wildcard $(CFG_GIT)),)
@ -144,8 +144,9 @@ ifneq ($(wildcard $(CFG_GIT_DIR)),)
endif
endif
ifdef CFG_DISABLE_VALGRIND
$(info cfg: disabling valgrind (CFG_DISABLE_VALGRIND))
ifdef CFG_ENABLE_VALGRIND
$(info cfg: enabling valgrind (CFG_ENABLE_VALGRIND))
else
CFG_VALGRIND :=
endif
ifdef CFG_BAD_VALGRIND

View file

@ -6,52 +6,61 @@ documentation.
## Installation
The Rust compiler is slightly unusual in that it is written in Rust and
therefore must be built by a precompiled "snapshot" version of itself (made in
an earlier state of development). As such, source builds require that:
The Rust compiler currently must be built from a [tarball], unless you
are on Windows, in which case using the [installer][win-exe] is
recommended.
* You are connected to the internet, to fetch snapshots.
Since the Rust compiler is written in Rust, it must be built by
a precompiled "snapshot" version of itself (made in an earlier state
of development). As such, source builds require a connection to
the Internet, to fetch snapshots, and an OS that can execute the
available snapshot binaries.
* You can at least execute snapshot binaries of one of the forms we offer
them in. Currently we build and test snapshots on:
Snapshot binaries are currently built and tested on several platforms:
* Windows (7, server 2008 r2) x86 only
* Linux 2.6.x (various distributions) x86 and x86-64
* OSX 10.6 ("Snow Leopard") or 10.7 ("Lion") x86 and x86-64
* Windows (7, Server 2008 R2), x86 only
* Linux (various distributions), x86 and x86-64
* OSX 10.6 ("Snow Leopard") or greater, x86 and x86-64
You may find other platforms work, but these are our "tier 1" supported build
environments that are most likely to work. Further platforms will be added to
the list in the future via cross-compilation.
You may find that other platforms work, but these are our "tier 1"
supported build environments that are most likely to work.
To build from source you will also need the following prerequisite packages:
> ***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 precise details of which are not discussed here.
To build from source you will also need the following prerequisite
packages:
* g++ 4.4 or clang++ 3.x
* python 2.6 or later
* python 2.6 or later (but not 3.x)
* perl 5.0 or later
* gnu make 3.81 or later
* curl
Assuming you're on a relatively modern Linux/OSX system and have met the
prerequisites, something along these lines should work:
Assuming you're on a relatively modern *nix system and have met the
prerequisites, something along these lines should work.
$ wget http://dl.rust-lang.org/dist/rust-0.4.tar.gz
$ tar -xzf rust-0.4.tar.gz
$ cd rust-0.4
$ ./configure
$ make && make install
When complete, make install will place the following programs into
/usr/local/bin:
You may need to use `sudo make install` if you do not normally have
permission to modify the destination directory. The install locations
can be adjusted by passing a `--prefix` argument to
`configure`. Various other options are also supported, pass `--help`
for more information on them.
* 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.
In addition to a manual page under /usr/local/share/man and a set of host and
target libraries under /usr/local/lib/rustc.
The install locations can be adjusted by passing a --prefix argument to
configure. Various other options are also supported, pass --help for more
information on them.
[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
[win-exe]: http://dl.rust-lang.org/dist/rust-0.4-install.exe
## License

View file

@ -1,7 +1,7 @@
Version 0.4 (October 2012)
--------------------------
* ~1500 changes, numerous bugfixes
* ~2000 changes, numerous bugfixes
* Syntax
* All keywords are now strict and may not be used as identifiers anywhere

28
configure vendored
View file

@ -187,6 +187,7 @@ need_cmd cmp
need_cmd mkdir
need_cmd printf
need_cmd cut
need_cmd head
need_cmd grep
need_cmd xargs
need_cmd cp
@ -257,6 +258,16 @@ case $CFG_CPUTYPE in
err "unknown CPU type: $CFG_CPUTYPE"
esac
# Detect 64 bit linux systems with 32 bit userland and force 32 bit compilation
if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ]
then
file -L "$SHELL" | grep -q "x86[_-]64"
if [ $? != 0 ]; then
CFG_CPUTYPE=i686
fi
fi
DEFAULT_HOST_TRIPLE="${CFG_CPUTYPE}-${CFG_OSTYPE}"
CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
@ -283,7 +294,7 @@ else
fi
opt sharedstd 1 "build libstd as a shared library"
opt valgrind 1 "run tests with valgrind (memcheck by default)"
opt valgrind 0 "run tests with valgrind (memcheck by default)"
opt helgrind 0 "run tests with helgrind instead of memcheck"
opt docs 1 "build documentation"
opt optimize 1 "build optimized rust code"
@ -352,11 +363,16 @@ fi
if [ ! -z "$CFG_PANDOC" ]
then
PV=$(pandoc --version | awk '/^pandoc/ {print $2}')
if [ "$PV" \< "1.8" ]
PANDOC_VER_LINE=$(pandoc --version | grep '^pandoc ')
PANDOC_VER=${PANDOC_VER_LINE#pandoc }
PV_MAJOR_MINOR=${PANDOC_VER%.[0-9]*}
PV_MAJOR=${PV_MAJOR_MINOR%%[.][0-9]*}
PV_MINOR=${PV_MAJOR_MINOR#[0-9]*[.]}
PV_MINOR=${PV_MINOR%%[.][0-9]*}
if [ "$PV_MAJOR" -lt "1" ] || [ "$PV_MINOR" -lt "8" ]
then
step_msg "pandoc $PV is too old. disabling"
BAD_PANDOC=1
step_msg "pandoc $PV_MAJOR.$PV_MINOR is too old. disabling"
BAD_PANDOC=1
fi
fi
@ -579,7 +595,7 @@ then
need_ok "git failed"
msg "git: submodule foreach sync"
"${CFG_GIT}" submodule --quiet foreach --recursive git submodule sync
"${CFG_GIT}" submodule --quiet foreach --recursive 'if test -e .gitmodules; then git submodule sync; fi'
need_ok "git failed"
msg "git: submodule foreach update"

View file

@ -9,7 +9,7 @@ CodeMirror.defineMode("rust", function() {
"as": "op", "true": "atom", "false": "atom", "assert": "op", "check": "op",
"claim": "op", "extern": "ignore", "unsafe": "ignore", "import": "else-style",
"export": "else-style", "copy": "op", "log": "op",
"use": "op", "self": "atom"
"use": "op", "self": "atom", "pub": "atom", "priv": "atom"
};
var typeKeywords = function() {
var keywords = {"fn": "fn"};

File diff suppressed because it is too large Load diff

View file

@ -2,32 +2,32 @@
# Introduction
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 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
pointers are being used safely. Another advantage of borrowed pointers
is that they are invisible to the garbage collector, so working with
borrowed pointers helps keep things efficient.
Borrowed pointers are one of the more flexible and powerful tools available in
Rust. A borrowed pointer can point anywhere: into the managed or exchange
heap, into the stack, and even into the interior of another data structure. A
borrowed pointer is as flexible as a C pointer or C++ reference. However,
unlike C and C++ compilers, the Rust compiler includes special static checks
that ensure that programs use borrowed pointers safely. Another advantage of
borrowed pointers is that they are invisible to the garbage collector, so
working with borrowed pointers helps reduce the overhead of automatic memory
management.
Despite the fact that they are completely safe, at runtime, a borrowed
pointer is “just a pointer”. They introduce zero overhead. All safety
checks are done at compilation time.
Despite their complete safety, a borrowed pointer's representation at runtime
is the same as that of an ordinary pointer in a C program. They introduce zero
overhead. The compiler does all safety checks at compile time.
Although borrowed pointers have rather elaborate theoretical
underpinnings (region pointers), the core concepts will be familiar to
anyone who worked with C or C++. Therefore, the best way to explain
anyone who has worked with C or C++. Therefore, the best way to explain
how they are used—and their limitations—is probably just to work
through several examples.
# By example
Borrowed pointers are called borrowed because they are only valid for
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.
Borrowed pointers are called *borrowed* because they are only valid for
a limited duration. Borrowed pointers never claim any kind of ownership
over the data that they point to: instead, they are used for cases
where you would like to use data for a short time.
As an example, consider a simple struct type `Point`:
@ -35,7 +35,7 @@ As an example, consider a simple struct type `Point`:
struct Point {x: float, y: float}
~~~
We can use this simple definition to allocate points in many ways. For
We can use this simple definition to allocate points in many different ways. For
example, in this code, each of these three local variables contains a
point, but allocated in a different place:
@ -46,17 +46,17 @@ 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
between any two points, no matter where they were stored. For example,
we might like to compute the distance between `on_the_stack` and
`shared_box`, or between `shared_box` and `unique_box`. One option is
to define a function that takes two arguments of type point—that is,
it takes the points by value. But this will cause the points to be
copied when we call the function. For points, this is probably not so
bad, but often copies are expensive or, worse, if there are mutable
fields, they can change the semantics of your program. So wed like to
define a function that takes the points by pointer. We can use
borrowed pointers to do this:
Suppose we wanted to write a procedure that computed the distance between any
two points, no matter where they were stored. For example, we might like to
compute the distance between `on_the_stack` and `shared_box`, or between
`shared_box` and `unique_box`. One option is to define a function that takes
two arguments of type `Point`—that is, it takes the points by value. But we
define it this way, calling the function will cause the points to be
copied. For points, this is probably not so bad, but often copies are
expensive. Worse, if the data type contains mutable fields, copying can change
the semantics of your program in unexpected ways. So we'd like to define a
function that takes the points by pointer. We can use borrowed pointers to do
this:
~~~
# struct Point {x: float, y: float}
@ -80,28 +80,28 @@ 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
Here, the `&` operator takes the address of the variable
`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.
`on_the_stack`, because we have created an alias: that is, another
name for 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
contents of the shared/unique box is being lent out.
In contrast, we can pass the boxes `shared_box` and `unique_box` to
`compute_distance` directly. The compiler automatically converts a box like
`@Point` or `~Point` to a borrowed pointer like `&Point`. This is another form
of borrowing: in this case, the caller lends the contents of the shared or
unique box to the callee.
Whenever a value is borrowed, there are some limitations on what you
can do with the original. For example, if the contents of a variable
have been lent out, you cannot send that variable to another task, nor
will you be permitted to take actions that might cause the borrowed
value to be freed or to change its type (Ill get into what kinds of
actions those are shortly). This rule should make intuitive sense: you
must wait for a borrowed value to be returned (that is, for the
borrowed pointer to go out of scope) before you can make full use of
it again.
Whenever a caller lends data to a callee, there are some limitations on what
the caller can do with the original. For example, if the contents of a
variable have been lent out, you cannot send that variable to another task. In
addition, the compiler will reject any code that might cause the borrowed
value to be freed or overwrite its component fields with values of different
types (I'll get into what kinds of actions those are shortly). This rule
should make intuitive sense: you must wait for a borrower to return the value
that you lent it (that is, wait for the borrowed pointer to go out of scope)
before you can make full use of it again.
# Other uses for the & operator
@ -112,10 +112,10 @@ In the previous example, the value `on_the_stack` was defined like so:
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
explicitly take the address of `on_the_stack` to get a borrowed
pointer. Sometimes however it is more convenient to move the &
operator into the definition of `on_the_stack`:
This declaration means that code can only pass `Point` by value to other
functions. As a consequence, we had to explicitly take the address of
`on_the_stack` to get a borrowed pointer. Sometimes however it is more
convenient to move the & operator into the definition of `on_the_stack`:
~~~
# struct Point {x: float, y: float}
@ -123,7 +123,8 @@ 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:
shorthand for creating a temporary and taking its address. A more verbose
way to write the same code is:
~~~
# struct Point {x: float, y: float}
@ -134,7 +135,7 @@ let on_the_stack2 : &Point = &tmp;
# 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
local variables. It can also take the address of fields or
individual array elements. For example, consider this type definition
for `rectangle`:
@ -144,7 +145,7 @@ 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:
Now, as before, we can define rectangles in a few different ways:
~~~
# struct Point {x: float, y: float}
@ -158,8 +159,8 @@ 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:
In each case, we can extract out individual subcomponents with the `&`
operator. For example, I could write:
~~~
# struct Point {x: float, y: float} // as before
@ -173,29 +174,31 @@ compute_distance(&rect_stack.origin, &rect_managed.origin);
~~~
which would borrow the field `origin` from the rectangle on the stack
from the managed box and then compute the distance between them.
as well as from the managed box, and then compute the distance between them.
# Borrowing managed boxes and rooting
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
Weve seen a few examples so far of borrowing heap boxes, both managed
and unique. 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
issues that C has with dangling pointers (and we do!), a compile-time
safety check is required.
is simply a pointer, nothing more. Therefore, avoiding C's problems
with dangling pointers requires a compile-time safety check.
The basis for the check is the notion of _lifetimes_. A lifetime is
basically a static approximation of the period in which the pointer is
valid: it always corresponds to some expression or block within the
program. Within that expression, the pointer can be used freely, but
if the pointer somehow leaks outside of that expression, the compiler
will report an error. Well be discussing lifetimes more in the
examples to come, and a more thorough introduction is also available.
The basis for the check is the notion of _lifetimes_. A lifetime is a
static approximation of the span of execution during which the pointer
is valid: it always corresponds to some expression or block within the
program. Code inside that expression can use the pointer without
restrictions. But if the pointer escapes from that expression (for
example, if the expression contains an assignment expression that
assigns the pointer to a mutable field of a data structure with a
broader scope than the pointer itself), the compiler reports an
error. We'll be discussing lifetimes more in the examples to come, and
a more thorough introduction is also available.
When a borrowed pointer is created, the compiler must ensure that it
will remain valid for its entire lifetime. Sometimes this is
relatively easy, such as when taking the address of a local variable
or a field that is stored on the stack:
When the `&` operator creates a borrowed pointer, the compiler must
ensure that the pointer remains valid for its entire
lifetime. Sometimes this is 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 }
@ -206,12 +209,12 @@ fn example1() {
} // -+
~~~
Here, the lifetime of the borrowed pointer is simply L, the remainder
of the function body. No extra work is required to ensure that `x.f`
will not be freed. This is true even if `x` is mutated.
Here, the lifetime of the borrowed pointer `y` is simply L, the
remainder of the function body. The compiler need not do any other
work to prove that code will not free `x.f`. This is true even if the
code mutates `x`.
The situation gets more complex when borrowing data that resides in
heap boxes:
The situation gets more complex when borrowing data inside heap boxes:
~~~
# struct X { f: int }
@ -222,20 +225,25 @@ fn example2() {
} // -+
~~~
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 managed box would become
unrooted and therefore be subject to garbage collection
In this example, the value `x` is a heap box, and `y` is therefore a
pointer into that heap box. Again the lifetime of `y` is L, the
remainder of the function body. But there is a crucial difference:
suppose `x` were to be reassigned during the lifetime L? If the
compiler isn't careful, the managed box could become *unrooted*, and
would therefore be subject to garbage collection. A heap box that is
unrooted is one such that no pointer values in the heap point to
it. It would violate memory safety for the box that was originally
assigned to `x` to be garbage-collected, since a non-heap
pointer---`y`---still points into it.
> ***Note:***In our current implementation, the garbage collector is
> implemented using reference counting and cycle detection.
> ***Note:*** Our current implementation implements the garbage collector
> using reference counting and cycle detection.
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 managed box remains live for the entire
lifetime. So, the above example would be compiled as:
For this reason, whenever an `&` expression borrows the interior of a
managed box stored in a mutable location, the compiler inserts a
temporary that ensures that the managed box remains live for the
entire lifetime. So, the above example would be compiled as if it were
written
~~~
# struct X { f: int }
@ -254,9 +262,9 @@ process is called *rooting*.
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.
borrow. Unfortunately, rooting does not work for borrows of unique
boxes, because it is not possible to have two references to a unique
box.
For unique boxes, therefore, the compiler will only allow a borrow *if
the compiler can guarantee that the unique box will not be reassigned
@ -279,14 +287,14 @@ fn example3() -> int {
~~~
Here, as before, the interior of the variable `x` is being borrowed
and `x` is declared as mutable. However, the compiler can clearly see
that `x` is not assigned anywhere in the lifetime L of the variable
and `x` is declared as mutable. However, the compiler can prove that
`x` is not assigned anywhere in the lifetime L of the variable
`y`. Therefore, it accepts the function, even though `x` is mutable
and in fact is mutated later in the function.
It may not be clear why we are so concerned about the variable which
was borrowed being mutated. The reason is that unique boxes are freed
_as soon as their owning reference is changed or goes out of
It may not be clear why we are so concerned about mutating a borrowed
variable. The reason is that the runtime system frees any unique box
_as soon as its owning reference changes or goes out of
scope_. Therefore, a program like this is illegal (and would be
rejected by the compiler):
@ -331,11 +339,11 @@ Once the reassignment occurs, the memory will look like this:
Here you can see that the variable `y` still points at the old box,
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 structs, and the compiler will still be
able to detect possible mutations:
In fact, the compiler can apply the same kind of reasoning to any
memory that is _(uniquely) owned by the stack frame_. So we could
modify the previous example to introduce additional unique pointers
and structs, and the compiler will still be able to detect possible
mutations:
~~~ {.xfail-test}
fn example3() -> int {
@ -352,11 +360,11 @@ fn example3() -> int {
In this case, two errors are reported, one when the variable `x` is
modified and another when `x.f` is modified. Either modification would
cause the pointer `y` to be invalidated.
invalidate the pointer `y`.
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:
Things get trickier when the unique box is not uniquely owned by the
stack frame, or when there is no way for the compiler to determine the
box's owner. Consider a program like this:
~~~
struct R { g: int }
@ -380,18 +388,18 @@ 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
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
inn unique fields, as in the following example:
In this case, the owning reference to the value being borrowed is
`x.f`. Moreover, `x.f` is both mutable and *aliasable*. Aliasable
means that there may be other pointers to that same managed box, so
even if the compiler were to prove an absence of mutations to `x.f`,
code could mutate `x.f` indirectly by changing an alias of
`x`. Therefore, to be safe, the compiler only accepts *pure* actions
during the lifetime of `y`. We define what "pure" means in the section
on [purity](#purity).
Besides ensuring purity, the only way to borrow the interior of a
unique found in aliasable memory is to ensure that it is stored within
unique fields, as in the following example:
unique found in aliasable memory is to ensure that the borrowed field
itself is also unique, as in the following example:
~~~
struct R { g: int }
@ -408,7 +416,7 @@ the compiler to know that, even if aliases to `x` exist, the field `f`
cannot be changed and hence the unique box `g` will remain valid.
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
it, one option is to use the swap operator to move that unique box
onto your stack:
~~~
@ -429,22 +437,21 @@ fn example5c(x: @S) -> int {
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.
won't be accessing that same box for the duration of the loan. Also,
it is sometimes 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 the targets of valid outstanding loans. Introducing
the block restricts the scope of `y`, making the move legal.
# Borrowing and enums
The previous example showed that borrowing unique boxes found in
aliasable, mutable memory is not permitted, so as to prevent pointers
into freed memory. There is one other case where the compiler must be
very careful to ensure that pointers remain valid: pointers into the
interior of an enum.
The previous example showed that the type system forbids any borrowing
of unique boxes found in aliasable, mutable memory. This restriction
prevents pointers from pointing into freed memory. There is one other
case where the compiler must be very careful to ensure that pointers
remain valid: pointers into the interior of an `enum`.
As an example, lets look at the following `shape` type that can
represent both rectangles and circles:
@ -458,9 +465,9 @@ enum Shape {
}
~~~
Now I might write a function to compute the area of a shape. This
function takes a borrowed pointer to a shape to avoid the need of
copying them.
Now we might write a function to compute the area of a shape. This
function takes a borrowed pointer to a shape, to avoid the need for
copying.
~~~
# struct Point {x: float, y: float}; // as before
@ -478,21 +485,21 @@ fn compute_area(shape: &Shape) -> float {
}
~~~
The first case matches against circles. Here the radius is extracted
from the shape variant and used to compute the area of the circle
(Like any up-to-date engineer, we use the [tau circle constant][tau]
and not that dreadfully outdated notion of pi).
The first case matches against circles. Here, the pattern extracts the
radius from the shape variant and the action uses it to compute the
area of the circle. (Like any up-to-date engineer, we use the [tau
circle constant][tau] and not that dreadfully outdated notion of pi).
[tau]: http://www.math.utah.edu/~palais/pi.html
The second match is more interesting. Here we match against a
rectangle and extract its size: but rather than copy the `size` struct,
we use a by-reference binding to create a pointer to it. In other
words, a pattern binding like `ref size` in fact creates a pointer of
type `&size` into the _interior of the enum_.
rectangle and extract its size: but rather than copy the `size`
struct, we use a by-reference binding to create a pointer to it. In
other words, a pattern binding like `ref size` binds the name `size`
to a pointer of type `&size` into the _interior of the enum_.
To make this more clear, lets look at a diagram of how things are
laid out in memory in the case where `shape` points at a rectangle:
To make this more clear, let's look at a diagram of memory layout in
the case where `shape` points at a rectangle:
~~~ {.notrust}
Stack Memory
@ -516,8 +523,8 @@ the shape.
Perhaps you can see where the danger lies: if the shape were somehow
to be reassigned, perhaps to a circle, then although the memory used
to store that shape value would still be valid, _it would have a
different type_! This is shown in the following diagram, depicting what
the state of memory would be if shape were overwritten with a circle:
different type_! The following diagram shows what memory would look
like if code overwrote `shape` with a circle:
~~~ {.notrust}
Stack Memory
@ -531,20 +538,23 @@ Stack Memory
+---------------+
~~~
As you can see, the `size` pointer would not be pointing at a `float` and
not a struct. This is not good.
As you can see, the `size` pointer would be pointing at a `float`
instead of a struct. This is not good: dereferencing the second field
of a `float` as if it were a struct with two fields would be a memory
safety violation.
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
memory containing a shape”. If however the type of that pointer were
`&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.
box: it must be able to guarantee that the `enum` will not be
overwritten for the duration of the borrow. In fact, the compiler
would accept the example we gave earlier. The example is safe because
the shape 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 be ill-typed. Just as with unique boxes, the compiler will
permit `ref` bindings into data owned by the stack frame even if the
data are mutable, but otherwise it requires that the data reside in
immutable memory.
> ***Note:*** Right now, pattern bindings not explicitly annotated
> with `ref` or `copy` use a special mode of "implicit by reference".
@ -553,11 +563,11 @@ otherwise it requires that the data reside in immutable memory.
# 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. It is also
possible to return borrowed pointers to the caller, but as we'll see
this requires some explicit annotation.
So far, all of the examples we've looked at use borrowed pointers in a
“downward” direction. That is, a method or code block creates a
borrowed pointer, then uses it within the same scope. It is also
possible to return borrowed pointers as the result of a function, but
as we'll see, doing so requires some explicit annotation.
For example, we could write a subroutine like this:
@ -566,23 +576,25 @@ 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. 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.
Here, the function `get_x()` returns a pointer into the structure it
was given. The type of the parameter (`&r/Point`) and return type
(`&r/float`) both use a new syntactic form that we have not seen so
far. Here the identifier `r` names the lifetime of the pointer
explicitly. So in effect, this function declares that it takes a
pointer with lifetime `r` and returns a pointer with that same
lifetime.
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.
are derived from a parameter to the procedure. In that case, the
pointer result will always have the same lifetime as one of the
parameters; named lifetimes indicate which parameter that
is.
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.
In the previous examples, function parameter types did not include a
lifetime name. In those examples, the compiler simply creates a fresh
name for the lifetime automatically: that is, the lifetime name is
guaranteed to refer to a distinct lifetime from the lifetimes of 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
@ -592,13 +604,13 @@ 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
In any case, whatever the lifetime of `r` is, the pointer produced by
`&p.x` always has the same lifetime as `p` itself: a pointer to a
field of a struct is valid as long as the struct is valid. Therefore,
the compiler is satisfied with the function `get_x()`.
the compiler accepts the function `get_x()`.
To drill in this point, lets look at a variation on the example, this
time one which does not compile:
To emphasize this point, lets look at a variation on the example, this
time one that does not compile:
~~~ {.xfail-test}
struct Point {x: float, y: float}
@ -610,22 +622,21 @@ fn get_x_sh(p: @Point) -> &float {
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
return a borrowed pointer that is valid for as long as the caller
would like: this is subtly different from the first example, which
promised to return a pointer that was valid for as long as the pointer
it was given.
caller). That means that `get_x_sh()` promises to return a borrowed
pointer that is valid for as long as the caller would like: this is
subtly different from the first example, which promised to return a
pointer that was valid for as long as its pointer argument was valid.
Within `get_x_sh()`, we see the expression `&p.x` which takes the
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
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.
address of a field of a managed box. The presence of this expression
implies that the compiler must guarantee that, so long as the
resulting pointer is valid, the 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 managed (or unique) box to create a
borrowed pointer, the pointer will only be valid within the function
@ -636,9 +647,9 @@ points at a static constant).
# Named lifetimes
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:
Let's look at named lifetimes in more detail. Named lifetimes allow
for grouping of parameters by lifetime. For example, consider this
function:
~~~
# struct Point {x: float, y: float}; // as before
@ -711,10 +722,10 @@ fn select<T>(shape: &tmp/Shape, threshold: float,
}
~~~
Here you can see the lifetime of shape is now being called `tmp`. The
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:
Here you can see that `shape`'s lifetime is now named `tmp`. The
parameters `a`, `b`, and the return value all have the lifetime `r`.
However, since the lifetime `tmp` is not returned, it would be more
concise to just omit the named lifetime for `shape` altogether:
~~~
# struct Point {x: float, y: float}; // as before
@ -735,17 +746,22 @@ This is equivalent to the previous definition.
# Purity
As mentioned before, the Rust compiler offers a kind of escape hatch
that permits borrowing of any data, but only if the actions that occur
that permits borrowing of any data, as long as the actions that occur
during the lifetime of the borrow are pure. Pure actions are those
which only modify data owned by the current stack frame. The compiler
that only modify data owned by the current stack frame. The compiler
can therefore permit arbitrary pointers into the heap, secure in the
knowledge that no pure action will ever cause them to become
invalidated (the compiler must still track data on the stack which is
borrowed and enforce those rules normally, of course).
borrowed and enforce those rules normally, of course). A pure function
in Rust is referentially transparent: it returns the same results
given the same (observably equivalent) inputs. That is because while
pure functions are allowed to modify data, they may only modify
*stack-local* data, which cannot be observed outside the scope of the
function itself. (Using an `unsafe` block invalidates this guarantee.)
Lets revisit a previous example and show how purity can affect the
compilers result. Here is `example5a()`, which borrows the interior of
a unique box found in an aliasable, mutable location, only now weve
Lets revisit a previous example and show how purity can affect
typechecking. Here is `example5a()`, which borrows the interior of a
unique box found in an aliasable, mutable location, only now weve
replaced the `...` with some specific code:
~~~
@ -757,8 +773,8 @@ fn example5a(x: @S ...) -> int {
}
~~~
The new code simply returns an incremented version of `y`. This clearly
doesnt do mutate anything in the heap, so the compiler is satisfied.
The new code simply returns an incremented version of `y`. This code
clearly doesn't mutate the heap, so the compiler is satisfied.
But suppose we wanted to pull the increment code into a helper, like
this:
@ -780,8 +796,8 @@ fn example5a(x: @S ...) -> int {
~~~
But now the compiler will report an error again. The reason is that it
only considers one function at a time (like most type checkers), and
so it does not know that `add_one()` only takes pure actions. We can
only considers one function at a time (like most typecheckers), and
so it does not know that `add_one()` consists of pure code. We can
help the compiler by labeling `add_one()` as pure:
~~~
@ -792,7 +808,7 @@ With this change, the modified version of `example5a()` will again compile.
# Conclusion
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
So there you have it: a (relatively) brief tour of the borrowed pointer
system. For more details, we refer to the (yet to be written) reference
document on borrowed pointers, which will explain the full notation
and give more examples.

View file

@ -2,17 +2,15 @@
# Introduction
One of Rust's aims, as a system programming language, is to
Because Rust is a systems programming language, one of its goals is to
interoperate well with C code.
We'll start with an example. It's a bit bigger than usual, and
contains a number of new concepts. We'll go over it one piece at a
time.
This is a program that uses OpenSSL's `SHA1` function to compute the
hash of its first command-line argument, which it then converts to a
hexadecimal string and prints to standard output. If you have the
OpenSSL libraries installed, it should 'just work'.
We'll start with an example, which is a bit bigger than usual. We'll
go over it one piece at a time. This is a program that uses OpenSSL's
`SHA1` function to compute the hash of its first command-line
argument, which it then converts to a hexadecimal string and prints to
standard output. If you have the OpenSSL libraries installed, it
should compile and run without any extra effort.
~~~~ {.xfail-test}
extern mod std;
@ -32,7 +30,7 @@ fn sha1(data: ~str) -> ~str unsafe {
let bytes = str::to_bytes(data);
let hash = crypto::SHA1(vec::raw::to_ptr(bytes),
vec::len(bytes) as c_uint, ptr::null());
return as_hex(vec::raw::from_buf(hash, 20u));
return as_hex(vec::from_buf(hash, 20));
}
fn main(args: ~[~str]) {
@ -42,26 +40,27 @@ fn main(args: ~[~str]) {
# Foreign modules
Before we can call `SHA1`, we have to declare it. That is what this
part of the program is responsible for:
Before we can call the `SHA1` function defined in the OpenSSL library, we have
to declare it. That is what this part of the program does:
~~~~ {.xfail-test}
extern mod crypto {
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8;
}
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8; }
~~~~
An `extern` module declaration containing function signatures introduces
the functions listed as _foreign functions_, that are implemented in some
other language (usually C) and accessed through Rust's foreign function
interface (FFI). An extern module like this is called a foreign module, and
implicitly tells the compiler to link with a library with the same name as
the module, and that it will find the foreign functions in that library.
An `extern` module declaration containing function signatures introduces the
functions listed as _foreign functions_. Foreign functions differ from regular
Rust functions in that they are implemented in some other language (usually C)
and called through Rust's foreign function interface (FFI). An extern module
like this is called a foreign module, and implicitly tells the compiler to
link with a library that contains the listed foreign functions, and has the
same name as the module.
In this case, it'll change the name `crypto` to a shared library name
in a platform-specific way (`libcrypto.so` on Linux, for example), and
link that in. If you want the module to have a different name from the
actual library, you can use the `"link_name"` attribute, like:
In this case, the Rust compiler changes the name `crypto` to a shared library
name in a platform-specific way (`libcrypto.so` on Linux, for example),
searches for the shared library with that name, and links the library into the
program. If you want the module to have a different name from the actual
library, you can use the `"link_name"` attribute, like:
~~~~ {.xfail-test}
#[link_name = "crypto"]
@ -72,11 +71,11 @@ extern mod something {
# Foreign calling conventions
Most foreign code will be C code, which usually uses the `cdecl` calling
Most foreign code is C code, which usually uses the `cdecl` calling
convention, so that is what Rust uses by default when calling foreign
functions. Some foreign functions, most notably the Windows API, use other
calling conventions, so Rust provides a way to hint to the compiler which
is expected by using the `"abi"` attribute:
calling conventions. Rust provides the `"abi"` attribute as a way to hint to
the compiler which calling convention to use:
~~~~
#[cfg(target_os = "win32")]
@ -86,14 +85,14 @@ extern mod kernel32 {
}
~~~~
The `"abi"` attribute applies to a foreign module (it can not be applied
The `"abi"` attribute applies to a foreign module (it cannot be applied
to a single function within a module), and must be either `"cdecl"`
or `"stdcall"`. Other conventions may be defined in the future.
or `"stdcall"`. We may extend the compiler in the future to support other
calling conventions.
# Unsafe pointers
The foreign `SHA1` function is declared to take three arguments, and
return a pointer.
The foreign `SHA1` function takes three arguments, and returns a pointer.
~~~~ {.xfail-test}
# extern mod crypto {
@ -104,21 +103,20 @@ fn SHA1(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
When declaring the argument types to a foreign function, the Rust
compiler has no way to check whether your declaration is correct, so
you have to be careful. If you get the number or types of the
arguments wrong, you're likely to get a segmentation fault. Or,
arguments wrong, you're likely to cause a segmentation fault. Or,
probably even worse, your code will work on one platform, but break on
another.
In this case, `SHA1` is defined as taking two `unsigned char*`
arguments and one `unsigned long`. The rust equivalents are `*u8`
In this case, we declare that `SHA1` takes two `unsigned char*`
arguments and one `unsigned long`. The Rust equivalents are `*u8`
unsafe pointers and an `uint` (which, like `unsigned long`, is a
machine-word-sized type).
Unsafe pointers can be created through various functions in the
standard lib, usually with `unsafe` somewhere in their name. You can
dereference an unsafe pointer with `*` operator, but use
caution—unlike Rust's other pointer types, unsafe pointers are
completely unmanaged, so they might point at invalid memory, or be
null pointers.
The standard library provides various functions to create unsafe pointers,
such as those in `core::cast`. Most of these functions have `unsafe` in their
name. You can dereference an unsafe pointer with the `*` operator, but use
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
@ -134,12 +132,12 @@ fn sha1(data: ~str) -> ~str {
let bytes = str::to_bytes(data);
let hash = crypto::SHA1(vec::raw::to_ptr(bytes),
vec::len(bytes), ptr::null());
return as_hex(vec::raw::from_buf(hash, 20u));
return as_hex(vec::from_buf(hash, 20));
}
}
~~~~
Firstly, what does the `unsafe` keyword at the top of the function
First, what does the `unsafe` keyword at the top of the function
mean? `unsafe` is a block modifier—it declares the block following it
to be known to be unsafe.
@ -158,8 +156,8 @@ advertise it to the world. An unsafe function is written like this:
unsafe fn kaboom() { ~"I'm harmless!"; }
~~~~
This function can only be called from an unsafe block or another
unsafe function.
This function can only be called from an `unsafe` block or another
`unsafe` function.
# Pointer fiddling
@ -179,35 +177,36 @@ Let's look at our `sha1` function again.
let bytes = str::to_bytes(data);
let hash = crypto::SHA1(vec::raw::to_ptr(bytes),
vec::len(bytes), ptr::null());
return as_hex(vec::raw::from_buf(hash, 20u));
return as_hex(vec::from_buf(hash, 20));
# }
# }
~~~~
The `str::to_bytes` function is perfectly safe: it converts a string to
a `[u8]`. This byte array is then fed to `vec::raw::to_ptr`, which
The `str::to_bytes` function is perfectly safe: it converts a string to a
`~[u8]`. The program then feeds this byte array to `vec::raw::to_ptr`, which
returns an unsafe pointer to its contents.
This pointer will become invalid as soon as the vector it points into
is cleaned up, so you should be very careful how you use it. In this
case, the local variable `bytes` outlives the pointer, so we're good.
This pointer will become invalid at the end of the scope in which the vector
it points to (`bytes`) is valid, so you should be very careful how you use
it. In this case, the local variable `bytes` outlives the pointer, so we're
good.
Passing a null pointer as the third argument to `SHA1` makes it use a
static buffer, and thus save us the effort of allocating memory
ourselves. `ptr::null` is a generic function that will return an
unsafe null pointer of the correct type (Rust generics are awesome
like thatthey can take the right form depending on the type that they
are expected to return).
ourselves. `ptr::null` is a generic function that, in this case, returns an
unsafe null pointer of type `*u8`. (Rust generics are awesome
like that: they can take the right form depending on the type that they
are expected to return.)
Finally, `vec::raw::from_buf` builds up a new `[u8]` from the
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
Finally, `vec::from_buf` builds up a new `~[u8]` from the
unsafe pointer that `SHA1` returned. SHA1 digests are always
twenty bytes long, so we can pass `20` for the length of the new
vector.
# Passing structures
C functions often take pointers to structs as arguments. Since Rust
structs are binary-compatible with C structs, Rust programs can call
`struct`s are binary-compatible with C structs, Rust programs can call
such functions directly.
This program uses the POSIX function `gettimeofday` to get a
@ -241,12 +240,12 @@ fn unix_time_in_microseconds() -> u64 unsafe {
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 struct type with the same contents, and declare
`gettimeofday` to take a pointer to such a struct.
In C, a `timeval` is a struct with two 32-bit integer fields. Thus, we
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
type. Since all null pointers have the same representation regardless of
their referent type, this is safe.
This program does not use the second argument to `gettimeofday` (the time
zone), so the `extern mod` declaration for it simply declares this argument
to be a pointer to the unit type (written `()`). Since all null pointers have
the same representation regardless of their referent type, this is safe.

View file

@ -2,10 +2,11 @@
# Introduction
Functions are the programmer's primary tool of abstraction, but there are
cases in which they are insufficient, because the programmer wants to
abstract over concepts not represented as values. Consider the following
example:
Functions are the primary tool that programmers can use to build abstractions.
Sometimes, however, programmers want to perform abstractions over things that are not
runtime values. Macros provide a syntactic abstraction. For an example of how this
can be useful, consider the following two code fragments, which both pattern-match
on their input and return early in one case, and do nothing otherwise:
~~~~
# enum t { special_a(uint), special_b(uint) };
@ -24,11 +25,12 @@ match input_2 {
# }
~~~~
This code could become tiresome if repeated many times. However, there is
no reasonable function that could be written to solve this problem. In such a
case, it's possible to define a macro to solve the problem. Macros are
This code could become tiresome if repeated many times. However, there is no
straightforward way to rewrite it without the repeated code, using functions
alone. There is a solution, though: defining a macro to solve the problem. Macros are
lightweight custom syntax extensions, themselves defined using the
`macro_rules!` syntax extension:
`macro_rules!` syntax extension. The following `early_return` macro captures
the pattern in the above code:
~~~~
# enum t { special_a(uint), special_b(uint) };
@ -50,48 +52,72 @@ early_return!(input_2 special_b);
# }
~~~~
Macros are defined in pattern-matching style:
Macros are defined in pattern-matching style: in the above example, the text
`($inp:expr $sp:ident)` that appears on the left-hand side of the `=>` is the
*macro invocation syntax*, a pattern denoting how to write a call to the
macro. The text on the right-hand side of the `=>`, beginning with `match
$inp`, is the *macro transcription syntax*: what the macro expands to.
# Invocation syntax
On the left-hand-side of the `=>` is the macro invocation syntax. It is
free-form, excepting the following rules:
The macro invocation syntax specifies the syntax for the arguments to the
macro. It appears on the left-hand side of the `=>` in a macro definition. It
conforms to the following rules:
1. It must be surrounded in parentheses.
1. It must be surrounded by parentheses.
2. `$` has special meaning.
3. The `()`s, `[]`s, and `{}`s it contains must balance. For example, `([)` is
forbidden.
Otherwise, the invocation syntax is free-form.
To take as an argument a fragment of Rust code, write `$` followed by a name
(for use on the right-hand side), followed by a `:`, followed by the sort of
fragment to match (the most common ones are `ident`, `expr`, `ty`, `pat`, and
`block`). Anything not preceded by a `$` is taken literally. The standard
(for use on the right-hand side), followed by a `:`, followed by a *fragment
specifier*. The fragment specifier denotes the sort of fragment to match. The
most common fragment specifiers are:
* `ident` (an identifier, referring to a variable or item. Examples: `f`, `x`,
`foo`.)
* `expr` (an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`;
`f(42)`.)
* `ty` (a type. Examples: `int`, `~[(char, ~str)]`, `&T`.)
* `pat` (a pattern, usually appearing in a `match` or on the left-hand side of
a declaration. Examples: `Some(t)`; `(17, 'a')`; `_`.)
* `block` (a sequence of actions. Example: `{ log(error, "hi"); return 12; }`)
The parser interprets any token that's not preceded by a `$` literally. Rust's usual
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 )))`.
So `($x:ident -> (($e:expr)))`, though excessively fancy, would designate a macro
that could be invoked like: `my_macro!(i->(( 2+2 )))`.
# 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
to transcribe.
except that a `$` need only be followed by the name of the syntactic fragment
to transcribe into the macro expansion; its type need not be repeated.
The right-hand side must be surrounded by delimiters of some kind, and must be
an expression; currently, user-defined macros can only be invoked in
expression position (even though `macro_rules!` itself can be in item
position).
The right-hand side must be enclosed by delimiters, and must be
an expression. Currently, invocations of user-defined macros can only appear in a context
where the Rust grammar requires an expression, even though `macro_rules!` itself can appear
in a context where the grammar requires an item.
# Multiplicity
## Invocation
Going back to the motivating example, suppose that we wanted each invocation
of `early_return` to potentially accept multiple "special" identifiers. The
syntax `$(...)*` accepts zero or more occurrences of its contents, much like
the Kleene star operator in regular expressions. It also supports a separator
token (a comma-separated list could be written `$(...),*`), and `+` instead of
`*` to mean "at least one".
Going back to the motivating example, recall that `early_return` expanded into
a `match` that would `return` if the `match`'s scrutinee matched the
"special case" identifier provided as the second argument to `early_return`,
and do nothing otherwise. Now suppose that we wanted to write a
version of `early_return` that could handle a variable number of "special"
cases.
The syntax `$(...)*` on the left-hand side of the `=>` in a macro definition
accepts zero or more occurrences of its contents. It works much
like the `*` operator in regular expressions. It also supports a
separator token (a comma-separated list could be written `$(...),*`), and `+`
instead of `*` to mean "at least one".
~~~~
# enum t { special_a(uint),special_b(uint),special_c(uint),special_d(uint)};
@ -118,37 +144,40 @@ early_return!(input_2, [special_b]);
### Transcription
As the above example demonstrates, `$(...)*` is also valid on the right-hand
side of a macro definition. The behavior of Kleene star in transcription,
especially in cases where multiple stars are nested, and multiple different
side of a macro definition. The behavior of `*` in transcription,
especially in cases where multiple `*`s are nested, and multiple different
names are involved, can seem somewhat magical and intuitive at first. The
system that interprets them is called "Macro By Example". The two rules to
keep in mind are (1) the behavior of `$(...)*` is to walk through one "layer"
of repetitions for all of the `$name`s it contains in lockstep, and (2) each
`$name` must be under at least as many `$(...)*`s as it was matched against.
If it is under more, it'll will be repeated, as appropriate.
If it is under more, it'll be repeated, as appropriate.
## Parsing limitations
The parser used by the macro system is reasonably powerful, but the parsing of
Rust syntax is restricted in two ways:
1. The parser will always parse as much as possible. For example, if the comma
were omitted from the syntax of `early_return!` above, `input_1 [` would've
been interpreted as the beginning of an array index. In fact, invoking the
macro would have been impossible.
2. The parser must have eliminated all ambiguity by the time it reaches a
`$name:fragment_specifier`. This most often affects them when they occur in
the beginning of, or immediately after, a `$(...)*`; requiring a distinctive
token in front can solve the problem.
For technical reasons, there are two limitations to the treatment of syntax
fragments by the macro parser:
1. The parser will always parse as much as possible of a Rust syntactic
fragment. For example, if the comma were omitted from the syntax of
`early_return!` above, `input_1 [` would've been interpreted as the beginning
of an array index. In fact, invoking the macro would have been impossible.
2. The parser must have eliminated all ambiguity by the time it reaches a
`$name:fragment_specifier` declaration. This limitation can result in parse
errors when declarations occur at the beginning of, or immediately after,
a `$(...)*`. For example, the grammar `$($t:ty)* $e:expr` will always fail to
parse because the parser would be forced to choose between parsing `t` and
parsing `e`. Changing the invocation syntax to require a distinctive token in
front can solve the problem. In the above example, `$(T $t:ty)* E $e:exp`
solves the problem.
## A final note
Macros, as currently implemented, are not for the faint of heart. Even
ordinary syntax errors can be more difficult to debug when they occur inside
a macro, and errors caused by parse problems in generated code can be very
ordinary syntax errors can be more difficult to debug when they occur inside a
macro, and errors caused by parse problems in generated code can be very
tricky. Invoking the `log_syntax!` macro can help elucidate intermediate
states, using `trace_macros!(true)` will automatically print those
intermediate states out, and using `--pretty expanded` as an argument to the
compiler will show the result of expansion.
states, invoking `trace_macros!(true)` will automatically print those
intermediate states out, and passing the flag `--pretty expanded` as a
command-line argument to the compiler will show the result of expansion.

View file

@ -2,40 +2,41 @@
# Introduction
The Rust language is designed from the ground up to support pervasive
The designers of Rust designed the language from the ground up to support pervasive
and safe concurrency through lightweight, memory-isolated tasks and
message passing.
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.
Rust tasks are not the same as traditional threads: rather, they are more like
_green threads_. The Rust runtime system schedules tasks cooperatively onto a
small number of operating system threads. Because tasks are significantly
cheaper to create than traditional threads, Rust can create hundreds of
thousands of concurrent tasks on a typical 32-bit system.
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.
Tasks provide failure isolation and recovery. When an exception occurs in Rust
code (as a result of an explicit call to `fail`, an assertion failure, or
another invalid operation), the runtime system destroys the entire
task. Unlike in languages such as Java and C++, there is no way to `catch` an
exception. Instead, tasks may monitor each other for failure.
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.
Rust tasks have dynamically sized stacks. A task begins its life with a small
amount of stack space (currently in the low thousands of bytes, depending on
platform), and acquires more stack as needed. Unlike in languages such as C, a
Rust task cannot run off the end of the stack. However, tasks do have a stack
budget. If a Rust task exceeds its stack budget, then it will fail safely:
with a checked exception.
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_.
Tasks use Rust's type system to provide strong memory safety guarantees. In
particular, the type system guarantees that tasks cannot share mutable state
with each other. Tasks communicate with each other by transferring _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
This tutorial explains the basics of tasks and communication in Rust,
explores some typical patterns in concurrent Rust code, and finally
discusses some of the more unusual synchronization types in the standard
library.
> ***Warning:*** This tutorial is incomplete
## A note about the libraries
While Rust's type system provides the building blocks needed for safe
@ -43,23 +44,23 @@ 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 removed 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.
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, we will remove the existing `core::comm` API
and move the user-facing portions of `core::pipes` to `core::comm`. In this
tutorial, we discuss `pipes` and ignore the `comm` API.
For your reference, these are the standard modules involved in Rust
concurrency at the moment.
concurrency at this writing.
* [`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::arc`] - The ARC (atomic reference counted) type, for safely sharing
immutable data
* [`std::par`] - Some basic tools for implementing parallel algorithms
[`core::task`]: core/task.html
@ -72,11 +73,11 @@ concurrency at the moment.
# 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.
The programming interface for creating and managing tasks lives
in the `task` module of the `core` library, and is thus available to all
Rust code by default. At its simplest, creating a task is a matter of
calling the `spawn` function with a closure argument. `spawn` executes the
closure in the new task.
~~~~
# use io::println;
@ -95,17 +96,17 @@ do spawn {
}
~~~~
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.
In Rust, there is nothing special about creating tasks: a task is not a
concept that appears in the language semantics. Instead, Rust's type system
provides all the tools necessary to implement safe concurrency: particularly,
_owned types_. The language leaves the implementation details to the core
library.
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
contain 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
execution. Like any closure, the function passed to `spawn` may capture
an environment that it carries across tasks.
~~~
@ -121,8 +122,8 @@ do spawn {
}
~~~
By default tasks will be multiplexed across the available cores, running
in parallel, thus on a multicore machine, running the following code
By default, the scheduler multiplexes tasks across the available cores, running
in parallel. Thus, on a multicore machine, running the following code
should interleave the output in vaguely random order.
~~~
@ -143,17 +144,16 @@ 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.
A pipe is simply a pair of endpoints: one for sending messages and another for
receiving messages. Pipes are low-level communication building-blocks and so
come in a variety of forms, each one appropriate for a different use case. In
what follows, we cover the most commonly used varieties.
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 receiving
endpoint. Consider the following example of performing two calculations
concurrently.
function to create a `(Chan, Port)` pair. In Rust parlance, a *channel*
is a sending endpoint of a pipe, and a *port* is the receiving
endpoint. Consider the following example of calculating two results
concurrently:
~~~~
use task::spawn;
@ -161,7 +161,7 @@ use pipes::{stream, Port, Chan};
let (chan, port): (Chan<int>, Port<int>) = stream();
do spawn {
do spawn |move chan| {
let result = some_expensive_computation();
chan.send(result);
}
@ -172,17 +172,17 @@ let result = port.recv();
# fn some_other_expensive_computation() {}
~~~~
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).
Let's examine this example in detail. First, the `let` statement creates a
stream for sending and receiving integers (the left-hand side of the `let`,
`(chan, port)`, is an example of a *destructuring let*: the pattern separates
a tuple into its component parts).
~~~~
# use pipes::{stream, Chan, Port};
let (chan, port): (Chan<int>, Port<int>) = stream();
~~~~
The channel will be used by the child task to send data to the parent task,
The child task will use the channel to send data to the parent task,
which will wait to receive the data on the port. The next statement
spawns the child task.
@ -192,20 +192,20 @@ spawns the child task.
# use pipes::{stream, Port, Chan};
# fn some_expensive_computation() -> int { 42 }
# let (chan, port) = stream();
do spawn {
do spawn |move chan| {
let result = some_expensive_computation();
chan.send(result);
}
~~~~
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.
Notice that the creation of the task closure transfers `chan` to the child
task implicitly: the closure captures `chan` in its environment. Both `Chan`
and `Port` are sendable types and may be captured into tasks or otherwise
transferred between them. In the example, the child task runs 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
Finally, the parent continues with some other expensive
computation, then waits for the child's result to arrive on the
port:
~~~~
@ -217,12 +217,11 @@ some_other_expensive_computation();
let result = port.recv();
~~~~
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:
The `Port` and `Chan` pair created by `stream` enables efficient communication
between a single sender and a single receiver, but multiple senders cannot use
a single `Chan`, and multiple receivers cannot use a single `Port`. What if our
example needed to computer multiple results across a number of tasks? The
following program is ill-typed:
~~~ {.xfail-test}
# use task::{spawn};
@ -230,7 +229,7 @@ be written:
# fn some_expensive_computation() -> int { 42 }
let (chan, port) = stream();
do spawn {
do spawn |move chan| {
chan.send(some_expensive_computation());
}
@ -254,7 +253,7 @@ 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 {
do spawn |move child_chan| {
child_chan.send(some_expensive_computation(init_val));
}
}
@ -263,18 +262,18 @@ 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.
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 with `Chan`, though, the programmer
may duplicate a `SharedChan`, 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
illustrate the point. For reference, written with multiple streams, it
might look like the example below.
~~~
@ -284,10 +283,10 @@ might look like the example below.
// 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 {
do spawn |move chan| {
chan.send(some_expensive_computation(init_val));
}
port
move port
};
// Wait on each port, accumulating the results
@ -295,19 +294,19 @@ 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.
Rust has a built-in mechanism for raising exceptions. The `fail` construct
(which can also be written with an error string as an argument: `fail
~reason`) and the `assert` construct (which effectively calls `fail` if a
boolean expression is false) are both ways to raise exceptions. When a task
raises an exception the task unwinds its stack---running destructors and
freeing memory along the way---and then exits. Unlike exceptions in 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 intertwined, and if one fails so do all of them.
All tasks are, by default, _linked_ to each other. That means that the fates
of all tasks are intertwined: if one fails, so do all the others.
~~~
# use task::spawn;
@ -321,11 +320,15 @@ 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.
While it isn't possible for a task to recover from failure, tasks may notify
each other of failure. 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. `try` returns a value of type `Result<int,
()>`. `Result` is an `enum` type with two variants: `Ok` and `Err`. In this
case, because the type arguments to `Result` are `int` and `()`, callers can
pattern-match on a result to check whether it's an `Ok` result with an `int`
field (representing a successful result) or an `Err` result (representing
termination with an error).
~~~
# fn some_condition() -> bool { false }
@ -349,8 +352,8 @@ 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
> value (`try` always returns `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
@ -362,11 +365,11 @@ 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_.
proceed). Hence, you will need different _linked failure modes_.
## Failure modes
By default, task failure is _bidirectionally linked_, which means if
By default, task failure is _bidirectionally linked_, which means that if
either task dies, it kills the other one.
~~~
@ -382,8 +385,8 @@ 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
If you want parent tasks to be able to kill their children, but do not want a
parent to die automatically if one of its child task dies, 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
@ -395,13 +398,13 @@ before returning. Hence:
# fn sleep_forever() { loop { task::yield() } }
# do task::try {
let (sender, receiver): (Chan<int>, Port<int>) = stream();
do spawn { // Bidirectionally linked
do spawn |move receiver| { // 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
do try |move sender| { // Unidirectionally linked
sender.send(42);
sleep_forever(); // Will get woken up by force
}
@ -411,7 +414,7 @@ do try { // Unidirectionally linked
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
if any child fails. On the other hand, if the _parent_ (supervisor) fails,
then there is nothing the children can do to recover, so they should
also fail.
@ -451,23 +454,16 @@ fail;
# };
~~~
# 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
function `std::comm::DuplexStream()` supports this pattern. We'll
look briefly at how it is used.
look briefly at how to use it.
To see how `spawn_conversation()` works, we will create a child task
that receives `uint` messages, converts them to a string, and sends
the string in response. The child terminates when `0` is received.
that repeatedly receives a `uint` message, converts it to a string, and sends
the string in response. The child terminates when it receives `0`.
Here is the function that implements the child task:
~~~~
@ -477,8 +473,8 @@ fn stringifier(channel: &DuplexStream<~str, uint>) {
let mut value: uint;
loop {
value = channel.recv();
channel.send(uint::to_str(value, 10u));
if value == 0u { break; }
channel.send(uint::to_str(value, 10));
if value == 0 { break; }
}
}
~~~~
@ -488,7 +484,7 @@ receiving. The `stringifier` function takes a `DuplexStream` that can
send strings (the first type parameter) and receive `uint` messages
(the second type parameter). The body itself simply loops, reading
from the channel and then sending its response back. The actual
response itself is simply the strified version of the received value,
response itself is simply the stringified version of the received value,
`uint::to_str(value)`.
Here is the code for the parent task:
@ -509,15 +505,15 @@ Here is the code for the parent task:
let (from_child, to_child) = DuplexStream();
do spawn || {
do spawn |move to_child| {
stringifier(&to_child);
};
from_child.send(22u);
from_child.send(22);
assert from_child.recv() == ~"22";
from_child.send(23u);
from_child.send(0u);
from_child.send(23);
from_child.send(0);
assert from_child.recv() == ~"23";
assert from_child.recv() == ~"0";
@ -525,6 +521,8 @@ 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.
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.

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
.TH RUSTC "1" "July 2012" "rustc 0.3" "User Commands"
.TH RUSTC "1" "October 2012" "rustc 0.4" "User Commands"
.SH NAME
rustc \- rust compiler
.SH SYNOPSIS
@ -42,6 +42,9 @@ Compile a library crate
\fB\-\-ls\fR
List the symbols defined by a compiled library crate
.TP
\fB\-\-jit\fR
Execute using JIT (experimental)
.TP
\fB\-\-no\-trans\fR
Run all passes except translation; no output
.TP
@ -62,9 +65,9 @@ Parse only; do not compile, assemble, or link
.TP
\fB\-\-pretty\fR [type]
Pretty\-print the input instead of compiling;
valid types are: \fBnormal\fR (un\-annotated source),
\fBexpanded\fR (crates expanded), \fBtyped\fR (crates expanded,
with type annotations), or \fBidentified\fR (fully
valid types are: normal (un\-annotated source),
expanded (crates expanded), typed (crates expanded,
with type annotations), or identified (fully
parenthesized, AST nodes and blocks with IDs)
.TP
\fB\-S\fR
@ -75,7 +78,8 @@ Write intermediate files (.bc, .opt.bc, .o)
in addition to normal output
.TP
\fB\-\-static\fR
Use or produce static libraries or binaries (experimental)
Use or produce static libraries or binaries
(experimental)
.TP
\fB\-\-sysroot\fR <path>
Override the system root
@ -84,24 +88,16 @@ 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 <\fBhttp://sources.redhat.com/autobook/autobook/autobook_17.html\fR> for
detail)
Target cpu\-manufacturer\-kernel[\-os] to compile for
(default: host triple)
(see http://sources.redhat.com/autobook/autobook/
autobook_17.html for detail)
.TP
\fB\-W\fR <foo>
enable warning <foo>
\fB\-W help\fR
Print 'lint' options and default settings
.TP
\fB\-W\fR no\-<foo>
disable warning <foo>
.TP
\fB\-W\fR err\-<foo>
enable warning <foo> as an error
.TP
\fB\-W\fR help
Print available warnings and default settings
.TP
\fB\-Z\fR help
list internal options for debugging rustc
\fB\-Z help\fR
Print internal options for debugging rustc
.TP
\fB\-v\fR \fB\-\-version\fR
Print version info and exit
@ -117,11 +113,12 @@ 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 issues.
.SH "AUTHOR"
See \fBAUTHORS.txt\fR in the rust source distribution. Graydon Hoare
<\fIgraydon@mozilla.com\fR> is the project leader.
.SH "COPYRIGHT"
See \fBLICENSE.txt\fR in the rust source distribution.
This work is licensed under MIT-like terms. See \fBLICENSE.txt\fR
in the rust source distribution.

View file

@ -19,6 +19,10 @@ CFG_GCCISH_CFLAGS += -fno-omit-frame-pointer
# embedded into the executable, so use a no-op command.
CFG_DSYMUTIL := true
# Add a dSYM glob for all platforms, even though it will do nothing on
# non-Darwin platforms; omitting it causes a full -R copy of lib/
CFG_LIB_DSYM_GLOB=lib$(1)-*.dylib.dSYM
ifneq ($(findstring freebsd,$(CFG_OSTYPE)),)
CFG_LIB_NAME=lib$(1).so
CFG_LIB_GLOB=lib$(1)-*.so
@ -77,7 +81,6 @@ endif
ifneq ($(findstring darwin,$(CFG_OSTYPE)),)
CFG_LIB_NAME=lib$(1).dylib
CFG_LIB_GLOB=lib$(1)-*.dylib
CFG_LIB_DSYM_GLOB=lib$(1)-*.dylib.dSYM
CFG_UNIXY := 1
CFG_LDENV := DYLD_LIBRARY_PATH
CFG_GCCISH_LINK_FLAGS += -dynamiclib -lpthread -framework CoreServices -Wl,-no_compact_unwind

View file

@ -10,7 +10,7 @@
// End:
#[link(name = "cargo",
vers = "0.4",
vers = "0.5",
uuid = "9ff87a04-8fed-4295-9ff8-f99bb802650b",
url = "https://github.com/mozilla/rust/tree/master/src/cargo")];
@ -27,10 +27,10 @@
#[allow(deprecated_mode)];
#[allow(deprecated_pattern)];
extern mod core(vers = "0.4");
extern mod std(vers = "0.4");
extern mod rustc(vers = "0.4");
extern mod syntax(vers = "0.4");
extern mod core(vers = "0.5");
extern mod std(vers = "0.5");
extern mod rustc(vers = "0.5");
extern mod syntax(vers = "0.5");
use core::*;

View file

@ -705,7 +705,7 @@ fn configure(opts: Options) -> Cargo {
~" or package manager to get it to work correctly");
}
c
move c
}
fn for_each_package(c: &Cargo, b: fn(s: @Source, p: &Package)) {
@ -1162,20 +1162,20 @@ fn sync_one_file(c: &Cargo, dir: &Path, src: @Source) -> bool {
}
match (src.key, src.keyfp) {
(Some(_), Some(f)) => {
let r = pgp::verify(&c.root, &pkgfile, &sigfile, f);
let r = pgp::verify(&c.root, &pkgfile, &sigfile);
if !r {
error(fmt!("signature verification failed for source %s",
name));
error(fmt!("signature verification failed for source %s with \
key %s", name, f));
return false;
}
if has_src_file {
let e = pgp::verify(&c.root, &srcfile, &srcsigfile, f);
let e = pgp::verify(&c.root, &srcfile, &srcsigfile);
if !e {
error(fmt!("signature verification failed for source %s",
name));
error(fmt!("signature verification failed for source %s \
with key %s", name, f));
return false;
}
}
@ -1273,21 +1273,21 @@ fn sync_one_git(c: &Cargo, dir: &Path, src: @Source) -> bool {
}
match (src.key, src.keyfp) {
(Some(_), Some(f)) => {
let r = pgp::verify(&c.root, &pkgfile, &sigfile, f);
let r = pgp::verify(&c.root, &pkgfile, &sigfile);
if !r {
error(fmt!("signature verification failed for source %s",
name));
error(fmt!("signature verification failed for source %s with \
key %s", name, f));
rollback(name, dir, false);
return false;
}
if has_src_file {
let e = pgp::verify(&c.root, &srcfile, &srcsigfile, f);
let e = pgp::verify(&c.root, &srcfile, &srcsigfile);
if !e {
error(fmt!("signature verification failed for source %s",
name));
error(fmt!("signature verification failed for source %s \
with key %s", name, f));
rollback(name, dir, false);
return false;
}
@ -1370,11 +1370,11 @@ fn sync_one_curl(c: &Cargo, dir: &Path, src: @Source) -> bool {
return false;
}
let r = pgp::verify(&c.root, &pkgfile, &sigfile, f);
let r = pgp::verify(&c.root, &pkgfile, &sigfile);
if !r {
error(fmt!("signature verification failed for source %s",
name));
error(fmt!("signature verification failed for source %s with \
key %s", name, f));
return false;
}
@ -1390,11 +1390,11 @@ fn sync_one_curl(c: &Cargo, dir: &Path, src: @Source) -> bool {
return false;
}
let e = pgp::verify(&c.root, &srcfile, &srcsigfile, f);
let e = pgp::verify(&c.root, &srcfile, &srcsigfile);
if !e {
error(~"signature verification failed for " +
~"source " + name);
~"source " + name + ~" with key " + f);
return false;
}
}
@ -1463,8 +1463,7 @@ fn cmd_init(c: &Cargo) {
return;
}
let r = pgp::verify(&c.root, &srcfile, &sigfile,
pgp::signing_key_fp());
let r = pgp::verify(&c.root, &srcfile, &sigfile);
if !r {
error(fmt!("signature verification failed for '%s'",
srcfile.to_str()));
@ -1615,10 +1614,10 @@ fn dump_sources(c: &Cargo) {
_ => ()
}
hash.insert(copy k, json::Object(chash));
hash.insert(copy k, json::Object(move chash));
}
json::to_writer(writer, &json::Object(hash))
json::to_writer(writer, &json::Object(move hash))
}
result::Err(e) => {
error(fmt!("could not dump sources: %s", e));

View file

@ -1,5 +1,5 @@
fn gpg(args: ~[~str]) -> { status: int, out: ~str, err: ~str } {
return run::program_output(~"gpg", args);
fn gpgv(args: ~[~str]) -> { status: int, out: ~str, err: ~str } {
return run::program_output(~"gpgv", args);
}
fn signing_key() -> ~str {
@ -59,7 +59,7 @@ fn signing_key_fp() -> ~str {
}
fn supported() -> bool {
let r = gpg(~[~"--version"]);
let r = gpgv(~[~"--version"]);
r.status == 0
}
@ -88,15 +88,14 @@ fn add(root: &Path, key: &Path) {
}
}
fn verify(root: &Path, data: &Path, sig: &Path, keyfp: ~str) -> bool {
fn verify(root: &Path, data: &Path, sig: &Path) -> bool {
let path = root.push("gpg");
let p = gpg(~[~"--homedir", path.to_str(),
~"--with-fingerprint",
~"--verify", sig.to_str(),
data.to_str()]);
let res = ~"Primary key fingerprint: " + keyfp;
for str::split_char_each(p.err, '\n') |line| {
if line == res { return true; }
let res = gpgv(~[~"--homedir", path.to_str(),
~"--keyring", ~"pubring.gpg",
~"--verbose",
sig.to_str(), data.to_str()]);
if res.status != 0 {
return false;
}
return false;
return true;
}

View file

@ -8,8 +8,8 @@
#[allow(deprecated_mode)];
#[allow(deprecated_pattern)];
extern mod core(vers = "0.4");
extern mod std(vers = "0.4");
extern mod core(vers = "0.5");
extern mod std(vers = "0.5");
use core::*;

View file

@ -145,7 +145,7 @@ fn make_tests(config: config) -> ~[test::TestDesc] {
tests.push(make_test(config, file))
}
}
return tests;
move tests
}
fn is_test(config: config, testfile: &Path) -> bool {

View file

@ -60,12 +60,12 @@ fn run(lib_path: ~str,
writeclose(pipe_in.out, input);
let p = pipes::PortSet();
let ch = p.chan();
do task::spawn_sched(task::SingleThreaded) {
do task::spawn_sched(task::SingleThreaded) |move ch| {
let errput = readclose(pipe_err.in);
ch.send((2, errput));
}
let ch = p.chan();
do task::spawn_sched(task::SingleThreaded) {
do task::spawn_sched(task::SingleThreaded) |move ch| {
let output = readclose(pipe_out.in);
ch.send((1, output));
}

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "language.dtd">
<language name="Rust" version="0.3.1" kateversion="2.4" section="Sources" extensions="*.rs;*.rc" mimetype="text/x-rust" priority="15">
<language name="Rust" version="0.4.0" kateversion="2.4" section="Sources" extensions="*.rs;*.rc" mimetype="text/x-rust" priority="15">
<highlighting>
<list name="fn">
<item> fn </item>
@ -9,59 +9,39 @@
<item> type </item>
</list>
<list name="keywords">
<item> alt </item>
<item> again </item>
<item> as </item>
<item> assert </item>
<item> break </item>
<item> check </item>
<item> claim </item>
<item> const </item>
<item> copy </item>
<item> do </item>
<item> drop </item>
<item> else </item>
<item> enum </item>
<item> export </item>
<item> extern </item>
<item> f16 </item>
<item> f80 </item>
<item> f128 </item>
<item> fail </item>
<item> for </item>
<item> if </item>
<item> impl </item>
<item> import </item>
<item> in </item>
<item> let </item>
<item> log </item>
<item> loop </item>
<item> m32 </item>
<item> m64 </item>
<item> m128 </item>
<item> match </item>
<item> mod </item>
<item> module </item>
<item> move </item>
<item> mut </item>
<item> new </item>
<item> of </item>
<item> owned </item>
<item> priv </item>
<item> pub </item>
<item> pure </item>
<item> ret </item>
<item> ref </item>
<item> return </item>
<item> to </item>
<item> unchecked </item>
<item> static </item>
<item> struct </item>
<item> trait </item>
<item> unsafe </item>
<item> use </item>
<item> while </item>
<item> with </item>
<item> mod </item>
<item> trait </item>
<item> class </item>
<item> struct </item>
<item> enum </item>
</list>
<list name="types">
<item> bool </item>
@ -80,8 +60,9 @@
<item> float </item>
<item> char </item>
<item> str </item>
<item> option </item>
<item> either </item>
<item> Either </item>
<item> Option </item>
<item> Result </item>
</list>
<list name="ctypes">
<item> c_float </item>
@ -121,16 +102,16 @@
<list name="constants">
<item> true </item>
<item> false </item>
<item> some </item>
<item> none </item>
<item> left </item>
<item> right </item>
<item> ok </item>
<item> err </item>
<item> success </item>
<item> failure </item>
<item> cons </item>
<item> nil </item>
<item> Some </item>
<item> None </item>
<item> Left </item>
<item> Right </item>
<item> Ok </item>
<item> Err </item>
<item> Success </item>
<item> Failure </item>
<item> Cons </item>
<item> Nil </item>
</list>
<list name="cconstants">
<item> EXIT_FAILURE </item>

View file

@ -68,7 +68,7 @@ def parse_line(n, line):
match = re.match(r"([ST]) (\d{4}-\d{2}-\d{2}) ([a-fA-F\d]+)\s*$", line);
if (not match):
raise Exception("%s:%d:E syntax error" % (snapshotfile, n))
raise Exception("%s:%d:E syntax error: " % (snapshotfile, n))
return {"type": "snapshot",
"date": match.group(2),
"rev": match.group(3)}

View file

@ -12,9 +12,9 @@
#[allow(deprecated_mode)];
#[allow(deprecated_pattern)];
extern mod core(vers = "0.4");
extern mod std(vers = "0.4");
extern mod syntax(vers = "0.4");
extern mod core(vers = "0.5");
extern mod std(vers = "0.5");
extern mod syntax(vers = "0.5");
use core::*;

View file

@ -104,7 +104,7 @@ pure fn safe_to_use_expr(e: ast::expr, tm: test_mode) -> bool {
}
}
fn safe_to_steal_ty(t: @ast::ty, tm: test_mode) -> bool {
fn safe_to_steal_ty(t: @ast::Ty, tm: test_mode) -> bool {
// Restrictions happen to be the same.
safe_to_replace_ty(t.node, tm)
}
@ -119,16 +119,16 @@ fn stash_expr_if(c: fn@(@ast::expr, test_mode)->bool,
} else {/* now my indices are wrong :( */ }
}
fn stash_ty_if(c: fn@(@ast::ty, test_mode)->bool,
es: @mut ~[ast::ty],
e: @ast::ty,
fn stash_ty_if(c: fn@(@ast::Ty, test_mode)->bool,
es: @mut ~[ast::Ty],
e: @ast::Ty,
tm: test_mode) {
if c(e, tm) {
es.push(*e);
} else {/* now my indices are wrong :( */ }
}
type stolen_stuff = {exprs: ~[ast::expr], tys: ~[ast::ty]};
type stolen_stuff = {exprs: ~[ast::expr], tys: ~[ast::Ty]};
fn steal(crate: ast::crate, tm: test_mode) -> stolen_stuff {
let exprs = @mut ~[];
@ -195,7 +195,7 @@ fn replace_expr_in_crate(crate: ast::crate, i: uint,
// Replace the |i|th ty (in fold order) of |crate| with |newty|.
fn replace_ty_in_crate(crate: ast::crate, i: uint, newty: ast::ty,
fn replace_ty_in_crate(crate: ast::crate, i: uint, newty: ast::Ty,
tm: test_mode) -> ast::crate {
let j: @mut uint = @mut 0u;
fn fold_ty_rep(j_: @mut uint, i_: uint, newty_: ast::ty_,
@ -225,7 +225,7 @@ fn as_str(f: fn@(+x: io::Writer)) -> ~str {
io::with_str_writer(f)
}
fn check_variants_of_ast(crate: ast::crate, codemap: codemap::codemap,
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(),
@ -239,7 +239,7 @@ fn check_variants_of_ast(crate: ast::crate, codemap: codemap::codemap,
fn check_variants_T<T: Copy>(
crate: ast::crate,
codemap: codemap::codemap,
codemap: codemap::CodeMap,
filename: &Path,
thing_label: ~str,
things: ~[T],
@ -296,7 +296,7 @@ fn check_variants_T<T: Copy>(
}
fn last_part(filename: ~str) -> ~str {
let ix = option::get(&str::rfind_char(filename, '/'));
let ix = option::get(str::rfind_char(filename, '/'));
str::slice(filename, ix + 1u, str::len(filename) - 3u)
}
@ -444,7 +444,7 @@ fn parse_and_print(code: @~str) -> ~str {
fn has_raw_pointers(c: ast::crate) -> bool {
let has_rp = @mut false;
fn visit_ty(flag: @mut bool, t: @ast::ty) {
fn visit_ty(flag: @mut bool, t: @ast::Ty) {
match t.node {
ast::ty_ptr(_) => { *flag = true; }
_ => { }

View file

@ -122,9 +122,9 @@ pub mod tests {
pub fn test_transmute() {
unsafe {
let x = @1;
let x: *int = transmute(x);
let x: *int = transmute(move x);
assert *x == 1;
let _x: @int = transmute(x);
let _x: @int = transmute(move x);
}
}

View file

@ -142,7 +142,7 @@ pub unsafe fn annihilate() {
assert (*box).header.prev == null();
debug!("freeing box: %x", box as uint);
rt_free(transmute(box));
rt_free(transmute(move box));
}
}

View file

@ -12,7 +12,7 @@ use libc::c_double;
#[link_name = "m"]
#[abi = "cdecl"]
pub extern mod c_double {
pub extern mod c_double_utils {
// Alpabetically sorted by link_name
@ -87,7 +87,7 @@ pub extern mod c_double {
#[link_name = "m"]
#[abi = "cdecl"]
pub extern mod c_float {
pub extern mod c_float_utils {
// Alpabetically sorted by link_name

300
src/libcore/condition.rs Normal file
View file

@ -0,0 +1,300 @@
// helper for transmutation, shown below.
type RustClosure = (int,int);
struct Condition<T, U:Copy> {
key: task::local_data::LocalDataKey<Handler<T,U>>
}
struct Handler<T, U:Copy> {
handle: RustClosure
}
struct ProtectBlock<T, U:Copy> {
cond: &Condition<T, U>,
inner: RustClosure
}
struct Guard<T, U:Copy> {
cond: &Condition<T,U>,
prev: Option<@Handler<T, U>>,
drop {
match self.prev {
None => (),
Some(p) =>
unsafe {
debug!("Guard: popping handler from TLS");
task::local_data::local_data_set(self.cond.key, p)
}
}
}
}
struct HandleBlock<T, U:Copy> {
pb: &ProtectBlock<T,U>,
prev: Option<@Handler<T,U>>,
handler: @Handler<T,U>,
drop {
unsafe {
debug!("HandleBlock: pushing handler to TLS");
let _g = Guard { cond: self.pb.cond,
prev: self.prev };
task::local_data::local_data_set(self.pb.cond.key,
self.handler);
// transmutation to avoid copying non-copyable, should
// be fixable by tracking closure pointees in regionck.
let f : &fn() = ::cast::transmute(self.pb.inner);
debug!("HandleBlock: invoking protected code");
f();
debug!("HandleBlock: returned from protected code");
}
}
}
struct Trap<T, U:Copy> {
cond: &Condition<T,U>,
handler: @Handler<T, U>
}
impl<T, U: Copy> ProtectBlock<T,U> {
fn handle(&self, h: &self/fn(&T) ->U) -> HandleBlock/&self<T,U> {
unsafe {
debug!("ProtectBlock.handle: setting up handler block");
let p : *RustClosure = ::cast::transmute(&h);
let prev = task::local_data::local_data_get(self.cond.key);
HandleBlock { pb: self,
prev: prev,
handler: @Handler{handle: *p} }
}
}
}
impl<T, U: Copy> Trap<T,U> {
fn in<V: Copy>(&self, inner: &self/fn() -> V) -> V {
unsafe {
let prev = task::local_data::local_data_get(self.cond.key);
let _g = Guard { cond: self.cond,
prev: prev };
debug!("Trap: pushing handler to TLS");
task::local_data::local_data_set(self.cond.key, self.handler);
inner()
}
}
}
impl<T, U: Copy> Condition<T,U> {
fn guard(&self, h: &self/fn(&T) ->U) -> Guard/&self<T,U> {
unsafe {
let prev = task::local_data::local_data_get(self.key);
let g = Guard { cond: self, prev: prev };
debug!("Guard: pushing handler to TLS");
let p : *RustClosure = ::cast::transmute(&h);
let h = @Handler{handle: *p};
task::local_data::local_data_set(self.key, h);
move g
}
}
fn trap(&self, h: &self/fn(&T) ->U) -> Trap/&self<T,U> {
unsafe {
let p : *RustClosure = ::cast::transmute(&h);
let h = @Handler{handle: *p};
move Trap { cond: self, handler: h }
}
}
fn protect(&self, inner: &self/fn()) -> ProtectBlock/&self<T,U> {
unsafe {
// transmutation to avoid copying non-copyable, should
// be fixable by tracking closure pointees in regionck.
debug!("Condition.protect: setting up protected block");
let p : *RustClosure = ::cast::transmute(&inner);
ProtectBlock { cond: self,
inner: *p }
}
}
fn raise(t:&T) -> U {
unsafe {
match task::local_data::local_data_get(self.key) {
None => {
debug!("Condition.raise: found no handler");
fail
}
Some(handler) => {
debug!("Condition.raise: found handler");
let f : &fn(&T) -> U = ::cast::transmute(handler.handle);
f(t)
}
}
}
}
}
#[cfg(test)]
fn sadness_key(_x: @Handler<int,int>) { }
#[cfg(test)]
fn trouble(i: int) {
// Condition should work as a const, just limitations in consts.
let sadness_condition : Condition<int,int> =
Condition { key: sadness_key };
debug!("trouble: raising conition");
let j = sadness_condition.raise(&i);
debug!("trouble: handler recovered with %d", j);
}
#[test]
fn test1() {
let sadness_condition : Condition<int,int> =
Condition { key: sadness_key };
let mut i = 10;
let b = do sadness_condition.protect {
debug!("test1: in protected block");
trouble(1);
trouble(2);
trouble(3);
};
do b.handle |j| {
debug!("test1: in handler");
i += *j;
i
};
assert i == 16;
}
#[cfg(test)]
fn nested_test_inner() {
let sadness_condition : Condition<int,int> =
Condition { key: sadness_key };
let mut inner_trapped = false;
let b = do sadness_condition.protect {
debug!("nested_test_inner: in protected block");
trouble(1);
};
do b.handle |_j| {
debug!("nested_test_inner: in handler");
inner_trapped = true;
0
};
assert inner_trapped;
}
#[test]
fn nested_test_outer() {
let sadness_condition : Condition<int,int> =
Condition { key: sadness_key };
let mut outer_trapped = false;
let b = do sadness_condition.protect {
debug!("nested_test_outer: in protected block");
nested_test_inner();
trouble(1);
};
do b.handle |_j| {
debug!("nested_test_outer: in handler");
outer_trapped = true;
0
};
assert outer_trapped;
}
#[cfg(test)]
fn nested_guard_test_inner() {
let sadness_condition : Condition<int,int> =
Condition { key: sadness_key };
let mut inner_trapped = false;
let _g = do sadness_condition.guard |_j| {
debug!("nested_guard_test_inner: in handler");
inner_trapped = true;
0
};
debug!("nested_guard_test_inner: in protected block");
trouble(1);
assert inner_trapped;
}
#[test]
fn nested_guard_test_outer() {
let sadness_condition : Condition<int,int> =
Condition { key: sadness_key };
let mut outer_trapped = false;
let _g = do sadness_condition.guard |_j| {
debug!("nested_guard_test_outer: in handler");
outer_trapped = true;
0
};
debug!("nested_guard_test_outer: in protected block");
nested_guard_test_inner();
trouble(1);
assert outer_trapped;
}
#[cfg(test)]
fn nested_trap_test_inner() {
let sadness_condition : Condition<int,int> =
Condition { key: sadness_key };
let mut inner_trapped = false;
do sadness_condition.trap(|_j| {
debug!("nested_trap_test_inner: in handler");
inner_trapped = true;
0
}).in {
debug!("nested_trap_test_inner: in protected block");
trouble(1);
}
assert inner_trapped;
}
#[test]
fn nested_trap_test_outer() {
let sadness_condition : Condition<int,int> =
Condition { key: sadness_key };
let mut outer_trapped = false;
do sadness_condition.trap(|_j| {
debug!("nested_trap_test_outer: in handler");
outer_trapped = true; 0
}).in {
debug!("nested_guard_test_outer: in protected block");
nested_trap_test_inner();
trouble(1);
}
assert outer_trapped;
}

View file

@ -25,7 +25,7 @@ Implicitly, all crates behave as if they included the following prologue:
*/
#[link(name = "core",
vers = "0.4",
vers = "0.5",
uuid = "c70c24a7-5551-4f73-8e37-380b11d80be8",
url = "https://github.com/mozilla/rust/tree/master/src/libcore")];
@ -200,6 +200,7 @@ pub mod flate;
pub mod repr;
pub mod cleanup;
pub mod reflect;
pub mod condition;
// Modules supporting compiler-generated code
// Exported but not part of the public interface

View file

@ -11,8 +11,8 @@ pub use GenericPath = path::GenericPath;
pub use WindowsPath = path::WindowsPath;
pub use PosixPath = path::PosixPath;
pub use tuple::{TupleOps, ExtendedTupleOps};
pub use str::{StrSlice, UniqueStr};
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
pub use str::{StrSlice, Trimmable};
pub use vec::{ConstVector, CopyableVector, ImmutableVector};
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
pub use vec::{MutableVector, MutableCopyableVector};
@ -33,7 +33,7 @@ pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, BitAnd, BitOr, BitXor};
pub use ops::{Shl, Shr, Index};
#[cfg(test)]
extern mod coreops(name = "core", vers = "0.4");
extern mod coreops(name = "core", vers = "0.5");
#[cfg(test)]
pub use coreops::ops::{Const, Copy, Send, Owned};
@ -72,6 +72,6 @@ mod core {
// Similar to above. Some magic to make core testable.
#[cfg(test)]
mod std {
extern mod std(vers = "0.4");
extern mod std(vers = "0.5");
pub use std::test;
}

View file

@ -208,7 +208,7 @@ impl<T> DList<T> {
fn push_head_n(data: T) -> DListNode<T> {
let mut nobe = self.new_link(move data);
self.add_head(nobe);
option::get(&nobe)
option::get(nobe)
}
/// Add data to the tail of the list. O(1).
fn push(data: T) {
@ -221,7 +221,7 @@ impl<T> DList<T> {
fn push_n(data: T) -> DListNode<T> {
let mut nobe = self.new_link(move data);
self.add_tail(nobe);
option::get(&nobe)
option::get(nobe)
}
/**
* Insert data into the middle of the list, left of the given node.
@ -245,7 +245,7 @@ impl<T> DList<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)
option::get(nobe)
}
/**
* Insert data into the middle of the list, right of the given node.
@ -269,7 +269,7 @@ impl<T> DList<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)
option::get(nobe)
}
/// Remove a node from the head of the list. O(1).
@ -385,17 +385,17 @@ impl<T> DList<T> {
let mut link = self.peek_n();
let mut rabbit = link;
while option::is_some(&link) {
let nobe = option::get(&link);
let nobe = option::get(link);
assert nobe.linked;
// check cycle
if option::is_some(&rabbit) {
rabbit = option::get(&rabbit).next;
rabbit = option::get(rabbit).next;
}
if option::is_some(&rabbit) {
rabbit = option::get(&rabbit).next;
rabbit = option::get(rabbit).next;
}
if option::is_some(&rabbit) {
assert !box::ptr_eq(*option::get(&rabbit), *nobe);
assert !box::ptr_eq(*option::get(rabbit), *nobe);
}
// advance
link = nobe.next_link();
@ -406,17 +406,17 @@ impl<T> DList<T> {
link = self.peek_tail_n();
rabbit = link;
while option::is_some(&link) {
let nobe = option::get(&link);
let nobe = option::get(link);
assert nobe.linked;
// check cycle
if option::is_some(&rabbit) {
rabbit = option::get(&rabbit).prev;
rabbit = option::get(rabbit).prev;
}
if option::is_some(&rabbit) {
rabbit = option::get(&rabbit).prev;
rabbit = option::get(rabbit).prev;
}
if option::is_some(&rabbit) {
assert !box::ptr_eq(*option::get(&rabbit), *nobe);
assert !box::ptr_eq(*option::get(rabbit), *nobe);
}
// advance
link = nobe.prev_link();

View file

@ -56,7 +56,7 @@ pub enum DVec<A> {
}
/// Creates a new, empty dvec
pub fn DVec<A>() -> DVec<A> {
pub pure fn DVec<A>() -> DVec<A> {
DVec_({mut data: ~[]})
}

View file

@ -301,7 +301,7 @@ pub mod rt {
unsafe { str::unshift_char(&mut s, ' ') };
}
}
return unsafe { pad(cv, s, PadSigned) };
return unsafe { pad(cv, move s, PadSigned) };
}
pub pure fn conv_uint(cv: Conv, u: uint) -> ~str {
let prec = get_int_precision(cv);
@ -313,7 +313,7 @@ pub mod rt {
TyBits => uint_to_str_prec(u, 2u, prec),
TyOctal => uint_to_str_prec(u, 8u, prec)
};
return unsafe { pad(cv, rs, PadUnsigned) };
return unsafe { pad(cv, move rs, PadUnsigned) };
}
pub pure fn conv_bool(cv: Conv, b: bool) -> ~str {
let s = if b { ~"true" } else { ~"false" };
@ -323,20 +323,20 @@ pub mod rt {
}
pub pure fn conv_char(cv: Conv, c: char) -> ~str {
let mut s = str::from_char(c);
return unsafe { pad(cv, s, PadNozero) };
return unsafe { pad(cv, move s, PadNozero) };
}
pub pure fn conv_str(cv: Conv, s: &str) -> ~str {
// For strings, precision is the maximum characters
// displayed
let mut unpadded = match cv.precision {
CountImplied => s.to_unique(),
CountImplied => s.to_owned(),
CountIs(max) => if max as uint < str::char_len(s) {
str::substr(s, 0u, max as uint)
} else {
s.to_unique()
s.to_owned()
}
};
return unsafe { pad(cv, unpadded, PadNozero) };
return unsafe { pad(cv, move unpadded, PadNozero) };
}
pub pure fn conv_float(cv: Conv, f: float) -> ~str {
let (to_str, digits) = match cv.precision {
@ -351,7 +351,7 @@ pub mod rt {
s = ~" " + s;
}
}
return unsafe { pad(cv, s, PadFloat) };
return unsafe { pad(cv, move s, PadFloat) };
}
pub pure fn conv_poly<T>(cv: Conv, v: &T) -> ~str {
let s = sys::log_str(v);
@ -411,14 +411,14 @@ pub mod rt {
pub fn pad(cv: Conv, s: ~str, mode: PadMode) -> ~str {
let mut s = move s; // sadtimes
let uwidth : uint = match cv.width {
CountImplied => return s,
CountImplied => return (move 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 s; }
if uwidth <= strlen { return (move s); }
let mut padchar = ' ';
let diff = uwidth - strlen;
if have_flag(cv.flags, flag_left_justify) {

View file

@ -4,7 +4,7 @@
//! Operations and constants for `f32`
pub use cmath::c_float::*;
pub use cmath::c_float_utils::*;
pub use cmath::c_float_targ_consts::*;
// These are not defined inside consts:: for consistency with

View file

@ -4,7 +4,7 @@
//! Operations and constants for `f64`
pub use cmath::c_double::*;
pub use cmath::c_double_utils::*;
pub use cmath::c_double_targ_consts::*;
// FIXME (#1433): obtain these in a different way
@ -59,7 +59,7 @@ pub pure fn ge(x: f64, y: f64) -> bool { return x >= y; }
pub pure fn gt(x: f64, y: f64) -> bool { return x > y; }
pub pure fn sqrt(x: f64) -> f64 {
cmath::c_double::sqrt(x as libc::c_double) as f64
cmath::c_double_utils::sqrt(x as libc::c_double) as f64
}
/// Returns true if `x` is a positive number, including +0.0f640 and +Infinity

View file

@ -37,7 +37,7 @@ pub fn deflate_bytes(bytes: &[const u8]) -> ~[u8] {
ptr::addr_of(&outsz),
lz_norm);
assert res as int != 0;
let out = vec::raw::from_buf(res as *u8,
let out = vec::raw::from_buf_raw(res as *u8,
outsz as uint);
libc::free(res);
move out
@ -55,7 +55,7 @@ pub fn inflate_bytes(bytes: &[const u8]) -> ~[u8] {
ptr::addr_of(&outsz),
0);
assert res as int != 0;
let out = vec::raw::from_buf(res as *u8,
let out = vec::raw::from_buf_raw(res as *u8,
outsz as uint);
libc::free(res);
move out

View file

@ -91,7 +91,7 @@ pub mod consts {
* * digits - The number of significant digits
* * exact - Whether to enforce the exact number of significant digits
*/
pub fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
pub pure 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"; }
@ -125,7 +125,8 @@ pub fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
// store the next digit
frac *= 10.0;
let digit = frac as uint;
fractionalParts.push(digit);
// Bleh: not really unsafe.
unsafe { fractionalParts.push(digit); }
// calculate the next frac
frac -= digit as float;
@ -140,7 +141,8 @@ pub fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
// turn digits into string
// using stack of digits
while fractionalParts.is_not_empty() {
let mut adjusted_digit = carry + fractionalParts.pop();
// Bleh; shouldn't need to be unsafe
let mut adjusted_digit = carry + unsafe { fractionalParts.pop() };
if adjusted_digit == 10 {
carry = 1;
@ -196,7 +198,7 @@ pub fn test_to_str_exact_do_decimal() {
* * num - The float value
* * digits - The number of significant digits
*/
pub fn to_str(num: float, digits: uint) -> ~str {
pub pure fn to_str(num: float, digits: uint) -> ~str {
to_str_common(num, digits, false)
}
@ -361,7 +363,7 @@ pub fn from_str(num: &str) -> Option<float> {
*
* `NaN` if both `x` and `pow` are `0u`, otherwise `x^pow`
*/
pub fn pow_with_uint(base: uint, pow: uint) -> float {
pub pure fn pow_with_uint(base: uint, pow: uint) -> float {
if base == 0u {
if pow == 0u {
return NaN as float;

View file

@ -179,8 +179,8 @@ pub mod test {
#[test]
pub fn test_from_port() {
let (po, ch) = future_pipe::init();
future_pipe::server::completed(ch, ~"whale");
let f = from_port(po);
future_pipe::server::completed(move ch, ~"whale");
let f = from_port(move po);
assert get(&f) == ~"whale";
}
@ -238,7 +238,7 @@ pub mod test {
pub fn test_sendable_future() {
let expected = ~"schlorf";
let f = do spawn |copy expected| { copy expected };
do task::spawn {
do task::spawn |move f, move expected| {
let actual = get(&f);
assert actual == expected;
}

View file

@ -156,7 +156,7 @@ struct SipState {
mut v1: u64,
mut v2: u64,
mut v3: u64,
tail: [mut u8]/8, // unprocessed bytes
tail: [mut u8 * 8], // unprocessed bytes
mut ntail: uint, // how many bytes in tail are valid
}
@ -359,72 +359,72 @@ impl &SipState : Streaming {
#[test]
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, ]/_,
[ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, ]/_,
[ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, ]/_,
[ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, ]/_,
[ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, ]/_,
[ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, ]/_,
[ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, ]/_,
[ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, ]/_,
[ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, ]/_,
[ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, ]/_,
[ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, ]/_,
[ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, ]/_,
[ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, ]/_,
[ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, ]/_,
[ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, ]/_,
[ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, ]/_,
[ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, ]/_,
[ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, ]/_,
[ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, ]/_,
[ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, ]/_,
[ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, ]/_,
[ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, ]/_,
[ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, ]/_,
[ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, ]/_,
[ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, ]/_,
[ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, ]/_,
[ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, ]/_,
[ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, ]/_,
[ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, ]/_,
[ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, ]/_,
[ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, ]/_,
[ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, ]/_,
[ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, ]/_,
[ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, ]/_,
[ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, ]/_,
[ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, ]/_,
[ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, ]/_,
[ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, ]/_,
[ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, ]/_,
[ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, ]/_,
[ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, ]/_,
[ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, ]/_,
[ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, ]/_,
[ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, ]/_,
[ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, ]/_,
[ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, ]/_,
[ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, ]/_,
[ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, ]/_,
[ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, ]/_,
[ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, ]/_,
[ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, ]/_,
[ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, ]/_,
[ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, ]/_,
[ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, ]/_,
[ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, ]/_,
[ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, ]/_,
[ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, ]/_,
[ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, ]/_,
[ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, ]/_,
[ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, ]/_,
[ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, ]/_,
[ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, ]/_,
[ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, ]/_
]/_;
let vecs : [[u8 * 8] * 64] = [
[ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, ],
[ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, ],
[ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, ],
[ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, ],
[ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, ],
[ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, ],
[ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, ],
[ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, ],
[ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, ],
[ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, ],
[ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, ],
[ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, ],
[ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, ],
[ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, ],
[ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, ],
[ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, ],
[ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, ],
[ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, ],
[ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, ],
[ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, ],
[ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, ],
[ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, ],
[ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, ],
[ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, ],
[ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, ],
[ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, ],
[ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, ],
[ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, ],
[ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, ],
[ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, ],
[ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, ],
[ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, ],
[ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, ],
[ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, ],
[ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, ],
[ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, ],
[ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, ],
[ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, ],
[ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, ],
[ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, ],
[ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, ],
[ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, ],
[ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, ],
[ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, ],
[ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, ],
[ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, ],
[ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, ],
[ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, ],
[ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, ],
[ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, ],
[ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, ],
[ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, ],
[ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, ],
[ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, ],
[ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, ],
[ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, ],
[ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, ],
[ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, ],
[ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, ],
[ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, ],
[ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, ],
[ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, ],
[ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, ],
[ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, ]
];
let k0 = 0x_07_06_05_04_03_02_01_00_u64;
let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08_u64;
@ -433,12 +433,12 @@ pub fn test_siphash() {
let stream_inc = &State(k0,k1);
let stream_full = &State(k0,k1);
fn to_hex_str(r: &[u8]/8) -> ~str {
fn to_hex_str(r: &[u8 * 8]) -> ~str {
let mut s = ~"";
for vec::each(*r) |b| {
s += uint::to_str(*b as uint, 16u);
}
return s;
move s
}
while t < 64 {

View file

@ -50,7 +50,6 @@ pub pure fn compl(i: T) -> T {
}
/// Computes the absolute value
// FIXME: abs should return an unsigned int (#2353)
pub pure fn abs(i: T) -> T {
if is_negative(i) { -i } else { i }
}
@ -154,7 +153,7 @@ impl T : FromStr {
}
/// Convert to a string in a given base
pub fn to_str(n: T, radix: uint) -> ~str {
pub pure 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) }
@ -162,7 +161,7 @@ pub fn to_str(n: T, radix: uint) -> ~str {
}
}
pub fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
pub pure 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 {
@ -171,7 +170,7 @@ pub fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
}
/// Convert to a string
pub fn str(i: T) -> ~str { return to_str(i, 10u); }
pub pure fn str(i: T) -> ~str { return to_str(i, 10u); }
// FIXME: Has alignment issues on windows and 32-bit linux (#2609)
#[test]

View file

@ -37,7 +37,7 @@ pub trait Reader {
// FIXME (#2004): Seekable really should be orthogonal.
// FIXME (#2982): This should probably return an error.
fn read(buf: &[mut u8], len: uint) -> uint;
fn read(bytes: &[mut u8], len: uint) -> uint;
fn read_byte() -> int;
fn unread_byte(int);
fn eof() -> bool;
@ -65,32 +65,32 @@ pub trait ReaderUtil {
impl<T: Reader> T : ReaderUtil {
fn read_bytes(len: uint) -> ~[u8] {
let mut buf = vec::with_capacity(len);
unsafe { vec::raw::set_len(&mut buf, len); }
let mut bytes = vec::with_capacity(len);
unsafe { vec::raw::set_len(&mut bytes, len); }
let count = self.read(buf, len);
let count = self.read(bytes, len);
unsafe { vec::raw::set_len(&mut buf, count); }
move buf
unsafe { vec::raw::set_len(&mut bytes, count); }
move bytes
}
fn read_line() -> ~str {
let mut buf = ~[];
let mut bytes = ~[];
loop {
let ch = self.read_byte();
if ch == -1 || ch == 10 { break; }
buf.push(ch as u8);
bytes.push(ch as u8);
}
str::from_bytes(buf)
str::from_bytes(bytes)
}
fn read_chars(n: uint) -> ~[char] {
// returns the (consumed offset, n_req), appends characters to &chars
fn chars_from_bytes<T: Reader>(buf: &~[u8], chars: &mut ~[char])
fn chars_from_bytes<T: Reader>(bytes: &~[u8], chars: &mut ~[char])
-> (uint, uint) {
let mut i = 0;
let buf_len = buf.len();
while i < buf_len {
let b0 = buf[i];
let bytes_len = bytes.len();
while i < bytes_len {
let b0 = bytes[i];
let w = str::utf8_char_width(b0);
let end = i + w;
i += 1;
@ -100,12 +100,12 @@ impl<T: Reader> T : ReaderUtil {
loop;
}
// can't satisfy this char with the existing data
if end > buf_len {
return (i - 1, end - buf_len);
if end > bytes_len {
return (i - 1, end - bytes_len);
}
let mut val = 0;
while i < end {
let next = buf[i] as int;
let next = bytes[i] as int;
i += 1;
assert (next > -1);
assert (next & 192 == 128);
@ -119,8 +119,8 @@ impl<T: Reader> T : ReaderUtil {
}
return (i, 0);
}
let mut buf: ~[u8] = ~[];
let mut chars: ~[char] = ~[];
let mut bytes = ~[];
let mut chars = ~[];
// might need more bytes, but reading n will never over-read
let mut nbread = n;
while nbread > 0 {
@ -130,15 +130,15 @@ impl<T: Reader> T : ReaderUtil {
// we're split in a unicode char?
break;
}
buf.push_all(data);
let (offset, nbreq) = chars_from_bytes::<T>(&buf, &mut chars);
bytes.push_all(data);
let (offset, nbreq) = chars_from_bytes::<T>(&bytes, &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 > 0 {
buf = vec::slice(buf, offset, buf.len());
bytes = vec::slice(bytes, offset, bytes.len());
}
}
move chars
@ -154,12 +154,12 @@ impl<T: Reader> T : ReaderUtil {
}
fn read_c_str() -> ~str {
let mut buf: ~[u8] = ~[];
let mut bytes: ~[u8] = ~[];
loop {
let ch = self.read_byte();
if ch < 1 { break; } else { buf.push(ch as u8); }
if ch < 1 { break; } else { bytes.push(ch as u8); }
}
str::from_bytes(buf)
str::from_bytes(bytes)
}
// FIXME deal with eof? // #2004
@ -191,9 +191,9 @@ impl<T: Reader> T : ReaderUtil {
}
fn read_whole_stream() -> ~[u8] {
let mut buf: ~[u8] = ~[];
while !self.eof() { buf.push_all(self.read_bytes(2048u)); }
move buf
let mut bytes: ~[u8] = ~[];
while !self.eof() { bytes.push_all(self.read_bytes(2048u)); }
move bytes
}
fn each_byte(it: fn(int) -> bool) {
@ -226,8 +226,8 @@ fn convert_whence(whence: SeekStyle) -> i32 {
}
impl *libc::FILE: Reader {
fn read(buf: &[mut u8], len: uint) -> uint {
do vec::as_mut_buf(buf) |buf_p, buf_len| {
fn read(bytes: &[mut u8], len: uint) -> uint {
do vec::as_mut_buf(bytes) |buf_p, buf_len| {
assert buf_len <= len;
let count = libc::fread(buf_p as *mut c_void, 1u as size_t,
@ -250,7 +250,9 @@ impl *libc::FILE: Reader {
// duration of its lifetime.
// FIXME there really should be a better way to do this // #2004
impl<T: Reader, C> {base: T, cleanup: C}: Reader {
fn read(buf: &[mut u8], len: uint) -> uint { self.base.read(buf, len) }
fn read(bytes: &[mut u8], len: uint) -> uint {
self.base.read(bytes, len)
}
fn read_byte() -> int { self.base.read_byte() }
fn unread_byte(byte: int) { self.base.unread_byte(byte); }
fn eof() -> bool { self.base.eof() }
@ -297,39 +299,41 @@ pub fn file_reader(path: &Path) -> Result<Reader, ~str> {
}
// Byte buffer readers
// Byte readers
pub struct BytesReader {
bytes: &[u8],
mut pos: uint
}
pub type ByteBuf = {buf: &[const u8], mut pos: uint};
impl BytesReader: Reader {
fn read(bytes: &[mut u8], len: uint) -> uint {
let count = uint::min(len, self.bytes.len() - self.pos);
impl ByteBuf: Reader {
fn read(buf: &[mut u8], len: uint) -> uint {
let count = uint::min(len, self.buf.len() - self.pos);
let view = vec::const_view(self.buf, self.pos, self.buf.len());
vec::bytes::memcpy(buf, view, count);
let view = vec::view(self.bytes, self.pos, self.bytes.len());
vec::bytes::memcpy(bytes, view, count);
self.pos += count;
count
}
fn read_byte() -> int {
if self.pos == self.buf.len() { return -1; }
let b = self.buf[self.pos];
if self.pos == self.bytes.len() { return -1; }
let b = self.bytes[self.pos];
self.pos += 1u;
return b as int;
}
// FIXME (#2738): implement this
fn unread_byte(_byte: int) { error!("Unimplemented: unread_byte"); fail; }
fn eof() -> bool { self.pos == self.buf.len() }
fn eof() -> bool { self.pos == self.bytes.len() }
fn seek(offset: int, whence: SeekStyle) {
let pos = self.pos;
self.pos = seek_in_buf(offset, pos, self.buf.len(), whence);
self.pos = seek_in_buf(offset, pos, self.bytes.len(), whence);
}
fn tell() -> uint { self.pos }
}
pub fn with_bytes_reader<t>(bytes: &[u8], f: fn(Reader) -> t) -> t {
f({buf: bytes, mut pos: 0u} as Reader)
pub pure fn with_bytes_reader<t>(bytes: &[u8], f: fn(Reader) -> t) -> t {
f(BytesReader { bytes: bytes, pos: 0u } as Reader)
}
pub fn with_str_reader<T>(s: &str, f: fn(Reader) -> T) -> T {
@ -602,10 +606,10 @@ impl<T: Writer> T : WriterUtil {
self.write_str(&"\n");
}
fn write_int(n: int) {
int::to_str_bytes(n, 10u, |buf| self.write(buf))
int::to_str_bytes(n, 10u, |bytes| self.write(bytes))
}
fn write_uint(n: uint) {
uint::to_str_bytes(false, n, 10u, |buf| self.write(buf))
uint::to_str_bytes(false, n, 10u, |bytes| self.write(bytes))
}
fn write_le_uint(n: uint) {
u64_to_le_bytes(n as u64, uint::bytes, |v| self.write(v))
@ -687,34 +691,34 @@ pub fn print(s: &str) { stdout().write_str(s); }
pub fn println(s: &str) { stdout().write_line(s); }
pub struct BytesWriter {
buf: DVec<u8>,
bytes: DVec<u8>,
mut pos: uint,
}
impl BytesWriter: Writer {
fn write(v: &[const u8]) {
do self.buf.swap |buf| {
let mut buf <- buf;
do self.bytes.swap |bytes| {
let mut bytes <- bytes;
let v_len = v.len();
let buf_len = buf.len();
let bytes_len = bytes.len();
let count = uint::max(buf_len, self.pos + v_len);
vec::reserve(&mut buf, count);
unsafe { vec::raw::set_len(&mut buf, count); }
let count = uint::max(bytes_len, self.pos + v_len);
vec::reserve(&mut bytes, count);
unsafe { vec::raw::set_len(&mut bytes, count); }
{
let view = vec::mut_view(buf, self.pos, count);
let view = vec::mut_view(bytes, self.pos, count);
vec::bytes::memcpy(view, v, v_len);
}
self.pos += v_len;
move buf
move bytes
}
}
fn seek(offset: int, whence: SeekStyle) {
let pos = self.pos;
let len = self.buf.len();
let len = self.bytes.len();
self.pos = seek_in_buf(offset, pos, len, whence);
}
fn tell() -> uint { self.pos }
@ -730,24 +734,28 @@ impl @BytesWriter : Writer {
fn get_type() -> WriterType { (*self).get_type() }
}
pub fn BytesWriter() -> BytesWriter {
BytesWriter { buf: DVec(), mut pos: 0u }
pub pure fn BytesWriter() -> BytesWriter {
BytesWriter { bytes: DVec(), mut pos: 0u }
}
pub fn with_bytes_writer(f: fn(Writer)) -> ~[u8] {
pub pure fn with_bytes_writer(f: fn(Writer)) -> ~[u8] {
let wr = @BytesWriter();
f(wr as Writer);
wr.buf.check_out(|buf| buf)
// FIXME (#3758): This should not be needed.
unsafe { wr.bytes.check_out(|bytes| move bytes) }
}
pub fn with_str_writer(f: fn(Writer)) -> ~str {
pub pure 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.
v.push(0);
// FIXME (#3758): This should not be needed.
unsafe {
// Make sure the vector has a trailing null and is proper utf8.
v.push(0);
}
assert str::is_utf8(v);
unsafe { move ::cast::transmute(v) }
unsafe { move ::cast::transmute(move v) }
}
// Utility functions
@ -975,15 +983,17 @@ mod tests {
fn bytes_buffer_overwrite() {
let wr = BytesWriter();
wr.write(~[0u8, 1u8, 2u8, 3u8]);
assert wr.buf.borrow(|buf| buf == ~[0u8, 1u8, 2u8, 3u8]);
assert wr.bytes.borrow(|bytes| bytes == ~[0u8, 1u8, 2u8, 3u8]);
wr.seek(-2, SeekCur);
wr.write(~[4u8, 5u8, 6u8, 7u8]);
assert wr.buf.borrow(|buf| buf == ~[0u8, 1u8, 4u8, 5u8, 6u8, 7u8]);
assert wr.bytes.borrow(|bytes| bytes ==
~[0u8, 1u8, 4u8, 5u8, 6u8, 7u8]);
wr.seek(-2, SeekEnd);
wr.write(~[8u8]);
wr.seek(1, SeekSet);
wr.write(~[9u8]);
assert wr.buf.borrow(|buf| buf == ~[0u8, 9u8, 4u8, 5u8, 8u8, 7u8]);
assert wr.bytes.borrow(|bytes| bytes ==
~[0u8, 9u8, 4u8, 5u8, 8u8, 7u8]);
}
}

View file

@ -11,7 +11,7 @@ pub type IMPL_T<A> = dlist::DList<A>;
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);
let nobe = option::get(link);
assert nobe.linked;
if !f(&nobe.data) { break; }
// Check (weakly) that the user didn't do a remove.

View file

@ -42,8 +42,6 @@
// Initial glob-exports mean that all the contents of all the modules
// wind up exported, if you're interested in writing platform-specific code.
// FIXME (#2006): change these to glob-exports when sufficiently supported.
pub use types::common::c95::*;
pub use types::common::c99::*;
pub use types::common::posix88::*;
@ -89,7 +87,7 @@ pub use funcs::extra::*;
pub use size_t;
pub use c_float, c_double, c_void, FILE, fpos_t;
pub use DIR, dirent;
pub use DIR, dirent_t;
pub use c_char, c_schar, c_uchar;
pub use c_short, c_ushort, c_int, c_uint, c_long, c_ulong;
pub use size_t, ptrdiff_t, clock_t, time_t;
@ -149,7 +147,7 @@ mod types {
}
pub mod posix88 {
pub enum DIR {}
pub enum dirent {}
pub enum dirent_t {}
}
pub mod posix01 {}
pub mod posix08 {}
@ -1021,7 +1019,7 @@ pub mod funcs {
pub extern mod dirent {
fn opendir(dirname: *c_char) -> *DIR;
fn closedir(dirp: *DIR) -> c_int;
fn readdir(dirp: *DIR) -> *dirent;
fn readdir(dirp: *DIR) -> *dirent_t;
fn rewinddir(dirp: *DIR);
fn seekdir(dirp: *DIR, loc: c_long);
fn telldir(dirp: *DIR) -> c_long;

View file

@ -32,7 +32,7 @@ pub fn console_off() {
#[cfg(notest)]
#[lang="log_type"]
pub fn log_type<T>(level: u32, object: &T) {
let bytes = do io::with_bytes_writer() |writer| {
let bytes = do io::with_bytes_writer |writer| {
repr::write_repr(writer, object);
};
unsafe {

View file

@ -24,7 +24,7 @@ struct Data<T> {
pub type Mut<T> = Data<T>;
pub fn Mut<T>(t: T) -> Mut<T> {
Data {value: t, mode: ReadOnly}
Data {value: move t, mode: ReadOnly}
}
pub fn unwrap<T>(m: Mut<T>) -> T {
@ -32,7 +32,7 @@ pub fn unwrap<T>(m: Mut<T>) -> T {
// is in use, as that would be a move from a borrowed value.
assert (m.mode as uint) == (ReadOnly as uint);
let Data {value: move value, mode: _} = move m;
return value;
move value
}
impl<T> Data<T> {

View file

@ -42,7 +42,7 @@ pub enum Option<T> {
Some(T),
}
pub 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
@ -58,7 +58,7 @@ pub pure fn get<T: Copy>(opt: &Option<T>) -> T {
case explicitly.
*/
match *opt {
match opt {
Some(copy x) => return x,
None => fail ~"option::get none"
}
@ -85,7 +85,7 @@ pub pure fn get_ref<T>(opt: &r/Option<T>) -> &r/T {
}
}
pub 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
@ -94,7 +94,7 @@ pub pure fn expect<T: Copy>(opt: &Option<T>, reason: ~str) -> T {
*
* Fails if the value equals `none`
*/
match *opt { Some(copy x) => x, None => fail reason }
match opt { Some(copy x) => x, None => fail reason }
}
pub pure fn map<T, U>(opt: &Option<T>, f: fn(x: &T) -> U) -> Option<U> {
@ -119,11 +119,9 @@ pub pure fn chain<T, U>(opt: Option<T>,
* function that returns an option.
*/
// XXX write with move match
if opt.is_some() {
f(unwrap(opt))
} else {
None
match move opt {
Some(move t) => f(move t),
None => None
}
}
@ -169,10 +167,10 @@ pub pure fn is_some<T>(opt: &Option<T>) -> bool {
!is_none(opt)
}
pub 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(copy x) => x, None => def }
match opt { Some(copy x) => x, None => def }
}
pub pure fn map_default<T, U>(opt: &Option<T>, def: U,
@ -227,7 +225,7 @@ pub fn swap_unwrap<T>(opt: &mut Option<T>) -> 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(); }
if opt.is_none() { fail reason.to_owned(); }
unwrap(move opt)
}
@ -286,8 +284,8 @@ impl<T: Copy> Option<T> {
Instead, prefer to use pattern matching and handle the `None`
case explicitly.
*/
pure fn get() -> T { get(&self) }
pure fn get_default(def: T) -> T { get_default(&self, def) }
pure fn get() -> T { get(self) }
pure fn get_default(def: T) -> T { get_default(self, def) }
/**
* Gets the value out of an option, printing a specified message on
* failure
@ -296,7 +294,7 @@ 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, move 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) }
}
@ -326,8 +324,8 @@ impl<T: Eq> Option<T> : Eq {
fn test_unwrap_ptr() {
let x = ~0;
let addr_x = ptr::addr_of(&(*x));
let opt = Some(x);
let y = unwrap(opt);
let opt = Some(move x);
let y = unwrap(move opt);
let addr_y = ptr::addr_of(&(*y));
assert addr_x == addr_y;
}
@ -358,8 +356,8 @@ fn test_unwrap_resource() {
let i = @mut 0;
{
let x = R(i);
let opt = Some(x);
let _y = unwrap(opt);
let opt = Some(move x);
let _y = unwrap(move opt);
}
assert *i == 1;
}

View file

@ -473,7 +473,7 @@ pub fn tmpdir() -> Path {
#[cfg(unix)]
#[allow(non_implicitly_copyable_typarams)]
fn lookup() -> Path {
option::get_default(&getenv_nonempty("TMPDIR"),
option::get_default(getenv_nonempty("TMPDIR"),
Path("/tmp"))
}
@ -481,7 +481,7 @@ pub fn tmpdir() -> Path {
#[allow(non_implicitly_copyable_typarams)]
fn lookup() -> Path {
option::get_default(
&option::or(getenv_nonempty("TMP"),
option::or(getenv_nonempty("TMP"),
option::or(getenv_nonempty("TEMP"),
option::or(getenv_nonempty("USERPROFILE"),
getenv_nonempty("WINDIR")))),
@ -739,7 +739,7 @@ unsafe fn load_argc_and_argv(argc: c_int, argv: **c_char) -> ~[~str] {
for uint::range(0, argc as uint) |i| {
vec::push(&mut args, str::raw::from_c_str(*argv.offset(i)));
}
return args;
move args
}
/**
@ -903,7 +903,7 @@ mod tests {
let rng: rand::Rng = rand::Rng();
let n = ~"TEST" + rng.gen_str(10u);
assert getenv(n).is_none();
n
move n
}
#[test]
@ -937,7 +937,7 @@ mod tests {
let n = make_rand_name();
setenv(n, s);
log(debug, s);
assert getenv(n) == option::Some(s);
assert getenv(n) == option::Some(move s);
}
#[test]
@ -963,7 +963,7 @@ mod tests {
// MingW seems to set some funky environment variables like
// "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
// from env() but not visible from getenv().
assert v2.is_none() || v2 == option::Some(v);
assert v2.is_none() || v2 == option::Some(move v);
}
}
@ -976,7 +976,7 @@ mod tests {
assert !vec::contains(e, &(copy n, ~"VALUE"));
e = env();
assert vec::contains(e, &(n, ~"VALUE"));
assert vec::contains(e, &(move n, ~"VALUE"));
}
#[test]

View file

@ -61,7 +61,7 @@ pub pure fn Path(s: &str) -> Path {
}
impl PosixPath : ToStr {
fn to_str() -> ~str {
pure fn to_str() -> ~str {
let mut s = ~"";
if self.is_absolute {
s += "/";
@ -96,7 +96,7 @@ impl PosixPath : GenericPath {
let mut components = str::split_nonempty(s, |c| c == '/');
let is_absolute = (s.len() != 0 && s[0] == '/' as u8);
return PosixPath { is_absolute: is_absolute,
components: components }
components: move components }
}
pure fn dirname() -> ~str {
@ -192,7 +192,7 @@ impl PosixPath : GenericPath {
Some(ref f) => ~[copy *f]
};
return PosixPath { is_absolute: false,
components: cs }
components: move cs }
}
pure fn push_rel(other: &PosixPath) -> PosixPath {
@ -208,7 +208,8 @@ impl PosixPath : GenericPath {
|c| windows::is_sep(c as u8));
unsafe { v.push_all_move(move ss); }
}
PosixPath { components: move v, ..self }
PosixPath { is_absolute: self.is_absolute,
components: move v }
}
pure fn push(s: &str) -> PosixPath {
@ -223,20 +224,25 @@ impl PosixPath : GenericPath {
if cs.len() != 0 {
unsafe { cs.pop(); }
}
return PosixPath { components: move cs, ..self }
return PosixPath {
is_absolute: self.is_absolute,
components: move cs
}
//..self }
}
pure fn normalize() -> PosixPath {
return PosixPath {
components: normalize(self.components),
..self
is_absolute: self.is_absolute,
components: normalize(self.components)
// ..self
}
}
}
impl WindowsPath : ToStr {
fn to_str() -> ~str {
pure fn to_str() -> ~str {
let mut s = ~"";
match self.host {
Some(ref h) => { s += "\\\\"; s += *h; }
@ -286,10 +292,10 @@ impl WindowsPath : GenericPath {
let mut components =
str::split_nonempty(rest, |c| windows::is_sep(c as u8));
let is_absolute = (rest.len() != 0 && windows::is_sep(rest[0]));
return WindowsPath { host: host,
device: device,
return WindowsPath { host: move host,
device: move device,
is_absolute: is_absolute,
components: components }
components: move components }
}
pure fn dirname() -> ~str {
@ -386,7 +392,7 @@ impl WindowsPath : GenericPath {
return WindowsPath { host: None,
device: None,
is_absolute: false,
components: cs }
components: move cs }
}
pure fn push_rel(other: &WindowsPath) -> WindowsPath {
@ -402,7 +408,13 @@ impl WindowsPath : GenericPath {
|c| windows::is_sep(c as u8));
unsafe { v.push_all_move(move ss); }
}
return WindowsPath { components: move v, ..self }
// tedious, but as-is, we can't use ..self
return WindowsPath {
host: copy self.host,
device: copy self.device,
is_absolute: self.is_absolute,
components: move v
}
}
pure fn push(s: &str) -> WindowsPath {
@ -417,13 +429,20 @@ impl WindowsPath : GenericPath {
if cs.len() != 0 {
unsafe { cs.pop(); }
}
return WindowsPath { components: move cs, ..self }
return WindowsPath {
host: copy self.host,
device: copy self.device,
is_absolute: self.is_absolute,
components: move cs
}
}
pure fn normalize() -> WindowsPath {
return WindowsPath {
components: normalize(self.components),
..self
host: copy self.host,
device: copy self.device,
is_absolute: self.is_absolute,
components: normalize(self.components)
}
}
}

View file

@ -350,7 +350,8 @@ fn BufferResource<T: Send>(b: ~Buffer<T>) -> BufferResource<T> {
atomic_add_acq(&mut b.header.ref_count, 1);
BufferResource {
buffer: b
// tjc: ????
buffer: move b
}
}
@ -448,7 +449,12 @@ pub fn try_recv<T: Send, Tbuffer: Send>(p: RecvPacketBuffered<T, Tbuffer>)
let this = rustrt::rust_get_task();
rustrt::task_clear_event_reject(this);
rustrt::rust_task_ref(this);
debug!("blocked = %x this = %x", p.header.blocked_task as uint,
this as uint);
let old_task = swap_task(&mut p.header.blocked_task, this);
debug!("blocked = %x this = %x old_task = %x",
p.header.blocked_task as uint,
this as uint, old_task as uint);
assert old_task.is_null();
let mut first = true;
let mut count = SPIN_COUNT;
@ -661,7 +667,7 @@ pub fn select2<A: Send, Ab: Send, B: Send, Bb: Send>(
-> Either<(Option<A>, RecvPacketBuffered<B, Bb>),
(RecvPacketBuffered<A, Ab>, Option<B>)>
{
let i = wait_many([a.header(), b.header()]/_);
let i = wait_many([a.header(), b.header()]);
match i {
0 => Left((try_recv(move a), move b)),
@ -687,7 +693,7 @@ pub fn selecti<T: Selectable>(endpoints: &[T]) -> uint {
/// Returns 0 or 1 depending on which endpoint is ready to receive
pub fn select2i<A: Selectable, B: Selectable>(a: &A, b: &B) ->
Either<(), ()> {
match wait_many([a.header(), b.header()]/_) {
match wait_many([a.header(), b.header()]) {
0 => Left(()),
1 => Right(()),
_ => fail ~"wait returned unexpected index"
@ -1212,7 +1218,7 @@ pub mod test {
c1.send(~"abc");
match (p1, p2).select() {
match (move p1, move p2).select() {
Right(_) => fail,
_ => ()
}
@ -1224,8 +1230,8 @@ pub mod test {
pub fn test_oneshot() {
let (c, p) = oneshot::init();
oneshot::client::send(c, ());
oneshot::client::send(move c, ());
recv_one(p)
recv_one(move p)
}
}

View file

@ -374,7 +374,7 @@ pub unsafe fn unwrap_shared_mutable_state<T: Send>(rc: SharedMutableState<T>)
rc.data = ptr::null();
// Step 1 - drop our own reference.
let new_count = rustrt::rust_atomic_decrement(&mut ptr.count);
assert new_count >= 0;
// assert new_count >= 0;
if new_count == 0 {
// We were the last owner. Can unwrap immediately.
// Also we have to free the server endpoints.
@ -505,7 +505,7 @@ pub struct Exclusive<T: Send> { x: SharedMutableState<ExData<T>> }
pub fn exclusive<T:Send >(user_data: T) -> Exclusive<T> {
let data = ExData {
lock: LittleLock(), mut failed: false, mut data: user_data
lock: LittleLock(), mut failed: false, mut data: move user_data
};
Exclusive { x: unsafe { shared_mutable_state(move data) } }
}
@ -544,7 +544,7 @@ impl<T: Send> Exclusive<T> {
}
}
// FIXME(#2585) make this a by-move method on the exclusive
// FIXME(#3724) make this a by-move method on the exclusive
pub fn unwrap_exclusive<T: Send>(arc: Exclusive<T>) -> T {
let Exclusive { x: x } <- arc;
let inner = unsafe { unwrap_shared_mutable_state(move x) };
@ -558,17 +558,17 @@ pub mod tests {
pub fn exclusive_arc() {
let mut futures = ~[];
let num_tasks = 10u;
let count = 10u;
let num_tasks = 10;
let count = 10;
let total = exclusive(~mut 0u);
let total = exclusive(~mut 0);
for uint::range(0u, num_tasks) |_i| {
for uint::range(0, num_tasks) |_i| {
let total = total.clone();
futures.push(future::spawn(|| {
for uint::range(0u, count) |_i| {
futures.push(future::spawn(|move total| {
for uint::range(0, count) |_i| {
do total.with |count| {
**count += 1u;
**count += 1;
}
}
}));
@ -587,7 +587,7 @@ pub mod tests {
// accesses will also fail.
let x = exclusive(1);
let x2 = x.clone();
do task::try {
do task::try |move x2| {
do x2.with |one| {
assert *one == 2;
}
@ -600,27 +600,28 @@ pub mod tests {
#[test]
pub fn exclusive_unwrap_basic() {
let x = exclusive(~~"hello");
assert unwrap_exclusive(x) == ~~"hello";
assert unwrap_exclusive(move x) == ~~"hello";
}
#[test]
pub fn exclusive_unwrap_contended() {
let x = exclusive(~~"hello");
let x2 = ~mut Some(x.clone());
do task::spawn {
do task::spawn |move x2| {
let x2 = option::swap_unwrap(x2);
do x2.with |_hello| { }
task::yield();
}
assert unwrap_exclusive(x) == ~~"hello";
assert unwrap_exclusive(move x) == ~~"hello";
// Now try the same thing, but with the child task blocking.
let x = exclusive(~~"hello");
let x2 = ~mut Some(x.clone());
let mut res = None;
do task::task().future_result(|+r| res = Some(r)).spawn {
do task::task().future_result(|+r| res = Some(move r)).spawn
|move x2| {
let x2 = option::swap_unwrap(x2);
assert unwrap_exclusive(x2) == ~~"hello";
assert unwrap_exclusive(move x2) == ~~"hello";
}
// Have to get rid of our reference before blocking.
{ let _x = move x; } // FIXME(#3161) util::ignore doesn't work here
@ -633,11 +634,12 @@ pub mod tests {
let x = exclusive(~~"hello");
let x2 = ~mut Some(x.clone());
let mut res = None;
do task::task().future_result(|+r| res = Some(r)).spawn {
do task::task().future_result(|+r| res = Some(move r)).spawn
|move x2| {
let x2 = option::swap_unwrap(x2);
assert unwrap_exclusive(x2) == ~~"hello";
assert unwrap_exclusive(move x2) == ~~"hello";
}
assert unwrap_exclusive(x) == ~~"hello";
assert unwrap_exclusive(move x) == ~~"hello";
let res = option::swap_unwrap(&mut res);
future::get(&res);
}
@ -656,7 +658,7 @@ pub mod tests {
for 10.times { task::yield(); } // try to let the unwrapper go
fail; // punt it awake from its deadlock
}
let _z = unwrap_exclusive(x);
let _z = unwrap_exclusive(move x);
do x2.with |_hello| { }
};
assert result.is_err();

View file

@ -246,7 +246,7 @@ impl<V: TyVisitor MovePtr> MovePtrAdaptor<V>: TyVisitor {
}
fn visit_unboxed_vec(mtbl: uint, inner: *TyDesc) -> bool {
self.align_to::<vec::raw::UnboxedVecRepr>();
self.align_to::<vec::UnboxedVecRepr>();
if ! self.inner.visit_vec(mtbl, inner) { return false; }
true
}

View file

@ -15,7 +15,8 @@ use to_str::ToStr;
use cast::transmute;
use intrinsic::{TyDesc, TyVisitor, visit_tydesc};
use reflect::{MovePtr, MovePtrAdaptor};
use vec::raw::{VecRepr, UnboxedVecRepr, SliceRepr};
use vec::UnboxedVecRepr;
use vec::raw::{VecRepr, SliceRepr};
pub use box::raw::BoxRepr;
use box::raw::BoxHeaderRepr;
@ -155,7 +156,7 @@ impl ReprVisitor {
fn visit_ptr_inner(ptr: *c_void, inner: *TyDesc) -> bool {
let mut u = ReprVisitor(ptr, self.writer);
let v = reflect::MovePtrAdaptor(move u);
visit_tydesc(inner, v as @TyVisitor);
visit_tydesc(inner, (move v) as @TyVisitor);
true
}
@ -303,7 +304,7 @@ impl ReprVisitor : TyVisitor {
fn visit_unboxed_vec(mtbl: uint, inner: *TyDesc) -> bool {
do self.get::<vec::raw::UnboxedVecRepr> |b| {
do self.get::<vec::UnboxedVecRepr> |b| {
self.write_unboxed_vec_repr(mtbl, b, inner);
}
}
@ -452,7 +453,7 @@ pub fn write_repr2<T>(writer: @Writer, object: &T) {
let tydesc = intrinsic::get_tydesc::<T>();
let mut u = ReprVisitor(ptr, writer);
let v = reflect::MovePtrAdaptor(move u);
visit_tydesc(tydesc, v as @TyVisitor)
visit_tydesc(tydesc, (move v) as @TyVisitor)
}
#[test]
@ -558,7 +559,7 @@ impl ReprPrinter {
unsafe {
self.align(sys::min_align_of::<T>());
let value_addr: &T = transmute(copy self.ptr);
(*value_addr).write_repr(self.writer);
value_addr.write_repr(self.writer);
self.bump(sys::size_of::<T>());
true
}
@ -991,7 +992,7 @@ pub fn write_repr<T>(writer: @Writer, object: &T) {
unsafe {
let ptr = ptr::to_unsafe_ptr(object) as *c_void;
let tydesc = sys::get_type_desc::<T>();
let tydesc = cast::transmute(tydesc);
let tydesc = cast::transmute(move tydesc);
let repr_printer = @ReprPrinter {
ptr: ptr,

View file

@ -105,11 +105,9 @@ pub pure fn to_either<T: Copy, U: Copy>(res: &Result<U, T>)
*/
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))
match move res {
Ok(move t) => op(move t),
Err(move e) => Err(e)
}
}

View file

@ -226,7 +226,7 @@ pub fn start_program(prog: &str, args: &[~str]) -> Program {
fn ProgRes(r: ProgRepr) -> ProgRes {
ProgRes {
r: r
r: move r
}
}
@ -248,12 +248,14 @@ pub fn start_program(prog: &str, args: &[~str]) -> Program {
}
fn read_all(rd: io::Reader) -> ~str {
let mut buf = ~"";
while !rd.eof() {
let bytes = rd.read_bytes(4096u);
buf += str::from_bytes(bytes);
}
move buf
let buf = io::with_bytes_writer(|wr| {
let mut bytes = [mut 0, ..4096];
while !rd.eof() {
let nread = rd.read(bytes, bytes.len());
wr.write(bytes.view(0, nread));
}
});
str::from_bytes(buf)
}
/**
@ -313,10 +315,10 @@ pub fn program_output(prog: &str, args: &[~str]) ->
let stream = comm::recv(p);
match stream {
(1, copy s) => {
outs = s;
outs = move s;
}
(2, copy s) => {
errs = s;
errs = move s;
}
(n, _) => {
fail(fmt!("program_output received an unexpected file \
@ -341,13 +343,15 @@ fn writeclose(fd: c_int, s: ~str) {
fn readclose(fd: c_int) -> ~str {
let file = os::fdopen(fd);
let reader = io::FILE_reader(file, false);
let mut buf = ~"";
while !reader.eof() {
let bytes = reader.read_bytes(4096u);
buf += str::from_bytes(bytes);
}
let buf = io::with_bytes_writer(|writer| {
let mut bytes = [mut 0, ..4096];
while !reader.eof() {
let nread = reader.read(bytes, bytes.len());
writer.write(bytes.view(0, nread));
}
});
os::fclose(file);
move buf
str::from_bytes(buf)
}
/// Waits for a process to exit and returns the exit code

View file

@ -17,6 +17,9 @@ pub trait SendMap<K:Eq Hash, V: Copy> {
fn insert(&mut self, k: K, +v: V) -> bool;
fn remove(&mut self, k: &K) -> bool;
fn pop(&mut self, k: &K) -> Option<V>;
fn swap(&mut self, k: K, +v: V) -> Option<V>;
fn consume(&mut self, f: fn(K, V));
fn clear(&mut self);
pure fn len(&const self) -> uint;
pure fn is_empty(&const self) -> bool;
@ -182,8 +185,8 @@ pub mod linear {
debug!("insert fresh (%?->%?) at idx %?, hash %?",
k, v, idx, hash);
self.buckets[idx] = Some(Bucket {hash: hash,
key: k,
value: v});
key: move k,
value: move v});
self.size += 1;
true
}
@ -191,13 +194,59 @@ pub mod linear {
debug!("insert overwrite (%?->%?) at idx %?, hash %?",
k, v, idx, hash);
self.buckets[idx] = Some(Bucket {hash: hash,
key: k,
value: v});
key: move k,
value: move v});
false
}
}
}
fn pop_internal(&mut self, hash: uint, k: &K) -> Option<V> {
// Removing from an open-addressed hashtable
// is, well, painful. The problem is that
// the entry may lie on the probe path for other
// entries, so removing it would make you think that
// those probe paths are empty.
//
// To address this we basically have to keep walking,
// re-inserting entries we find until we reach an empty
// bucket. We know we will eventually reach one because
// we insert one ourselves at the beginning (the removed
// entry).
//
// I found this explanation elucidating:
// http://www.maths.lse.ac.uk/Courses/MA407/del-hash.pdf
let mut idx = match self.bucket_for_key_with_hash(self.buckets,
hash, k) {
TableFull | FoundHole(_) => return None,
FoundEntry(idx) => idx
};
let len_buckets = self.buckets.len();
let mut bucket = None;
self.buckets[idx] <-> bucket;
let value = match move bucket {
None => None,
Some(move bucket) => {
let Bucket { value: move value, _ } = move bucket;
Some(move value)
},
};
idx = self.next_bucket(idx, len_buckets);
while self.buckets[idx].is_some() {
let mut bucket = None;
bucket <-> self.buckets[idx];
self.insert_opt_bucket(move bucket);
idx = self.next_bucket(idx, len_buckets);
}
self.size -= 1;
move value
}
fn search(&self,
hash: uint,
op: fn(x: &Option<Bucket<K,V>>) -> bool) {
@ -222,37 +271,55 @@ pub mod linear {
}
fn remove(&mut self, k: &K) -> bool {
// Removing from an open-addressed hashtable
// is, well, painful. The problem is that
// the entry may lie on the probe path for other
// entries, so removing it would make you think that
// those probe paths are empty.
//
// To address this we basically have to keep walking,
// re-inserting entries we find until we reach an empty
// bucket. We know we will eventually reach one because
// we insert one ourselves at the beginning (the removed
// entry).
//
// I found this explanation elucidating:
// http://www.maths.lse.ac.uk/Courses/MA407/del-hash.pdf
let mut idx = match self.bucket_for_key(self.buckets, k) {
TableFull | FoundHole(_) => return false,
FoundEntry(idx) => idx
};
let len_buckets = self.buckets.len();
self.buckets[idx] = None;
idx = self.next_bucket(idx, len_buckets);
while self.buckets[idx].is_some() {
let mut bucket = None;
bucket <-> self.buckets[idx];
self.insert_opt_bucket(move bucket);
idx = self.next_bucket(idx, len_buckets);
match self.pop(k) {
Some(_) => true,
None => false,
}
}
fn pop(&mut self, k: &K) -> Option<V> {
let hash = k.hash_keyed(self.k0, self.k1) as uint;
self.pop_internal(hash, k)
}
fn swap(&mut self, k: K, v: V) -> Option<V> {
// this could be faster.
let hash = k.hash_keyed(self.k0, self.k1) as uint;
let old_value = self.pop_internal(hash, &k);
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
// simply going to update a key in place. My sense
// though is that it's worse to have to search through
// buckets to find the right spot twice than to just
// resize in this corner case.
self.expand();
}
self.insert_internal(hash, move k, move v);
move old_value
}
fn consume(&mut self, f: fn(K, V)) {
let mut buckets = ~[];
self.buckets <-> buckets;
self.size = 0;
do vec::consume(move buckets) |_i, bucket| {
match move bucket {
None => { },
Some(move bucket) => {
let Bucket {
key: move key,
value: move value,
_
} = move bucket;
f(move key, move value)
}
}
}
self.size -= 1;
return true;
}
fn clear(&mut self) {
@ -350,7 +417,6 @@ pub mod linear {
}
option::unwrap(move value)
}
}
}
@ -407,6 +473,37 @@ pub mod test {
assert m.is_empty();
}
#[test]
pub fn pops() {
let mut m = ~LinearMap();
m.insert(1, 2);
assert m.pop(&1) == Some(2);
assert m.pop(&1) == None;
}
#[test]
pub fn swaps() {
let mut m = ~LinearMap();
assert m.swap(1, 2) == None;
assert m.swap(1, 3) == Some(2);
assert m.swap(1, 4) == Some(3);
}
#[test]
pub fn consumes() {
let mut m = ~LinearMap();
assert m.insert(1, 2);
assert m.insert(2, 3);
let mut m2 = ~LinearMap();
do m.consume |k, v| {
m2.insert(k, v);
}
assert m.len() == 0;
assert m2.len() == 2;
assert m2.find(&1) == Some(2);
assert m2.find(&2) == Some(3);
}
#[test]
pub fn iterate() {
let mut m = linear::linear_map_with_capacity(4);

View file

@ -49,7 +49,7 @@ pub pure fn from_byte(b: u8) -> ~str {
}
/// Appends a character at the end of a string
pub fn push_char(s: &const ~str, ch: char) {
pub fn push_char(s: &mut ~str, ch: char) {
unsafe {
let code = ch as uint;
let nb = if code < max_one_b { 1u }
@ -140,7 +140,7 @@ pub pure fn from_chars(chs: &[char]) -> ~str {
/// Appends a string slice to the back of a string, without overallocating
#[inline(always)]
pub fn push_str_no_overallocate(lhs: &const ~str, rhs: &str) {
pub fn push_str_no_overallocate(lhs: &mut ~str, rhs: &str) {
unsafe {
let llen = lhs.len();
let rlen = rhs.len();
@ -157,7 +157,7 @@ pub fn push_str_no_overallocate(lhs: &const ~str, rhs: &str) {
}
/// Appends a string slice to the back of a string
#[inline(always)]
pub fn push_str(lhs: &const ~str, rhs: &str) {
pub fn push_str(lhs: &mut ~str, rhs: &str) {
unsafe {
let llen = lhs.len();
let rlen = rhs.len();
@ -203,6 +203,13 @@ pub pure fn connect(v: &[~str], sep: &str) -> ~str {
move s
}
/// Given a string, make a new string with repeated copies of it
pub fn repeat(ss: &str, nn: uint) -> ~str {
let mut acc = ~"";
for nn.times { acc += ss; }
move acc
}
/*
Section: Adding to and removing from a string
*/
@ -214,7 +221,7 @@ Section: Adding to and removing from a string
*
* If the string does not contain any characters
*/
pub fn pop_char(s: &const ~str) -> char {
pub fn pop_char(s: &mut ~str) -> char {
let end = len(*s);
assert end > 0u;
let {ch, prev} = char_range_at_reverse(*s, end);
@ -573,6 +580,40 @@ pub pure fn words(s: &str) -> ~[~str] {
split_nonempty(s, |c| char::is_whitespace(c))
}
/** Split a string into a vector of substrings,
* each of which is less than a limit
*/
pub fn split_within(ss: &str, lim: uint) -> ~[~str] {
let words = str::words(ss);
// empty?
if words == ~[] { return ~[]; }
let mut rows : ~[~str] = ~[];
let mut row : ~str = ~"";
for words.each |wptr| {
let word = copy *wptr;
// if adding this word to the row would go over the limit,
// then start a new row
if row.len() + word.len() + 1 > lim {
rows.push(copy row); // save previous row
row = move word; // start a new one
} else {
if row.len() > 0 { row += ~" " } // separate words
row += word; // append to this row
}
}
// save the last row
if row != ~"" { rows.push(move row); }
move rows
}
/// Convert a string to lowercase. ASCII only
pub pure fn to_lower(s: &str) -> ~str {
map(s,
@ -1361,7 +1402,7 @@ pub pure fn is_whitespace(s: &str) -> bool {
*
* Alphanumeric characters are determined by `char::is_alphanumeric`
*/
fn is_alphanumeric(s: &str) -> bool {
pure fn is_alphanumeric(s: &str) -> bool {
return all(s, char::is_alphanumeric);
}
@ -1473,6 +1514,11 @@ pub pure fn from_utf16(v: &[u16]) -> ~str {
move buf
}
pub pure fn with_capacity(capacity: uint) -> ~str {
let mut buf = ~"";
unsafe { reserve(&mut buf, capacity); }
move buf
}
/**
* As char_len but for a slice of a string
@ -1802,9 +1848,9 @@ pub pure fn as_buf<T>(s: &str, f: fn(*u8, uint) -> T) -> T {
* * s - A string
* * n - The number of bytes to reserve space for
*/
pub fn reserve(s: &const ~str, n: uint) {
pub fn reserve(s: &mut ~str, n: uint) {
unsafe {
let v: *mut ~[u8] = cast::transmute(copy s);
let v: *mut ~[u8] = cast::transmute(s);
vec::reserve(&mut *v, n + 1);
}
}
@ -1829,7 +1875,7 @@ pub fn reserve(s: &const ~str, n: uint) {
* * s - A string
* * n - The number of bytes to reserve space for
*/
pub fn reserve_at_least(s: &const ~str, n: uint) {
pub fn reserve_at_least(s: &mut ~str, n: uint) {
reserve(s, uint::next_power_of_two(n + 1u) - 1u)
}
@ -1906,7 +1952,7 @@ pub mod raw {
}
/// Converts a vector of bytes to a string.
pub pub unsafe fn from_bytes(v: &[const u8]) -> ~str {
pub unsafe fn from_bytes(v: &[const u8]) -> ~str {
do vec::as_const_buf(v) |buf, len| {
from_buf_len(buf, len)
}
@ -1974,7 +2020,7 @@ pub mod raw {
}
/// Appends a byte to a string. (Not UTF-8 safe).
pub unsafe fn push_byte(s: &const ~str, b: u8) {
pub unsafe fn push_byte(s: &mut ~str, b: u8) {
reserve_at_least(s, s.len() + 1);
do as_buf(*s) |buf, len| {
let buf: *mut u8 = ::cast::reinterpret_cast(&buf);
@ -1984,13 +2030,13 @@ pub mod raw {
}
/// Appends a vector of bytes to a string. (Not UTF-8 safe).
unsafe fn push_bytes(s: &const ~str, bytes: &[u8]) {
unsafe fn push_bytes(s: &mut ~str, bytes: &[u8]) {
reserve_at_least(s, s.len() + bytes.len());
for vec::each(bytes) |byte| { push_byte(s, *byte); }
}
/// Removes the last byte from a string and returns it. (Not UTF-8 safe).
pub unsafe fn pop_byte(s: &const ~str) -> u8 {
pub unsafe fn pop_byte(s: &mut ~str) -> u8 {
let len = len(*s);
assert (len > 0u);
let b = s[len - 1u];
@ -2008,7 +2054,7 @@ pub mod raw {
}
/// Sets the length of the string and adds the null terminator
pub unsafe fn set_len(v: &const ~str, new_len: uint) {
pub unsafe fn set_len(v: &mut ~str, new_len: uint) {
let v: **vec::raw::VecRepr = cast::transmute(copy v);
let repr: *vec::raw::VecRepr = *v;
(*repr).unboxed.fill = new_len + 1u;
@ -2029,23 +2075,23 @@ pub mod raw {
}
pub trait UniqueStr {
fn trim() -> self;
fn trim_left() -> self;
fn trim_right() -> self;
pub trait Trimmable {
pure fn trim() -> self;
pure fn trim_left() -> self;
pure fn trim_right() -> self;
}
/// Extension methods for strings
impl ~str: UniqueStr {
impl ~str: Trimmable {
/// Returns a string with leading and trailing whitespace removed
#[inline]
fn trim() -> ~str { trim(self) }
pure fn trim() -> ~str { trim(self) }
/// Returns a string with leading whitespace removed
#[inline]
fn trim_left() -> ~str { trim_left(self) }
pure fn trim_left() -> ~str { trim_left(self) }
/// Returns a string with trailing whitespace removed
#[inline]
fn trim_right() -> ~str { trim_right(self) }
pure fn trim_right() -> ~str { trim_right(self) }
}
#[cfg(notest)]
@ -2062,31 +2108,35 @@ pub mod traits {
pub mod traits {}
pub trait StrSlice {
fn all(it: fn(char) -> bool) -> bool;
fn any(it: fn(char) -> bool) -> bool;
fn contains(needle: &a/str) -> bool;
fn contains_char(needle: char) -> bool;
fn each(it: fn(u8) -> bool);
fn eachi(it: fn(uint, u8) -> bool);
fn each_char(it: fn(char) -> bool);
fn each_chari(it: fn(uint, char) -> bool);
fn ends_with(needle: &str) -> bool;
fn is_empty() -> bool;
fn is_not_empty() -> bool;
fn is_whitespace() -> bool;
fn is_alphanumeric() -> bool;
pure fn all(it: fn(char) -> bool) -> bool;
pure fn any(it: fn(char) -> bool) -> bool;
pure fn contains(needle: &a/str) -> bool;
pure fn contains_char(needle: char) -> bool;
pure fn each(it: fn(u8) -> bool);
pure fn eachi(it: fn(uint, u8) -> bool);
pure fn each_char(it: fn(char) -> bool);
pure fn each_chari(it: fn(uint, char) -> bool);
pure fn ends_with(needle: &str) -> bool;
pure fn is_empty() -> bool;
pure fn is_not_empty() -> bool;
pure fn is_whitespace() -> bool;
pure fn is_alphanumeric() -> bool;
pure fn len() -> uint;
pure fn slice(begin: uint, end: uint) -> ~str;
fn split(sepfn: fn(char) -> bool) -> ~[~str];
fn split_char(sep: char) -> ~[~str];
fn split_str(sep: &a/str) -> ~[~str];
fn starts_with(needle: &a/str) -> bool;
fn substr(begin: uint, n: uint) -> ~str;
pure fn split(sepfn: fn(char) -> bool) -> ~[~str];
pure fn split_char(sep: char) -> ~[~str];
pure fn split_str(sep: &a/str) -> ~[~str];
pure fn starts_with(needle: &a/str) -> bool;
pure fn substr(begin: uint, n: uint) -> ~str;
pure fn to_lower() -> ~str;
pure fn to_upper() -> ~str;
fn escape_default() -> ~str;
fn escape_unicode() -> ~str;
pure fn to_unique() -> ~str;
pure fn escape_default() -> ~str;
pure fn escape_unicode() -> ~str;
pure fn trim() -> ~str;
pure fn trim_left() -> ~str;
pure fn trim_right() -> ~str;
pure fn to_owned() -> ~str;
pure fn to_managed() -> @str;
pure fn char_at(i: uint) -> char;
}
@ -2097,54 +2147,56 @@ impl &str: StrSlice {
* contains no characters
*/
#[inline]
fn all(it: fn(char) -> bool) -> bool { all(self, it) }
pure fn all(it: fn(char) -> bool) -> bool { all(self, it) }
/**
* Return true if a predicate matches any character (and false if it
* matches none or there are no characters)
*/
#[inline]
fn any(it: fn(char) -> bool) -> bool { any(self, it) }
pure fn any(it: fn(char) -> bool) -> bool { any(self, it) }
/// Returns true if one string contains another
#[inline]
fn contains(needle: &a/str) -> bool { contains(self, needle) }
pure fn contains(needle: &a/str) -> bool { contains(self, needle) }
/// Returns true if a string contains a char
#[inline]
fn contains_char(needle: char) -> bool { contains_char(self, needle) }
pure fn contains_char(needle: char) -> bool {
contains_char(self, needle)
}
/// Iterate over the bytes in a string
#[inline]
fn each(it: fn(u8) -> bool) { each(self, it) }
pure fn each(it: fn(u8) -> bool) { each(self, it) }
/// Iterate over the bytes in a string, with indices
#[inline]
fn eachi(it: fn(uint, u8) -> bool) { eachi(self, it) }
pure fn eachi(it: fn(uint, u8) -> bool) { eachi(self, it) }
/// Iterate over the chars in a string
#[inline]
fn each_char(it: fn(char) -> bool) { each_char(self, it) }
pure fn each_char(it: fn(char) -> bool) { each_char(self, it) }
/// Iterate over the chars in a string, with indices
#[inline]
fn each_chari(it: fn(uint, char) -> bool) { each_chari(self, it) }
pure fn each_chari(it: fn(uint, char) -> bool) { each_chari(self, it) }
/// Returns true if one string ends with another
#[inline]
fn ends_with(needle: &str) -> bool { ends_with(self, needle) }
pure fn ends_with(needle: &str) -> bool { ends_with(self, needle) }
/// Returns true if the string has length 0
#[inline]
fn is_empty() -> bool { is_empty(self) }
pure fn is_empty() -> bool { is_empty(self) }
/// Returns true if the string has length greater than 0
#[inline]
fn is_not_empty() -> bool { is_not_empty(self) }
pure fn is_not_empty() -> bool { is_not_empty(self) }
/**
* Returns true if the string contains only whitespace
*
* Whitespace characters are determined by `char::is_whitespace`
*/
#[inline]
fn is_whitespace() -> bool { is_whitespace(self) }
pure fn is_whitespace() -> bool { is_whitespace(self) }
/**
* Returns true if the string contains only alphanumerics
*
* Alphanumeric characters are determined by `char::is_alphanumeric`
*/
#[inline]
fn is_alphanumeric() -> bool { is_alphanumeric(self) }
pure fn is_alphanumeric() -> bool { is_alphanumeric(self) }
#[inline]
/// Returns the size in bytes not counting the null terminator
pure fn len() -> uint { len(self) }
@ -2159,21 +2211,21 @@ impl &str: StrSlice {
pure fn slice(begin: uint, end: uint) -> ~str { slice(self, begin, end) }
/// Splits a string into substrings using a character function
#[inline]
fn split(sepfn: fn(char) -> bool) -> ~[~str] { split(self, sepfn) }
pure fn split(sepfn: fn(char) -> bool) -> ~[~str] { split(self, sepfn) }
/**
* Splits a string into substrings at each occurrence of a given character
*/
#[inline]
fn split_char(sep: char) -> ~[~str] { split_char(self, sep) }
pure fn split_char(sep: char) -> ~[~str] { split_char(self, sep) }
/**
* Splits a string into a vector of the substrings separated by a given
* string
*/
#[inline]
fn split_str(sep: &a/str) -> ~[~str] { split_str(self, sep) }
pure fn split_str(sep: &a/str) -> ~[~str] { split_str(self, sep) }
/// Returns true if one string starts with another
#[inline]
fn starts_with(needle: &a/str) -> bool { starts_with(self, needle) }
pure fn starts_with(needle: &a/str) -> bool { starts_with(self, needle) }
/**
* Take a substring of another.
*
@ -2181,7 +2233,7 @@ impl &str: StrSlice {
* `begin`.
*/
#[inline]
fn substr(begin: uint, n: uint) -> ~str { substr(self, begin, n) }
pure fn substr(begin: uint, n: uint) -> ~str { substr(self, begin, n) }
/// Convert a string to lowercase
#[inline]
pure fn to_lower() -> ~str { to_lower(self) }
@ -2190,13 +2242,31 @@ impl &str: StrSlice {
pure fn to_upper() -> ~str { to_upper(self) }
/// Escape each char in `s` with char::escape_default.
#[inline]
fn escape_default() -> ~str { escape_default(self) }
pure fn escape_default() -> ~str { escape_default(self) }
/// Escape each char in `s` with char::escape_unicode.
#[inline]
fn escape_unicode() -> ~str { escape_unicode(self) }
pure fn escape_unicode() -> ~str { escape_unicode(self) }
/// Returns a string with leading and trailing whitespace removed
#[inline]
pure fn trim() -> ~str { trim(self) }
/// Returns a string with leading whitespace removed
#[inline]
pure fn trim_left() -> ~str { trim_left(self) }
/// Returns a string with trailing whitespace removed
#[inline]
pure fn trim_right() -> ~str { trim_right(self) }
#[inline]
pure fn to_unique() -> ~str { self.slice(0, self.len()) }
pure fn to_owned() -> ~str { self.slice(0, self.len()) }
#[inline]
pure fn to_managed() -> @str {
let v = at_vec::from_fn(self.len() + 1, |i| {
if i == self.len() { 0 } else { self[i] }
});
unsafe { ::cast::transmute(v) }
}
#[inline]
pure fn char_at(i: uint) -> char { char_at(self, i) }
@ -2450,6 +2520,19 @@ mod tests {
assert ~[] == words(~"");
}
#[test]
fn test_split_within() {
assert split_within(~"", 0) == ~[];
assert split_within(~"", 15) == ~[];
assert split_within(~"hello", 15) == ~[~"hello"];
let data = ~"\nMary had a little lamb\nLittle lamb\n";
error!("~~~~ %?", split_within(data, 15));
assert split_within(data, 15) == ~[~"Mary had a",
~"little lamb",
~"Little lamb"];
}
#[test]
fn test_find_str() {
// byte positions
@ -2525,6 +2608,15 @@ mod tests {
t(~[~"hi"], ~" ", ~"hi");
}
#[test]
fn test_repeat() {
assert repeat(~"x", 4) == ~"xxxx";
assert repeat(~"hi", 4) == ~"hihihihi";
assert repeat(~"ไท华", 3) == ~"ไท华ไท华ไท华";
assert repeat(~"", 4) == ~"";
assert repeat(~"hi", 0) == ~"";
}
#[test]
fn test_to_upper() {
// libc::toupper, and hence str::to_upper
@ -2547,23 +2639,23 @@ mod tests {
#[test]
fn test_unsafe_slice() {
unsafe {
assert ~"ab" == raw::slice_bytes(~"abc", 0u, 2u);
assert ~"bc" == raw::slice_bytes(~"abc", 1u, 3u);
assert ~"" == raw::slice_bytes(~"abc", 1u, 1u);
assert ~"ab" == raw::slice_bytes(~"abc", 0, 2);
assert ~"bc" == raw::slice_bytes(~"abc", 1, 3);
assert ~"" == raw::slice_bytes(~"abc", 1, 1);
fn a_million_letter_a() -> ~str {
let mut i = 0;
let mut rs = ~"";
while i < 100000 { push_str(&mut rs, ~"aaaaaaaaaa"); i += 1; }
return rs;
move rs
}
fn half_a_million_letter_a() -> ~str {
let mut i = 0;
let mut rs = ~"";
while i < 100000 { push_str(&mut rs, ~"aaaaa"); i += 1; }
return rs;
move rs
}
assert half_a_million_letter_a() ==
raw::slice_bytes(a_million_letter_a(), 0u, 500000u);
raw::slice_bytes(a_million_letter_a(), 0u, 500000);
}
}
@ -2649,16 +2741,16 @@ mod tests {
#[test]
fn test_slice() {
assert ~"ab" == slice(~"abc", 0u, 2u);
assert ~"bc" == slice(~"abc", 1u, 3u);
assert ~"" == slice(~"abc", 1u, 1u);
assert ~"\u65e5" == slice(~"\u65e5\u672c", 0u, 3u);
assert ~"ab" == slice(~"abc", 0, 2);
assert ~"bc" == slice(~"abc", 1, 3);
assert ~"" == slice(~"abc", 1, 1);
assert ~"\u65e5" == slice(~"\u65e5\u672c", 0, 3);
let data = ~"ประเทศไทย中华";
assert ~"" == slice(data, 0u, 3u);
assert ~"" == slice(data, 3u, 6u);
assert ~"" == slice(data, 3u, 3u);
assert ~"" == slice(data, 30u, 33u);
assert ~"" == slice(data, 0, 3);
assert ~"" == slice(data, 3, 6);
assert ~"" == slice(data, 3, 3);
assert ~"" == slice(data, 30, 33);
fn a_million_letter_X() -> ~str {
let mut i = 0;
@ -2667,13 +2759,13 @@ mod tests {
push_str(&mut rs, ~"华华华华华华华华华华");
i += 1;
}
return rs;
move rs
}
fn half_a_million_letter_X() -> ~str {
let mut i = 0;
let mut rs = ~"";
while i < 100000 { push_str(&mut rs, ~"华华华华华"); i += 1; }
return rs;
move rs
}
assert half_a_million_letter_X() ==
slice(a_million_letter_X(), 0u, 3u * 500000u);
@ -3175,4 +3267,10 @@ mod tests {
assert escape_default(~"\U0001d4ea\r") == ~"\\U0001d4ea\\r";
}
#[test]
fn test_to_managed() {
assert (~"abc").to_managed() == @"abc";
assert view("abcdef", 1, 5).to_managed() == @"bcde";
}
}

View file

@ -153,7 +153,7 @@ pub mod tests {
assert f(20) == 30;
let original_closure: Closure = cast::transmute(f);
let original_closure: Closure = cast::transmute(move f);
let actual_function_pointer = original_closure.code;
let environment = original_closure.env;
@ -163,7 +163,7 @@ pub mod tests {
env: environment
};
let new_f: fn(int) -> int = cast::transmute(new_closure);
let new_f: fn(int) -> int = cast::transmute(move new_closure);
assert new_f(20) == 30;
}
}

View file

@ -217,7 +217,7 @@ pub type TaskOpts = {
// sidestep that whole issue by making builders uncopyable and making
// the run function move them in.
// FIXME (#2585): Replace the 'consumed' bit with move mode on self
// FIXME (#3724): Replace the 'consumed' bit with move mode on self
pub enum TaskBuilder = {
opts: TaskOpts,
gen_body: fn@(v: fn~()) -> fn~(),
@ -349,7 +349,7 @@ impl TaskBuilder {
* Fails if a future_result was already set for this task.
*/
fn future_result(blk: fn(v: future::Future<TaskResult>)) -> TaskBuilder {
// FIXME (#1087, #1857): Once linked failure and notification are
// FIXME (#3725): 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
// sending out messages.
@ -424,7 +424,11 @@ impl TaskBuilder {
mut notify_chan: move notify_chan,
sched: self.opts.sched
},
gen_body: |body| { wrapper(prev_gen_body(move body)) },
// tjc: I think this is the line that gets miscompiled
// w/ last-use off, if we leave out the move prev_gen_body?
// that makes no sense, though...
gen_body: |move prev_gen_body,
body| { wrapper(prev_gen_body(move body)) },
can_not_copy: None,
.. *self.consume()
})
@ -758,9 +762,9 @@ pub unsafe fn atomically<U>(f: fn() -> U) -> U {
fn test_cant_dup_task_builder() {
let b = task().unlinked();
do b.spawn { }
// FIXME(#2585): For now, this is a -runtime- failure, because we haven't
// got modes on self. When 2585 is fixed, this test should fail to compile
// instead, and should go in tests/compile-fail.
// FIXME(#3724): For now, this is a -runtime- failure, because we haven't
// got move mode on self. When 3724 is fixed, this test should fail to
// compile instead, and should go in tests/compile-fail.
do b.spawn { } // b should have been consumed by the previous call
}
@ -931,7 +935,7 @@ fn test_add_wrapper() {
let ch = comm::Chan(&po);
let b0 = task();
let b1 = do b0.add_wrapper |body| {
fn~() {
fn~(move body) {
body();
comm::send(ch, ());
}
@ -944,14 +948,15 @@ fn test_add_wrapper() {
#[ignore(cfg(windows))]
fn test_future_result() {
let mut result = None;
do task().future_result(|+r| { result = Some(r); }).spawn { }
assert future::get(&option::unwrap(result)) == Success;
do task().future_result(|+r| { result = Some(move r); }).spawn { }
assert future::get(&option::unwrap(move result)) == Success;
result = None;
do task().future_result(|+r| { result = Some(r); }).unlinked().spawn {
do task().future_result(|+r|
{ result = Some(move r); }).unlinked().spawn {
fail;
}
assert future::get(&option::unwrap(result)) == Failure;
assert future::get(&option::unwrap(move result)) == Failure;
}
#[test] #[should_fail] #[ignore(cfg(windows))]
@ -981,7 +986,7 @@ fn test_spawn_conversation() {
let (recv_str, send_int) = do spawn_conversation |recv_int, send_str| {
let input = comm::recv(recv_int);
let output = int::str(input);
comm::send(send_str, output);
comm::send(send_str, move output);
};
comm::send(send_int, 1);
assert comm::recv(recv_str) == ~"1";
@ -1134,7 +1139,7 @@ fn avoid_copying_the_body(spawnfn: fn(v: fn~())) {
let x = ~1;
let x_in_parent = ptr::addr_of(&(*x)) as uint;
do spawnfn {
do spawnfn |move x| {
let x_in_child = ptr::addr_of(&(*x)) as uint;
comm::send(ch, x_in_child);
}
@ -1160,7 +1165,7 @@ fn test_avoid_copying_the_body_spawn_listener() {
#[test]
fn test_avoid_copying_the_body_task_spawn() {
do avoid_copying_the_body |f| {
do task().spawn {
do task().spawn |move f| {
f();
}
}
@ -1178,7 +1183,7 @@ fn test_avoid_copying_the_body_spawn_listener_1() {
#[test]
fn test_avoid_copying_the_body_try() {
do avoid_copying_the_body |f| {
do try {
do try |move f| {
f()
};
}
@ -1187,7 +1192,7 @@ fn test_avoid_copying_the_body_try() {
#[test]
fn test_avoid_copying_the_body_unlinked() {
do avoid_copying_the_body |f| {
do spawn_unlinked {
do spawn_unlinked |move f| {
f();
}
}
@ -1212,7 +1217,7 @@ fn test_unkillable() {
// We want to do this after failing
do spawn_unlinked {
for iter::repeat(10u) { yield() }
for iter::repeat(10) { yield() }
ch.send(());
}
@ -1226,12 +1231,12 @@ fn test_unkillable() {
unsafe {
do unkillable {
let p = ~0;
let pp: *uint = cast::transmute(p);
let pp: *uint = cast::transmute(move p);
// If we are killed here then the box will leak
po.recv();
let _p: ~int = cast::transmute(pp);
let _p: ~int = cast::transmute(move pp);
}
}
@ -1246,8 +1251,8 @@ fn test_unkillable_nested() {
let (ch, po) = pipes::stream();
// We want to do this after failing
do spawn_unlinked {
for iter::repeat(10u) { yield() }
do spawn_unlinked |move ch| {
for iter::repeat(10) { yield() }
ch.send(());
}
@ -1262,12 +1267,12 @@ fn test_unkillable_nested() {
do unkillable {
do unkillable {} // Here's the difference from the previous test.
let p = ~0;
let pp: *uint = cast::transmute(p);
let pp: *uint = cast::transmute(move p);
// If we are killed here then the box will leak
po.recv();
let _p: ~int = cast::transmute(pp);
let _p: ~int = cast::transmute(move pp);
}
}
@ -1311,7 +1316,7 @@ fn test_child_doesnt_ref_parent() {
fn test_sched_thread_per_core() {
let (chan, port) = pipes::stream();
do spawn_sched(ThreadPerCore) {
do spawn_sched(ThreadPerCore) |move chan| {
let cores = rt::rust_num_threads();
let reported_threads = rt::rust_sched_threads();
assert(cores as uint == reported_threads as uint);
@ -1325,7 +1330,7 @@ fn test_sched_thread_per_core() {
fn test_spawn_thread_on_demand() {
let (chan, port) = pipes::stream();
do spawn_sched(ManualThreads(2)) {
do spawn_sched(ManualThreads(2)) |move chan| {
let max_threads = rt::rust_sched_threads();
assert(max_threads as int == 2);
let running_threads = rt::rust_sched_current_nonlazy_threads();
@ -1333,7 +1338,7 @@ fn test_spawn_thread_on_demand() {
let (chan2, port2) = pipes::stream();
do spawn() {
do spawn() |move chan2| {
chan2.send(());
}

View file

@ -312,8 +312,8 @@ fn TCB(me: *rust_task, tasks: TaskGroupArc, ancestors: AncestorList,
TCB {
me: me,
tasks: tasks,
ancestors: ancestors,
tasks: move tasks,
ancestors: move ancestors,
is_main: is_main,
notifier: move notifier
}
@ -330,7 +330,7 @@ struct AutoNotify {
fn AutoNotify(chan: Chan<Notification>) -> AutoNotify {
AutoNotify {
notify_chan: chan,
notify_chan: move chan,
failed: true // Un-set above when taskgroup successfully made.
}
}
@ -652,7 +652,7 @@ fn test_spawn_raw_unsupervise() {
mut notify_chan: None,
.. default_task_opts()
};
do spawn_raw(opts) {
do spawn_raw(move opts) {
fail;
}
}
@ -667,7 +667,7 @@ fn test_spawn_raw_notify_success() {
notify_chan: Some(move notify_ch),
.. default_task_opts()
};
do spawn_raw(opts) |move task_ch| {
do spawn_raw(move opts) |move task_ch| {
task_ch.send(get_task());
}
let task_ = task_po.recv();
@ -683,10 +683,10 @@ fn test_spawn_raw_notify_failure() {
let opts = {
linked: false,
notify_chan: Some(notify_ch),
notify_chan: Some(move notify_ch),
.. default_task_opts()
};
do spawn_raw(opts) {
do spawn_raw(move opts) |move task_ch| {
task_ch.send(get_task());
fail;
}

View file

@ -8,80 +8,82 @@ The `ToStr` trait for converting to strings
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];
pub trait ToStr { fn to_str() -> ~str; }
pub trait ToStr { pure fn to_str() -> ~str; }
impl int: ToStr {
fn to_str() -> ~str { int::str(self) }
pure fn to_str() -> ~str { int::str(self) }
}
impl i8: ToStr {
fn to_str() -> ~str { i8::str(self) }
pure fn to_str() -> ~str { i8::str(self) }
}
impl i16: ToStr {
fn to_str() -> ~str { i16::str(self) }
pure fn to_str() -> ~str { i16::str(self) }
}
impl i32: ToStr {
fn to_str() -> ~str { i32::str(self) }
pure fn to_str() -> ~str { i32::str(self) }
}
impl i64: ToStr {
fn to_str() -> ~str { i64::str(self) }
pure fn to_str() -> ~str { i64::str(self) }
}
impl uint: ToStr {
fn to_str() -> ~str { uint::str(self) }
pure fn to_str() -> ~str { uint::str(self) }
}
impl u8: ToStr {
fn to_str() -> ~str { u8::str(self) }
pure fn to_str() -> ~str { u8::str(self) }
}
impl u16: ToStr {
fn to_str() -> ~str { u16::str(self) }
pure fn to_str() -> ~str { u16::str(self) }
}
impl u32: ToStr {
fn to_str() -> ~str { u32::str(self) }
pure fn to_str() -> ~str { u32::str(self) }
}
impl u64: ToStr {
fn to_str() -> ~str { u64::str(self) }
pure fn to_str() -> ~str { u64::str(self) }
}
impl float: ToStr {
fn to_str() -> ~str { float::to_str(self, 4u) }
pure fn to_str() -> ~str { float::to_str(self, 4u) }
}
impl f32: ToStr {
fn to_str() -> ~str { float::to_str(self as float, 4u) }
pure fn to_str() -> ~str { float::to_str(self as float, 4u) }
}
impl f64: ToStr {
fn to_str() -> ~str { float::to_str(self as float, 4u) }
pure fn to_str() -> ~str { float::to_str(self as float, 4u) }
}
impl bool: ToStr {
fn to_str() -> ~str { bool::to_str(self) }
pure fn to_str() -> ~str { bool::to_str(self) }
}
impl (): ToStr {
fn to_str() -> ~str { ~"()" }
pure fn to_str() -> ~str { ~"()" }
}
impl ~str: ToStr {
fn to_str() -> ~str { copy self }
pure fn to_str() -> ~str { copy self }
}
impl &str: ToStr {
fn to_str() -> ~str { str::from_slice(self) }
pure fn to_str() -> ~str { str::from_slice(self) }
}
impl @str: ToStr {
fn to_str() -> ~str { str::from_slice(self) }
pure fn to_str() -> ~str { str::from_slice(self) }
}
impl<A: ToStr Copy, B: ToStr Copy> (A, B): ToStr {
fn to_str() -> ~str {
pure fn to_str() -> ~str {
let (a, b) = self;
~"(" + a.to_str() + ~", " + b.to_str() + ~")"
}
}
impl<A: ToStr Copy, B: ToStr Copy, C: ToStr Copy> (A, B, C): ToStr {
fn to_str() -> ~str {
pure fn to_str() -> ~str {
let (a, b, c) = self;
~"(" + a.to_str() + ~", " + b.to_str() + ~", " + c.to_str() + ~")"
}
}
impl<A: ToStr> ~[A]: ToStr {
fn to_str() -> ~str {
pure fn to_str() -> ~str unsafe {
// Bleh -- not really unsafe
// push_str and push_char
let mut acc = ~"[", first = true;
for vec::each(self) |elt| {
for vec::each(self) |elt| unsafe {
if first { first = false; }
else { str::push_str(&mut acc, ~", "); }
str::push_str(&mut acc, elt.to_str());
@ -92,10 +94,10 @@ impl<A: ToStr> ~[A]: ToStr {
}
impl<A: ToStr> @A: ToStr {
fn to_str() -> ~str { ~"@" + (*self).to_str() }
pure fn to_str() -> ~str { ~"@" + (*self).to_str() }
}
impl<A: ToStr> ~A: ToStr {
fn to_str() -> ~str { ~"~" + (*self).to_str() }
pure fn to_str() -> ~str { ~"~" + (*self).to_str() }
}
#[cfg(test)]

View file

@ -6,13 +6,13 @@
use cmp::{Eq, Ord};
pub trait TupleOps<T,U> {
pub trait CopyableTuple<T, U> {
pure fn first() -> T;
pure fn second() -> U;
pure fn swap() -> (U, T);
}
impl<T: Copy, U: Copy> (T, U): TupleOps<T,U> {
impl<T: Copy, U: Copy> (T, U): CopyableTuple<T, U> {
/// Return the first element of self
pure fn first() -> T {
@ -34,6 +34,24 @@ impl<T: Copy, U: Copy> (T, U): TupleOps<T,U> {
}
pub trait ImmutableTuple<T, U> {
pure fn first_ref(&self) -> &self/T;
pure fn second_ref(&self) -> &self/U;
}
impl<T, U> (T, U): ImmutableTuple<T, U> {
pure fn first_ref(&self) -> &self/T {
match *self {
(ref t, _) => t,
}
}
pure fn second_ref(&self) -> &self/U {
match *self {
(_, ref u) => u,
}
}
}
pub trait ExtendedTupleOps<A,B> {
fn zip(&self) -> ~[(A, B)];
fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C];
@ -145,6 +163,13 @@ impl<A: Ord, B: Ord, C: Ord> (A, B, C) : Ord {
pure fn gt(other: &(A, B, C)) -> bool { (*other).lt(&self) }
}
#[test]
fn test_tuple_ref() {
let x = (~"foo", ~"bar");
assert x.first_ref() == &~"foo";
assert x.second_ref() == &~"bar";
}
#[test]
#[allow(non_implicitly_copyable_typarams)]
fn test_tuple() {

View file

@ -187,19 +187,7 @@ pub pure fn to_str_bytes<U>(neg: bool, num: T, radix: uint,
// Enough room to hold any number in any radix.
// Worst case: 64-bit number, binary-radix, with
// a leading negative sign = 65 bytes.
let buf : [mut u8]/65 =
[mut
0u8,0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8,0u8,
0u8,0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8,0u8,
0u8,0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8,0u8,
0u8,0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8,0u8,
0u8,0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8,0u8,
0u8,0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8,0u8,
0u8,0u8,0u8,0u8,0u8
]/65;
let buf : [mut u8 * 65] = [mut 0u8, ..65];
// FIXME (#2649): post-snapshot, you can do this without the raw
// pointers and unsafe bits, and the codegen will prove it's all
@ -232,7 +220,7 @@ pub pure fn to_str_bytes<U>(neg: bool, num: T, radix: uint,
}
/// Convert to a string
pub fn str(i: T) -> ~str { return to_str(i, 10u); }
pub pure fn str(i: T) -> ~str { return to_str(i, 10u); }
#[test]
pub fn test_to_str() {

View file

@ -100,7 +100,7 @@ mod tests {
let x = ~[(5, false)];
//FIXME #3387 assert x.eq(id(copy x));
let y = copy x;
assert x.eq(&id(y));
assert x.eq(&id(move y));
}
#[test]
fn test_swap() {

View file

@ -340,15 +340,15 @@ pub fn splitn<T: Copy>(v: &[T], n: uint, f: fn(t: &T) -> bool) -> ~[~[T]] {
*/
pub fn rsplit<T: Copy>(v: &[T], f: fn(t: &T) -> bool) -> ~[~[T]] {
let ln = len(v);
if (ln == 0u) { return ~[] }
if (ln == 0) { return ~[] }
let mut end = ln;
let mut result = ~[];
while end > 0u {
match rposition_between(v, 0u, end, f) {
while end > 0 {
match rposition_between(v, 0, end, f) {
None => break,
Some(i) => {
result.push(slice(v, i + 1u, end));
result.push(slice(v, i + 1, end));
end = i;
}
}
@ -416,7 +416,7 @@ pub fn shift<T>(v: &mut ~[T]) -> T {
pub fn unshift<T>(v: &mut ~[T], x: T) {
let mut vv = ~[move x];
*v <-> vv;
v.push_all_move(vv);
v.push_all_move(move vv);
}
pub fn consume<T>(v: ~[T], f: fn(uint, v: T)) unsafe {
@ -433,7 +433,7 @@ pub fn consume<T>(v: ~[T], f: fn(uint, v: T)) unsafe {
}
pub fn consume_mut<T>(v: ~[mut T], f: fn(uint, v: T)) {
consume(vec::from_mut(v), f)
consume(vec::from_mut(move v), f)
}
/// Remove the last element from a vector and return it
@ -591,7 +591,7 @@ pub pure fn append_one<T>(lhs: ~[T], x: T) -> ~[T] {
#[inline(always)]
pure fn append_mut<T: Copy>(lhs: ~[mut T], rhs: &[const T]) -> ~[mut T] {
to_mut(append(from_mut(lhs), rhs))
to_mut(append(from_mut(move lhs), rhs))
}
/**
@ -1621,7 +1621,7 @@ impl<T> ~[T]: MutableVector<T> {
}
fn unshift(&mut self, x: T) {
unshift(self, x)
unshift(self, move x)
}
fn swap_remove(&mut self, index: uint) -> T {
@ -1657,9 +1657,29 @@ impl<T: Eq> ~[T]: MutableEqVector<T> {
}
}
/**
* Constructs a vector from an unsafe pointer to a buffer
*
* # Arguments
*
* * ptr - An unsafe pointer to a buffer of `T`
* * elts - The number of elements in the buffer
*/
// Wrapper for fn in raw: needs to be called by net_tcp::on_tcp_read_cb
pub unsafe fn from_buf<T>(ptr: *T, elts: uint) -> ~[T] {
raw::from_buf_raw(ptr, elts)
}
/// The internal 'unboxed' representation of a vector
pub struct UnboxedVecRepr {
mut fill: uint,
mut alloc: uint,
data: u8
}
/// Unsafe operations
pub mod raw {
// FIXME: This should have crate visibility (#1893 blocks that)
mod raw {
/// The internal representation of a (boxed) vector
pub struct VecRepr {
@ -1667,34 +1687,11 @@ pub mod raw {
unboxed: UnboxedVecRepr
}
/// The internal 'unboxed' representation of a vector
pub struct UnboxedVecRepr {
mut fill: uint,
mut alloc: uint,
data: u8
}
pub type SliceRepr = {
mut data: *u8,
mut len: uint
};
/**
* Constructs a vector from an unsafe pointer to a buffer
*
* # Arguments
*
* * ptr - An unsafe pointer to a buffer of `T`
* * elts - The number of elements in the buffer
*/
#[inline(always)]
pub unsafe fn from_buf<T>(ptr: *T, elts: uint) -> ~[T] {
let mut dst = with_capacity(elts);
set_len(&mut dst, elts);
as_mut_buf(dst, |p_dst, _len_dst| ptr::memcpy(p_dst, ptr, elts));
move dst
}
/**
* Sets the length of a vector
*
@ -1775,6 +1772,23 @@ pub mod raw {
}
}
/**
* Constructs a vector from an unsafe pointer to a buffer
*
* # Arguments
*
* * ptr - An unsafe pointer to a buffer of `T`
* * elts - The number of elements in the buffer
*/
// Was in raw, but needs to be called by net_tcp::on_tcp_read_cb
#[inline(always)]
pub unsafe fn from_buf_raw<T>(ptr: *T, elts: uint) -> ~[T] {
let mut dst = with_capacity(elts);
set_len(&mut dst, elts);
as_mut_buf(dst, |p_dst, _len_dst| ptr::memcpy(p_dst, ptr, elts));
move dst
}
/**
* Copies data from one vector to another.
*
@ -1959,7 +1973,7 @@ mod tests {
// Test on-stack copy-from-buf.
let a = ~[1, 2, 3];
let mut ptr = raw::to_ptr(a);
let b = raw::from_buf(ptr, 3u);
let b = from_buf(ptr, 3u);
assert (len(b) == 3u);
assert (b[0] == 1);
assert (b[1] == 2);
@ -1968,7 +1982,7 @@ mod tests {
// Test on-heap copy-from-buf.
let c = ~[1, 2, 3, 4, 5];
ptr = raw::to_ptr(c);
let d = raw::from_buf(ptr, 5u);
let d = from_buf(ptr, 5u);
assert (len(d) == 5u);
assert (d[0] == 1);
assert (d[1] == 2);
@ -2194,7 +2208,7 @@ mod tests {
#[test]
fn test_dedup() {
fn case(a: ~[uint], b: ~[uint]) {
let mut v = a;
let mut v = move a;
v.dedup();
assert(v == b);
}
@ -2450,13 +2464,13 @@ mod tests {
let v1 = ~[1, 2, 3];
let v2 = ~[4, 5, 6];
let z1 = zip(v1, v2);
let z1 = zip(move v1, move v2);
assert ((1, 4) == z1[0]);
assert ((2, 5) == z1[1]);
assert ((3, 6) == z1[2]);
let (left, right) = unzip(z1);
let (left, right) = unzip(move z1);
assert ((1, 4) == (left[0], right[0]));
assert ((2, 5) == (left[1], right[1]));
@ -2754,7 +2768,7 @@ mod tests {
unsafe {
let x = ~[1, 2, 3];
let addr = raw::to_ptr(x);
let x_mut = to_mut(x);
let x_mut = to_mut(move x);
let addr_mut = raw::to_ptr(x_mut);
assert addr == addr_mut;
}
@ -2765,7 +2779,7 @@ mod tests {
unsafe {
let x = ~[mut 1, 2, 3];
let addr = raw::to_ptr(x);
let x_imm = from_mut(x);
let x_imm = from_mut(move x);
let addr_imm = raw::to_ptr(x_imm);
assert addr == addr_imm;
}
@ -2963,7 +2977,7 @@ mod tests {
fn test_consume_fail() {
let v = ~[(~0, @0), (~0, @0), (~0, @0), (~0, @0)];
let mut i = 0;
do consume(v) |_i, _elt| {
do consume(move v) |_i, _elt| {
if i == 2 {
fail
}
@ -2977,7 +2991,7 @@ mod tests {
fn test_consume_mut_fail() {
let v = ~[mut (~0, @0), (~0, @0), (~0, @0), (~0, @0)];
let mut i = 0;
do consume_mut(v) |_i, _elt| {
do consume_mut(move v) |_i, _elt| {
if i == 2 {
fail
}
@ -3020,7 +3034,7 @@ mod tests {
fn test_map_consume_fail() {
let v = ~[(~0, @0), (~0, @0), (~0, @0), (~0, @0)];
let mut i = 0;
do map_consume(v) |_elt| {
do map_consume(move v) |_elt| {
if i == 2 {
fail
}

View file

@ -124,7 +124,7 @@ 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),
failed: false, data: user_data };
failed: false, data: move user_data };
MutexARC { x: unsafe { shared_mutable_state(move data) } }
}
@ -190,7 +190,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
// FIXME(#3724) make this a by-move method on the arc
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) };
@ -258,7 +258,7 @@ 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),
failed: false, data: user_data };
failed: false, data: move user_data };
RWARC { x: unsafe { shared_mutable_state(move data) }, cant_nest: () }
}
@ -368,7 +368,7 @@ impl<T: Const Send> &RWARC<T> {
* Will additionally fail if another task has failed while accessing the arc
* in write mode.
*/
// FIXME(#2585) make this a by-move method on the arc
// FIXME(#3724) make this a by-move method on the arc
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) };
@ -448,7 +448,7 @@ mod tests {
let (c, p) = pipes::stream();
do task::spawn() {
do task::spawn() |move c| {
let p = pipes::PortSet();
c.send(p.chan());
@ -471,8 +471,8 @@ mod tests {
let arc = ~MutexARC(false);
let arc2 = ~arc.clone();
let (c,p) = pipes::oneshot();
let (c,p) = (~mut Some(c), ~mut Some(p));
do task::spawn {
let (c,p) = (~mut Some(move c), ~mut Some(move p));
do task::spawn |move arc2, move p| {
// wait until parent gets in
pipes::recv_one(option::swap_unwrap(p));
do arc2.access_cond |state, cond| {
@ -494,7 +494,7 @@ mod tests {
let arc2 = ~arc.clone();
let (c,p) = pipes::stream();
do task::spawn_unlinked {
do task::spawn_unlinked |move arc2, move p| {
let _ = p.recv();
do arc2.access_cond |one, cond| {
cond.signal();
@ -513,7 +513,7 @@ mod tests {
fn test_mutex_arc_poison() {
let arc = ~MutexARC(1);
let arc2 = ~arc.clone();
do task::try {
do task::try |move arc2| {
do arc2.access |one| {
assert *one == 2;
}
@ -527,21 +527,21 @@ mod tests {
let arc = MutexARC(1);
let arc2 = ~(&arc).clone();
let (c,p) = pipes::stream();
do task::spawn {
do task::spawn |move c, move arc2| {
do arc2.access |one| {
c.send(());
assert *one == 2;
}
}
let _ = p.recv();
let one = unwrap_mutex_arc(arc);
let one = unwrap_mutex_arc(move arc);
assert one == 1;
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_rw_arc_poison_wr() {
let arc = ~RWARC(1);
let arc2 = ~arc.clone();
do task::try {
do task::try |move arc2| {
do arc2.write |one| {
assert *one == 2;
}
@ -554,7 +554,7 @@ mod tests {
fn test_rw_arc_poison_ww() {
let arc = ~RWARC(1);
let arc2 = ~arc.clone();
do task::try {
do task::try |move arc2| {
do arc2.write |one| {
assert *one == 2;
}
@ -567,7 +567,7 @@ mod tests {
fn test_rw_arc_poison_dw() {
let arc = ~RWARC(1);
let arc2 = ~arc.clone();
do task::try {
do task::try |move arc2| {
do arc2.write_downgrade |write_mode| {
do (&write_mode).write |one| {
assert *one == 2;
@ -582,7 +582,7 @@ mod tests {
fn test_rw_arc_no_poison_rr() {
let arc = ~RWARC(1);
let arc2 = ~arc.clone();
do task::try {
do task::try |move arc2| {
do arc2.read |one| {
assert *one == 2;
}
@ -595,7 +595,7 @@ mod tests {
fn test_rw_arc_no_poison_rw() {
let arc = ~RWARC(1);
let arc2 = ~arc.clone();
do task::try {
do task::try |move arc2| {
do arc2.read |one| {
assert *one == 2;
}
@ -608,9 +608,9 @@ mod tests {
fn test_rw_arc_no_poison_dr() {
let arc = ~RWARC(1);
let arc2 = ~arc.clone();
do task::try {
do task::try |move arc2| {
do arc2.write_downgrade |write_mode| {
let read_mode = arc2.downgrade(write_mode);
let read_mode = arc2.downgrade(move write_mode);
do (&read_mode).read |one| {
assert *one == 2;
}
@ -626,7 +626,7 @@ mod tests {
let arc2 = ~arc.clone();
let (c,p) = pipes::stream();
do task::spawn {
do task::spawn |move arc2, move c| {
do arc2.write |num| {
for 10.times {
let tmp = *num;
@ -642,7 +642,8 @@ mod tests {
let mut children = ~[];
for 5.times {
let arc3 = ~arc.clone();
do task::task().future_result(|+r| children.push(r)).spawn {
do task::task().future_result(|+r| children.push(move r)).spawn
|move arc3| {
do arc3.read |num| {
assert *num >= 0;
}
@ -670,9 +671,9 @@ mod tests {
let mut reader_convos = ~[];
for 10.times {
let ((rc1,rp1),(rc2,rp2)) = (pipes::stream(),pipes::stream());
reader_convos.push((rc1,rp2));
reader_convos.push((move rc1, move rp2));
let arcn = ~arc.clone();
do task::spawn {
do task::spawn |move rp1, move rc2, move arcn| {
rp1.recv(); // wait for downgrader to give go-ahead
do arcn.read |state| {
assert *state == 31337;
@ -684,7 +685,7 @@ mod tests {
// Writer task
let arc2 = ~arc.clone();
let ((wc1,wp1),(wc2,wp2)) = (pipes::stream(),pipes::stream());
do task::spawn {
do task::spawn |move arc2, move wc2, move wp1| {
wp1.recv();
do arc2.write_cond |state, cond| {
assert *state == 0;
@ -717,7 +718,7 @@ mod tests {
}
}
}
let read_mode = arc.downgrade(write_mode);
let read_mode = arc.downgrade(move write_mode);
do (&read_mode).read |state| {
// complete handshake with other readers
for vec::each(reader_convos) |x| {

View file

@ -244,7 +244,7 @@ fn test_arena_destructors() {
do arena.alloc { @i };
// Allocate something with funny size and alignment, to keep
// things interesting.
do arena.alloc { [0u8, 1u8, 2u8]/3 };
do arena.alloc { [0u8, 1u8, 2u8] };
}
}
@ -258,7 +258,7 @@ fn test_arena_destructors_fail() {
do arena.alloc { @i };
// Allocate something with funny size and alignment, to keep
// things interesting.
do arena.alloc { [0u8, 1u8, 2u8]/3 };
do arena.alloc { [0u8, 1u8, 2u8] };
}
// Now, fail while allocating
do arena.alloc::<@int> {

View file

@ -96,7 +96,7 @@ struct BigBitv {
}
fn BigBitv(storage: ~[mut uint]) -> BigBitv {
BigBitv {storage: storage}
BigBitv {storage: move storage}
}
/**
@ -223,7 +223,7 @@ pub fn Bitv (nbits: uint, init: bool) -> Bitv {
let s = to_mut(from_elem(nelems, elem));
Big(~BigBitv(move s))
};
Bitv {rep: rep, nbits: nbits}
Bitv {rep: move rep, nbits: nbits}
}
priv impl Bitv {
@ -301,7 +301,7 @@ impl Bitv {
let st = to_mut(from_elem(self.nbits / uint_bits + 1, 0));
let len = st.len();
for uint::range(0, len) |i| { st[i] = b.storage[i]; };
Bitv{nbits: self.nbits, rep: Big(~BigBitv{storage: st})}
Bitv{nbits: self.nbits, rep: Big(~BigBitv{storage: move st})}
}
}
}

View file

@ -57,7 +57,7 @@ fn test_basic() {
let value = value_cell.take();
assert value == ~10;
assert value_cell.is_empty();
value_cell.put_back(value);
value_cell.put_back(move value);
assert !value_cell.is_empty();
}

View file

@ -52,12 +52,12 @@ pub fn DuplexStream<T: Send, U: Send>()
let (c2, p1) = pipes::stream();
let (c1, p2) = pipes::stream();
(DuplexStream {
chan: c1,
port: p1
chan: move c1,
port: move p1
},
DuplexStream {
chan: c2,
port: p2
chan: move c2,
port: move p2
})
}

View file

@ -1,21 +1,35 @@
#[forbid(deprecated_mode)];
use serialization;
// Simple Extensible Binary Markup Language (ebml) reader and writer on a
// cursor model. See the specification here:
// http://www.matroska.org/technical/specs/rfc/index.html
use core::Option;
use option::{Some, None};
type EbmlTag = {id: uint, size: uint};
struct EbmlTag {
id: uint,
size: uint,
}
type EbmlState = {ebml_tag: EbmlTag, tag_pos: uint, data_pos: uint};
struct EbmlState {
ebml_tag: EbmlTag,
tag_pos: uint,
data_pos: uint,
}
// FIXME (#2739): When we have module renaming, make "reader" and "writer"
// separate modules within this file.
// ebml reading
pub type Doc = {data: @~[u8], start: uint, end: uint};
struct Doc {
data: @~[u8],
start: uint,
end: uint,
}
type TaggedDoc = {tag: uint, doc: Doc};
struct TaggedDoc {
tag: uint,
doc: Doc,
}
impl Doc: ops::Index<uint,Doc> {
pure fn index(tag: uint) -> Doc {
@ -49,15 +63,17 @@ fn vuint_at(data: &[u8], start: uint) -> {val: uint, next: uint} {
}
pub fn Doc(data: @~[u8]) -> Doc {
return {data: data, start: 0u, end: vec::len::<u8>(*data)};
Doc { data: data, start: 0u, end: vec::len::<u8>(*data) }
}
pub fn doc_at(data: @~[u8], start: uint) -> TaggedDoc {
let elt_tag = vuint_at(*data, start);
let elt_size = vuint_at(*data, elt_tag.next);
let end = elt_size.next + elt_size.val;
return {tag: elt_tag.val,
doc: {data: data, start: elt_size.next, end: end}};
TaggedDoc {
tag: elt_tag.val,
doc: Doc { data: data, start: elt_size.next, end: end }
}
}
pub fn maybe_get_doc(d: Doc, tg: uint) -> Option<Doc> {
@ -67,19 +83,15 @@ pub fn maybe_get_doc(d: Doc, tg: uint) -> Option<Doc> {
let elt_size = vuint_at(*d.data, elt_tag.next);
pos = elt_size.next + elt_size.val;
if elt_tag.val == tg {
return Some::<Doc>({
data: d.data,
start: elt_size.next,
end: pos
});
return Some(Doc { data: d.data, start: elt_size.next, end: pos });
}
}
return None::<Doc>;
None
}
pub fn get_doc(d: Doc, tg: uint) -> Doc {
match maybe_get_doc(d, tg) {
Some(d) => return d,
Some(d) => d,
None => {
error!("failed to find block with tag %u", tg);
fail;
@ -93,7 +105,8 @@ pub fn docs(d: Doc, it: fn(uint, Doc) -> bool) {
let elt_tag = vuint_at(*d.data, pos);
let elt_size = vuint_at(*d.data, elt_tag.next);
pos = elt_size.next + elt_size.val;
if !it(elt_tag.val, {data: d.data, start: elt_size.next, end: pos}) {
let doc = Doc { data: d.data, start: elt_size.next, end: pos };
if !it(elt_tag.val, doc) {
break;
}
}
@ -106,7 +119,8 @@ pub fn tagged_docs(d: Doc, tg: uint, it: fn(Doc) -> bool) {
let elt_size = vuint_at(*d.data, elt_tag.next);
pos = elt_size.next + elt_size.val;
if elt_tag.val == tg {
if !it({data: d.data, start: elt_size.next, end: pos}) {
let doc = Doc { data: d.data, start: elt_size.next, end: pos };
if !it(doc) {
break;
}
}
@ -116,29 +130,29 @@ pub fn tagged_docs(d: Doc, tg: uint, it: fn(Doc) -> bool) {
pub fn doc_data(d: Doc) -> ~[u8] { vec::slice::<u8>(*d.data, d.start, d.end) }
pub fn with_doc_data<T>(d: Doc, f: fn(x: &[u8]) -> T) -> T {
return f(vec::view(*d.data, d.start, d.end));
f(vec::view(*d.data, d.start, d.end))
}
pub fn doc_as_str(d: Doc) -> ~str { return str::from_bytes(doc_data(d)); }
pub fn doc_as_str(d: Doc) -> ~str { str::from_bytes(doc_data(d)) }
pub fn doc_as_u8(d: Doc) -> u8 {
assert d.end == d.start + 1u;
return (*d.data)[d.start];
(*d.data)[d.start]
}
pub fn doc_as_u16(d: Doc) -> u16 {
assert d.end == d.start + 2u;
return io::u64_from_be_bytes(*d.data, d.start, 2u) as u16;
io::u64_from_be_bytes(*d.data, d.start, 2u) as u16
}
pub fn doc_as_u32(d: Doc) -> u32 {
assert d.end == d.start + 4u;
return io::u64_from_be_bytes(*d.data, d.start, 4u) as u32;
io::u64_from_be_bytes(*d.data, d.start, 4u) as u32
}
pub fn doc_as_u64(d: Doc) -> u64 {
assert d.end == d.start + 8u;
return io::u64_from_be_bytes(*d.data, d.start, 8u);
io::u64_from_be_bytes(*d.data, d.start, 8u)
}
pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 }
@ -147,10 +161,9 @@ pub fn doc_as_i32(d: Doc) -> i32 { doc_as_u32(d) as i32 }
pub fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 }
// ebml writing
type Writer_ = {writer: io::Writer, mut size_positions: ~[uint]};
pub enum Writer {
Writer_(Writer_)
struct Serializer {
writer: io::Writer,
priv mut size_positions: ~[uint],
}
fn write_sized_vuint(w: io::Writer, n: uint, size: uint) {
@ -173,13 +186,13 @@ fn write_vuint(w: io::Writer, n: uint) {
fail fmt!("vint to write too big: %?", n);
}
pub fn Writer(w: io::Writer) -> Writer {
pub fn Serializer(w: io::Writer) -> Serializer {
let size_positions: ~[uint] = ~[];
return Writer_({writer: w, mut size_positions: size_positions});
Serializer { writer: w, mut size_positions: size_positions }
}
// FIXME (#2741): Provide a function to write the standard ebml header.
impl Writer {
impl Serializer {
fn start_tag(tag_id: uint) {
debug!("Start tag %u", tag_id);
@ -295,12 +308,7 @@ enum EbmlSerializerTag {
EsLabel // Used only when debugging
}
trait SerializerPriv {
fn _emit_tagged_uint(t: EbmlSerializerTag, v: uint);
fn _emit_label(label: &str);
}
impl ebml::Writer: SerializerPriv {
priv impl Serializer {
// used internally to emit things like the vector length and so on
fn _emit_tagged_uint(t: EbmlSerializerTag, v: uint) {
assert v <= 0xFFFF_FFFF_u;
@ -318,89 +326,123 @@ impl ebml::Writer: SerializerPriv {
}
}
impl ebml::Writer {
fn emit_opaque(f: fn()) {
impl Serializer {
fn emit_opaque(&self, f: fn()) {
do self.wr_tag(EsOpaque as uint) {
f()
}
}
}
impl ebml::Writer: serialization::Serializer {
fn emit_nil() {}
impl Serializer: serialization::Serializer {
fn emit_nil(&self) {}
fn emit_uint(v: uint) { self.wr_tagged_u64(EsUint as uint, v as u64); }
fn emit_u64(v: u64) { self.wr_tagged_u64(EsU64 as uint, v); }
fn emit_u32(v: u32) { self.wr_tagged_u32(EsU32 as uint, v); }
fn emit_u16(v: u16) { self.wr_tagged_u16(EsU16 as uint, v); }
fn emit_u8(v: u8) { self.wr_tagged_u8 (EsU8 as uint, v); }
fn emit_uint(&self, v: uint) {
self.wr_tagged_u64(EsUint as uint, v as u64);
}
fn emit_u64(&self, v: u64) { self.wr_tagged_u64(EsU64 as uint, v); }
fn emit_u32(&self, v: u32) { self.wr_tagged_u32(EsU32 as uint, v); }
fn emit_u16(&self, v: u16) { self.wr_tagged_u16(EsU16 as uint, v); }
fn emit_u8(&self, v: u8) { self.wr_tagged_u8 (EsU8 as uint, v); }
fn emit_int(v: int) { self.wr_tagged_i64(EsInt as uint, v as i64); }
fn emit_i64(v: i64) { self.wr_tagged_i64(EsI64 as uint, v); }
fn emit_i32(v: i32) { self.wr_tagged_i32(EsI32 as uint, v); }
fn emit_i16(v: i16) { self.wr_tagged_i16(EsI16 as uint, v); }
fn emit_i8(v: i8) { self.wr_tagged_i8 (EsI8 as uint, v); }
fn emit_int(&self, v: int) {
self.wr_tagged_i64(EsInt as uint, v as i64);
}
fn emit_i64(&self, v: i64) { self.wr_tagged_i64(EsI64 as uint, v); }
fn emit_i32(&self, v: i32) { self.wr_tagged_i32(EsI32 as uint, v); }
fn emit_i16(&self, v: i16) { self.wr_tagged_i16(EsI16 as uint, v); }
fn emit_i8(&self, v: i8) { self.wr_tagged_i8 (EsI8 as uint, v); }
fn emit_bool(v: bool) { self.wr_tagged_u8(EsBool as uint, v as u8) }
fn emit_bool(&self, v: bool) {
self.wr_tagged_u8(EsBool as uint, v as u8)
}
// FIXME (#2742): implement these
fn emit_f64(_v: f64) { fail ~"Unimplemented: serializing an f64"; }
fn emit_f32(_v: f32) { fail ~"Unimplemented: serializing an f32"; }
fn emit_float(_v: float) { fail ~"Unimplemented: serializing a float"; }
fn emit_f64(&self, _v: f64) { fail ~"Unimplemented: serializing an f64"; }
fn emit_f32(&self, _v: f32) { fail ~"Unimplemented: serializing an f32"; }
fn emit_float(&self, _v: float) {
fail ~"Unimplemented: serializing a float";
}
fn emit_str(v: &str) { self.wr_tagged_str(EsStr as uint, v) }
fn emit_char(&self, _v: char) {
fail ~"Unimplemented: serializing a char";
}
fn emit_enum(name: &str, f: fn()) {
fn emit_borrowed_str(&self, v: &str) {
self.wr_tagged_str(EsStr as uint, v)
}
fn emit_owned_str(&self, v: &str) {
self.emit_borrowed_str(v)
}
fn emit_managed_str(&self, v: &str) {
self.emit_borrowed_str(v)
}
fn emit_borrowed(&self, f: fn()) { f() }
fn emit_owned(&self, f: fn()) { f() }
fn emit_managed(&self, f: fn()) { f() }
fn emit_enum(&self, name: &str, f: fn()) {
self._emit_label(name);
self.wr_tag(EsEnum as uint, f)
}
fn emit_enum_variant(_v_name: &str, v_id: uint, _cnt: uint, f: fn()) {
fn emit_enum_variant(&self, _v_name: &str, v_id: uint, _cnt: uint,
f: fn()) {
self._emit_tagged_uint(EsEnumVid, v_id);
self.wr_tag(EsEnumBody as uint, f)
}
fn emit_enum_variant_arg(_idx: uint, f: fn()) { f() }
fn emit_enum_variant_arg(&self, _idx: uint, f: fn()) { f() }
fn emit_vec(len: uint, f: fn()) {
fn emit_borrowed_vec(&self, len: uint, f: fn()) {
do self.wr_tag(EsVec as uint) {
self._emit_tagged_uint(EsVecLen, len);
f()
}
}
fn emit_vec_elt(_idx: uint, f: fn()) {
fn emit_owned_vec(&self, len: uint, f: fn()) {
self.emit_borrowed_vec(len, f)
}
fn emit_managed_vec(&self, len: uint, f: fn()) {
self.emit_borrowed_vec(len, f)
}
fn emit_vec_elt(&self, _idx: uint, f: fn()) {
self.wr_tag(EsVecElt as uint, f)
}
fn emit_box(f: fn()) { f() }
fn emit_uniq(f: fn()) { f() }
fn emit_rec(f: fn()) { f() }
fn emit_rec_field(f_name: &str, _f_idx: uint, f: fn()) {
self._emit_label(f_name);
fn emit_rec(&self, f: fn()) { f() }
fn emit_struct(&self, _name: &str, f: fn()) { f() }
fn emit_field(&self, name: &str, _idx: uint, f: fn()) {
self._emit_label(name);
f()
}
fn emit_tup(_sz: uint, f: fn()) { f() }
fn emit_tup_elt(_idx: uint, f: fn()) { f() }
fn emit_tup(&self, _len: uint, f: fn()) { f() }
fn emit_tup_elt(&self, _idx: uint, f: fn()) { f() }
}
type EbmlDeserializer_ = {mut parent: ebml::Doc,
mut pos: uint};
pub enum EbmlDeserializer {
EbmlDeserializer_(EbmlDeserializer_)
struct Deserializer {
priv mut parent: Doc,
priv mut pos: uint,
}
pub fn ebml_deserializer(d: ebml::Doc) -> EbmlDeserializer {
EbmlDeserializer_({mut parent: d, mut pos: d.start})
pub fn Deserializer(d: Doc) -> Deserializer {
Deserializer { mut parent: d, mut pos: d.start }
}
priv impl EbmlDeserializer {
priv impl Deserializer {
fn _check_label(lbl: &str) {
if self.pos < self.parent.end {
let {tag: r_tag, doc: r_doc} =
ebml::doc_at(self.parent.data, self.pos);
let TaggedDoc { tag: r_tag, doc: r_doc } =
doc_at(self.parent.data, self.pos);
if r_tag == (EsLabel as uint) {
self.pos = r_doc.end;
let str = ebml::doc_as_str(r_doc);
let str = doc_as_str(r_doc);
if lbl != str {
fail fmt!("Expected label %s but found %s", lbl, str);
}
@ -408,13 +450,13 @@ priv impl EbmlDeserializer {
}
}
fn next_doc(exp_tag: EbmlSerializerTag) -> ebml::Doc {
fn next_doc(exp_tag: EbmlSerializerTag) -> Doc {
debug!(". next_doc(exp_tag=%?)", exp_tag);
if self.pos >= self.parent.end {
fail ~"no more documents in current node!";
}
let {tag: r_tag, doc: r_doc} =
ebml::doc_at(self.parent.data, self.pos);
let TaggedDoc { tag: r_tag, doc: r_doc } =
doc_at(self.parent.data, self.pos);
debug!("self.parent=%?-%? self.pos=%? r_tag=%? r_doc=%?-%?",
copy self.parent.start, copy self.parent.end,
copy self.pos, r_tag, r_doc.start, r_doc.end);
@ -427,10 +469,10 @@ priv impl EbmlDeserializer {
r_doc.end, self.parent.end);
}
self.pos = r_doc.end;
return r_doc;
r_doc
}
fn push_doc<T>(d: ebml::Doc, f: fn() -> T) -> T{
fn push_doc<T>(d: Doc, f: fn() -> T) -> T{
let old_parent = self.parent;
let old_pos = self.pos;
self.parent = d;
@ -442,63 +484,76 @@ priv impl EbmlDeserializer {
}
fn _next_uint(exp_tag: EbmlSerializerTag) -> uint {
let r = ebml::doc_as_u32(self.next_doc(exp_tag));
let r = doc_as_u32(self.next_doc(exp_tag));
debug!("_next_uint exp_tag=%? result=%?", exp_tag, r);
return r as uint;
r as uint
}
}
impl EbmlDeserializer {
fn read_opaque<R>(op: fn(ebml::Doc) -> R) -> R {
impl Deserializer {
fn read_opaque<R>(&self, op: fn(Doc) -> R) -> R {
do self.push_doc(self.next_doc(EsOpaque)) {
op(copy self.parent)
}
}
}
impl EbmlDeserializer: serialization::Deserializer {
fn read_nil() -> () { () }
impl Deserializer: serialization::Deserializer {
fn read_nil(&self) -> () { () }
fn read_u64() -> u64 { ebml::doc_as_u64(self.next_doc(EsU64)) }
fn read_u32() -> u32 { ebml::doc_as_u32(self.next_doc(EsU32)) }
fn read_u16() -> u16 { ebml::doc_as_u16(self.next_doc(EsU16)) }
fn read_u8 () -> u8 { ebml::doc_as_u8 (self.next_doc(EsU8 )) }
fn read_uint() -> uint {
let v = ebml::doc_as_u64(self.next_doc(EsUint));
fn read_u64(&self) -> u64 { doc_as_u64(self.next_doc(EsU64)) }
fn read_u32(&self) -> u32 { doc_as_u32(self.next_doc(EsU32)) }
fn read_u16(&self) -> u16 { doc_as_u16(self.next_doc(EsU16)) }
fn read_u8 (&self) -> u8 { doc_as_u8 (self.next_doc(EsU8 )) }
fn read_uint(&self) -> uint {
let v = doc_as_u64(self.next_doc(EsUint));
if v > (core::uint::max_value as u64) {
fail fmt!("uint %? too large for this architecture", v);
}
return v as uint;
v as uint
}
fn read_i64() -> i64 { ebml::doc_as_u64(self.next_doc(EsI64)) as i64 }
fn read_i32() -> i32 { ebml::doc_as_u32(self.next_doc(EsI32)) as i32 }
fn read_i16() -> i16 { ebml::doc_as_u16(self.next_doc(EsI16)) as i16 }
fn read_i8 () -> i8 { ebml::doc_as_u8 (self.next_doc(EsI8 )) as i8 }
fn read_int() -> int {
let v = ebml::doc_as_u64(self.next_doc(EsInt)) as i64;
fn read_i64(&self) -> i64 { doc_as_u64(self.next_doc(EsI64)) as i64 }
fn read_i32(&self) -> i32 { doc_as_u32(self.next_doc(EsI32)) as i32 }
fn read_i16(&self) -> i16 { doc_as_u16(self.next_doc(EsI16)) as i16 }
fn read_i8 (&self) -> i8 { doc_as_u8 (self.next_doc(EsI8 )) as i8 }
fn read_int(&self) -> int {
let v = doc_as_u64(self.next_doc(EsInt)) as i64;
if v > (int::max_value as i64) || v < (int::min_value as i64) {
fail fmt!("int %? out of range for this architecture", v);
}
return v as int;
v as int
}
fn read_bool() -> bool { ebml::doc_as_u8(self.next_doc(EsBool)) as bool }
fn read_bool(&self) -> bool { doc_as_u8(self.next_doc(EsBool)) as bool }
fn read_f64() -> f64 { fail ~"read_f64()"; }
fn read_f32() -> f32 { fail ~"read_f32()"; }
fn read_float() -> float { fail ~"read_float()"; }
fn read_f64(&self) -> f64 { fail ~"read_f64()"; }
fn read_f32(&self) -> f32 { fail ~"read_f32()"; }
fn read_float(&self) -> float { fail ~"read_float()"; }
fn read_str() -> ~str { ebml::doc_as_str(self.next_doc(EsStr)) }
fn read_char(&self) -> char { fail ~"read_char()"; }
fn read_owned_str(&self) -> ~str { doc_as_str(self.next_doc(EsStr)) }
fn read_managed_str(&self) -> @str { fail ~"read_managed_str()"; }
// Compound types:
fn read_enum<T>(name: &str, f: fn() -> T) -> T {
fn read_owned<T>(&self, f: fn() -> T) -> T {
debug!("read_owned()");
f()
}
fn read_managed<T>(&self, f: fn() -> T) -> T {
debug!("read_managed()");
f()
}
fn read_enum<T>(&self, name: &str, f: fn() -> T) -> T {
debug!("read_enum(%s)", name);
self._check_label(name);
self.push_doc(self.next_doc(EsEnum), f)
}
fn read_enum_variant<T>(f: fn(uint) -> T) -> T {
fn read_enum_variant<T>(&self, f: fn(uint) -> T) -> T {
debug!("read_enum_variant()");
let idx = self._next_uint(EsEnumVid);
debug!(" idx=%u", idx);
@ -507,13 +562,13 @@ impl EbmlDeserializer: serialization::Deserializer {
}
}
fn read_enum_variant_arg<T>(idx: uint, f: fn() -> T) -> T {
fn read_enum_variant_arg<T>(&self, idx: uint, f: fn() -> T) -> T {
debug!("read_enum_variant_arg(idx=%u)", idx);
f()
}
fn read_vec<T>(f: fn(uint) -> T) -> T {
debug!("read_vec()");
fn read_owned_vec<T>(&self, f: fn(uint) -> T) -> T {
debug!("read_owned_vec()");
do self.push_doc(self.next_doc(EsVec)) {
let len = self._next_uint(EsVecLen);
debug!(" len=%u", len);
@ -521,104 +576,69 @@ impl EbmlDeserializer: serialization::Deserializer {
}
}
fn read_vec_elt<T>(idx: uint, f: fn() -> T) -> T {
fn read_managed_vec<T>(&self, f: fn(uint) -> T) -> T {
debug!("read_managed_vec()");
do self.push_doc(self.next_doc(EsVec)) {
let len = self._next_uint(EsVecLen);
debug!(" len=%u", len);
f(len)
}
}
fn read_vec_elt<T>(&self, idx: uint, f: fn() -> T) -> T {
debug!("read_vec_elt(idx=%u)", idx);
self.push_doc(self.next_doc(EsVecElt), f)
}
fn read_box<T>(f: fn() -> T) -> T {
debug!("read_box()");
f()
}
fn read_uniq<T>(f: fn() -> T) -> T {
debug!("read_uniq()");
f()
}
fn read_rec<T>(f: fn() -> T) -> T {
fn read_rec<T>(&self, f: fn() -> T) -> T {
debug!("read_rec()");
f()
}
fn read_rec_field<T>(f_name: &str, f_idx: uint, f: fn() -> T) -> T {
debug!("read_rec_field(%s, idx=%u)", f_name, f_idx);
self._check_label(f_name);
fn read_struct<T>(&self, name: &str, f: fn() -> T) -> T {
debug!("read_struct(name=%s)", name);
f()
}
fn read_tup<T>(sz: uint, f: fn() -> T) -> T {
debug!("read_tup(sz=%u)", sz);
fn read_field<T>(&self, name: &str, idx: uint, f: fn() -> T) -> T {
debug!("read_field(name=%s, idx=%u)", name, idx);
self._check_label(name);
f()
}
fn read_tup_elt<T>(idx: uint, f: fn() -> T) -> T {
fn read_tup<T>(&self, len: uint, f: fn() -> T) -> T {
debug!("read_tup(len=%u)", len);
f()
}
fn read_tup_elt<T>(&self, idx: uint, f: fn() -> T) -> T {
debug!("read_tup_elt(idx=%u)", idx);
f()
}
}
// ___________________________________________________________________________
// Testing
#[test]
fn test_option_int() {
fn serialize_1<S: serialization::Serializer>(s: &S, v: int) {
s.emit_i64(v as i64);
}
fn serialize_0<S: serialization::Serializer>(s: &S, v: Option<int>) {
do s.emit_enum(~"core::option::t") {
match v {
None => s.emit_enum_variant(
~"core::option::None", 0u, 0u, || { } ),
Some(v0) => {
do s.emit_enum_variant(~"core::option::some", 1u, 1u) {
s.emit_enum_variant_arg(0u, || serialize_1(s, v0));
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_option_int() {
fn test_v(v: Option<int>) {
debug!("v == %?", v);
let bytes = do io::with_bytes_writer |wr| {
let ebml_w = Serializer(wr);
v.serialize(&ebml_w)
};
let ebml_doc = Doc(@bytes);
let deser = Deserializer(ebml_doc);
let v1 = serialization::deserialize(&deser);
debug!("v1 == %?", v1);
assert v == v1;
}
}
fn deserialize_1<S: serialization::Deserializer>(s: &S) -> int {
s.read_i64() as int
test_v(Some(22));
test_v(None);
test_v(Some(3));
}
fn deserialize_0<S: serialization::Deserializer>(s: &S) -> Option<int> {
do s.read_enum(~"core::option::t") {
do s.read_enum_variant |i| {
match i {
0 => None,
1 => {
let v0 = do s.read_enum_variant_arg(0u) {
deserialize_1(s)
};
Some(v0)
}
_ => {
fail #fmt("deserialize_0: unexpected variant %u", i);
}
}
}
}
}
fn test_v(v: Option<int>) {
debug!("v == %?", v);
let bytes = do io::with_bytes_writer |wr| {
let ebml_w = ebml::Writer(wr);
serialize_0(&ebml_w, v);
};
let ebml_doc = ebml::Doc(@bytes);
let deser = ebml_deserializer(ebml_doc);
let v1 = deserialize_0(&deser);
debug!("v1 == %?", v1);
assert v == v1;
}
test_v(Some(22));
test_v(None);
test_v(Some(3));
}

View file

@ -1,644 +0,0 @@
#[forbid(deprecated_mode)];
use serialization2;
// Simple Extensible Binary Markup Language (ebml) reader and writer on a
// cursor model. See the specification here:
// http://www.matroska.org/technical/specs/rfc/index.html
struct EbmlTag {
id: uint,
size: uint,
}
struct EbmlState {
ebml_tag: EbmlTag,
tag_pos: uint,
data_pos: uint,
}
// FIXME (#2739): When we have module renaming, make "reader" and "writer"
// separate modules within this file.
// ebml reading
struct Doc {
data: @~[u8],
start: uint,
end: uint,
}
struct TaggedDoc {
tag: uint,
doc: Doc,
}
impl Doc: ops::Index<uint,Doc> {
pure fn index(tag: uint) -> Doc {
unsafe {
get_doc(self, tag)
}
}
}
fn vuint_at(data: &[u8], start: uint) -> {val: uint, next: uint} {
let a = data[start];
if a & 0x80u8 != 0u8 {
return {val: (a & 0x7fu8) as uint, next: start + 1u};
}
if a & 0x40u8 != 0u8 {
return {val: ((a & 0x3fu8) as uint) << 8u |
(data[start + 1u] as uint),
next: start + 2u};
} else if a & 0x20u8 != 0u8 {
return {val: ((a & 0x1fu8) as uint) << 16u |
(data[start + 1u] as uint) << 8u |
(data[start + 2u] as uint),
next: start + 3u};
} else if a & 0x10u8 != 0u8 {
return {val: ((a & 0x0fu8) as uint) << 24u |
(data[start + 1u] as uint) << 16u |
(data[start + 2u] as uint) << 8u |
(data[start + 3u] as uint),
next: start + 4u};
} else { error!("vint too big"); fail; }
}
pub fn Doc(data: @~[u8]) -> Doc {
Doc { data: data, start: 0u, end: vec::len::<u8>(*data) }
}
pub fn doc_at(data: @~[u8], start: uint) -> TaggedDoc {
let elt_tag = vuint_at(*data, start);
let elt_size = vuint_at(*data, elt_tag.next);
let end = elt_size.next + elt_size.val;
TaggedDoc {
tag: elt_tag.val,
doc: Doc { data: data, start: elt_size.next, end: end }
}
}
pub fn maybe_get_doc(d: Doc, tg: uint) -> Option<Doc> {
let mut pos = d.start;
while pos < d.end {
let elt_tag = vuint_at(*d.data, pos);
let elt_size = vuint_at(*d.data, elt_tag.next);
pos = elt_size.next + elt_size.val;
if elt_tag.val == tg {
return Some(Doc { data: d.data, start: elt_size.next, end: pos });
}
}
None
}
pub fn get_doc(d: Doc, tg: uint) -> Doc {
match maybe_get_doc(d, tg) {
Some(d) => d,
None => {
error!("failed to find block with tag %u", tg);
fail;
}
}
}
pub fn docs(d: Doc, it: fn(uint, Doc) -> bool) {
let mut pos = d.start;
while pos < d.end {
let elt_tag = vuint_at(*d.data, pos);
let elt_size = vuint_at(*d.data, elt_tag.next);
pos = elt_size.next + elt_size.val;
let doc = Doc { data: d.data, start: elt_size.next, end: pos };
if !it(elt_tag.val, doc) {
break;
}
}
}
pub fn tagged_docs(d: Doc, tg: uint, it: fn(Doc) -> bool) {
let mut pos = d.start;
while pos < d.end {
let elt_tag = vuint_at(*d.data, pos);
let elt_size = vuint_at(*d.data, elt_tag.next);
pos = elt_size.next + elt_size.val;
if elt_tag.val == tg {
let doc = Doc { data: d.data, start: elt_size.next, end: pos };
if !it(doc) {
break;
}
}
}
}
pub fn doc_data(d: Doc) -> ~[u8] { vec::slice::<u8>(*d.data, d.start, d.end) }
pub fn with_doc_data<T>(d: Doc, f: fn(x: &[u8]) -> T) -> T {
f(vec::view(*d.data, d.start, d.end))
}
pub fn doc_as_str(d: Doc) -> ~str { str::from_bytes(doc_data(d)) }
pub fn doc_as_u8(d: Doc) -> u8 {
assert d.end == d.start + 1u;
(*d.data)[d.start]
}
pub fn doc_as_u16(d: Doc) -> u16 {
assert d.end == d.start + 2u;
io::u64_from_be_bytes(*d.data, d.start, 2u) as u16
}
pub fn doc_as_u32(d: Doc) -> u32 {
assert d.end == d.start + 4u;
io::u64_from_be_bytes(*d.data, d.start, 4u) as u32
}
pub fn doc_as_u64(d: Doc) -> u64 {
assert d.end == d.start + 8u;
io::u64_from_be_bytes(*d.data, d.start, 8u)
}
pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 }
pub fn doc_as_i16(d: Doc) -> i16 { doc_as_u16(d) as i16 }
pub fn doc_as_i32(d: Doc) -> i32 { doc_as_u32(d) as i32 }
pub fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 }
// ebml writing
struct Serializer {
writer: io::Writer,
priv mut size_positions: ~[uint],
}
fn write_sized_vuint(w: io::Writer, n: uint, size: uint) {
match size {
1u => w.write(&[0x80u8 | (n as u8)]),
2u => w.write(&[0x40u8 | ((n >> 8_u) as u8), n as u8]),
3u => w.write(&[0x20u8 | ((n >> 16_u) as u8), (n >> 8_u) as u8,
n as u8]),
4u => w.write(&[0x10u8 | ((n >> 24_u) as u8), (n >> 16_u) as u8,
(n >> 8_u) as u8, n as u8]),
_ => fail fmt!("vint to write too big: %?", n)
};
}
fn write_vuint(w: io::Writer, n: uint) {
if n < 0x7f_u { write_sized_vuint(w, n, 1u); return; }
if n < 0x4000_u { write_sized_vuint(w, n, 2u); return; }
if n < 0x200000_u { write_sized_vuint(w, n, 3u); return; }
if n < 0x10000000_u { write_sized_vuint(w, n, 4u); return; }
fail fmt!("vint to write too big: %?", n);
}
pub fn Serializer(w: io::Writer) -> Serializer {
let size_positions: ~[uint] = ~[];
Serializer { writer: w, mut size_positions: size_positions }
}
// FIXME (#2741): Provide a function to write the standard ebml header.
impl Serializer {
fn start_tag(tag_id: uint) {
debug!("Start tag %u", tag_id);
// Write the enum ID:
write_vuint(self.writer, tag_id);
// Write a placeholder four-byte size.
self.size_positions.push(self.writer.tell());
let zeroes: &[u8] = &[0u8, 0u8, 0u8, 0u8];
self.writer.write(zeroes);
}
fn end_tag() {
let last_size_pos = self.size_positions.pop();
let cur_pos = self.writer.tell();
self.writer.seek(last_size_pos as int, io::SeekSet);
let size = (cur_pos - last_size_pos - 4u);
write_sized_vuint(self.writer, size, 4u);
self.writer.seek(cur_pos as int, io::SeekSet);
debug!("End tag (size = %u)", size);
}
fn wr_tag(tag_id: uint, blk: fn()) {
self.start_tag(tag_id);
blk();
self.end_tag();
}
fn wr_tagged_bytes(tag_id: uint, b: &[u8]) {
write_vuint(self.writer, tag_id);
write_vuint(self.writer, vec::len(b));
self.writer.write(b);
}
fn wr_tagged_u64(tag_id: uint, v: u64) {
do io::u64_to_be_bytes(v, 8u) |v| {
self.wr_tagged_bytes(tag_id, v);
}
}
fn wr_tagged_u32(tag_id: uint, v: u32) {
do io::u64_to_be_bytes(v as u64, 4u) |v| {
self.wr_tagged_bytes(tag_id, v);
}
}
fn wr_tagged_u16(tag_id: uint, v: u16) {
do io::u64_to_be_bytes(v as u64, 2u) |v| {
self.wr_tagged_bytes(tag_id, v);
}
}
fn wr_tagged_u8(tag_id: uint, v: u8) {
self.wr_tagged_bytes(tag_id, &[v]);
}
fn wr_tagged_i64(tag_id: uint, v: i64) {
do io::u64_to_be_bytes(v as u64, 8u) |v| {
self.wr_tagged_bytes(tag_id, v);
}
}
fn wr_tagged_i32(tag_id: uint, v: i32) {
do io::u64_to_be_bytes(v as u64, 4u) |v| {
self.wr_tagged_bytes(tag_id, v);
}
}
fn wr_tagged_i16(tag_id: uint, v: i16) {
do io::u64_to_be_bytes(v as u64, 2u) |v| {
self.wr_tagged_bytes(tag_id, v);
}
}
fn wr_tagged_i8(tag_id: uint, v: i8) {
self.wr_tagged_bytes(tag_id, &[v as u8]);
}
fn wr_tagged_str(tag_id: uint, v: &str) {
str::byte_slice(v, |b| self.wr_tagged_bytes(tag_id, b));
}
fn wr_bytes(b: &[u8]) {
debug!("Write %u bytes", vec::len(b));
self.writer.write(b);
}
fn wr_str(s: &str) {
debug!("Write str: %?", s);
self.writer.write(str::to_bytes(s));
}
}
// FIXME (#2743): optionally perform "relaxations" on end_tag to more
// efficiently encode sizes; this is a fixed point iteration
// Set to true to generate more debugging in EBML serialization.
// Totally lame approach.
const debug: bool = false;
enum EbmlSerializerTag {
EsUint, EsU64, EsU32, EsU16, EsU8,
EsInt, EsI64, EsI32, EsI16, EsI8,
EsBool,
EsStr,
EsF64, EsF32, EsFloat,
EsEnum, EsEnumVid, EsEnumBody,
EsVec, EsVecLen, EsVecElt,
EsOpaque,
EsLabel // Used only when debugging
}
priv impl Serializer {
// used internally to emit things like the vector length and so on
fn _emit_tagged_uint(t: EbmlSerializerTag, v: uint) {
assert v <= 0xFFFF_FFFF_u;
self.wr_tagged_u32(t as uint, v as u32);
}
fn _emit_label(label: &str) {
// There are various strings that we have access to, such as
// the name of a record field, which do not actually appear in
// the serialized EBML (normally). This is just for
// efficiency. When debugging, though, we can emit such
// labels and then they will be checked by deserializer to
// try and check failures more quickly.
if debug { self.wr_tagged_str(EsLabel as uint, label) }
}
}
impl Serializer {
fn emit_opaque(&self, f: fn()) {
do self.wr_tag(EsOpaque as uint) {
f()
}
}
}
impl Serializer: serialization2::Serializer {
fn emit_nil(&self) {}
fn emit_uint(&self, v: uint) {
self.wr_tagged_u64(EsUint as uint, v as u64);
}
fn emit_u64(&self, v: u64) { self.wr_tagged_u64(EsU64 as uint, v); }
fn emit_u32(&self, v: u32) { self.wr_tagged_u32(EsU32 as uint, v); }
fn emit_u16(&self, v: u16) { self.wr_tagged_u16(EsU16 as uint, v); }
fn emit_u8(&self, v: u8) { self.wr_tagged_u8 (EsU8 as uint, v); }
fn emit_int(&self, v: int) {
self.wr_tagged_i64(EsInt as uint, v as i64);
}
fn emit_i64(&self, v: i64) { self.wr_tagged_i64(EsI64 as uint, v); }
fn emit_i32(&self, v: i32) { self.wr_tagged_i32(EsI32 as uint, v); }
fn emit_i16(&self, v: i16) { self.wr_tagged_i16(EsI16 as uint, v); }
fn emit_i8(&self, v: i8) { self.wr_tagged_i8 (EsI8 as uint, v); }
fn emit_bool(&self, v: bool) {
self.wr_tagged_u8(EsBool as uint, v as u8)
}
// FIXME (#2742): implement these
fn emit_f64(&self, _v: f64) { fail ~"Unimplemented: serializing an f64"; }
fn emit_f32(&self, _v: f32) { fail ~"Unimplemented: serializing an f32"; }
fn emit_float(&self, _v: float) {
fail ~"Unimplemented: serializing a float";
}
fn emit_char(&self, _v: char) {
fail ~"Unimplemented: serializing a char";
}
fn emit_borrowed_str(&self, v: &str) {
self.wr_tagged_str(EsStr as uint, v)
}
fn emit_owned_str(&self, v: &str) {
self.emit_borrowed_str(v)
}
fn emit_managed_str(&self, v: &str) {
self.emit_borrowed_str(v)
}
fn emit_borrowed(&self, f: fn()) { f() }
fn emit_owned(&self, f: fn()) { f() }
fn emit_managed(&self, f: fn()) { f() }
fn emit_enum(&self, name: &str, f: fn()) {
self._emit_label(name);
self.wr_tag(EsEnum as uint, f)
}
fn emit_enum_variant(&self, _v_name: &str, v_id: uint, _cnt: uint,
f: fn()) {
self._emit_tagged_uint(EsEnumVid, v_id);
self.wr_tag(EsEnumBody as uint, f)
}
fn emit_enum_variant_arg(&self, _idx: uint, f: fn()) { f() }
fn emit_borrowed_vec(&self, len: uint, f: fn()) {
do self.wr_tag(EsVec as uint) {
self._emit_tagged_uint(EsVecLen, len);
f()
}
}
fn emit_owned_vec(&self, len: uint, f: fn()) {
self.emit_borrowed_vec(len, f)
}
fn emit_managed_vec(&self, len: uint, f: fn()) {
self.emit_borrowed_vec(len, f)
}
fn emit_vec_elt(&self, _idx: uint, f: fn()) {
self.wr_tag(EsVecElt as uint, f)
}
fn emit_rec(&self, f: fn()) { f() }
fn emit_struct(&self, _name: &str, f: fn()) { f() }
fn emit_field(&self, name: &str, _idx: uint, f: fn()) {
self._emit_label(name);
f()
}
fn emit_tup(&self, _len: uint, f: fn()) { f() }
fn emit_tup_elt(&self, _idx: uint, f: fn()) { f() }
}
struct Deserializer {
priv mut parent: Doc,
priv mut pos: uint,
}
pub fn Deserializer(d: Doc) -> Deserializer {
Deserializer { mut parent: d, mut pos: d.start }
}
priv impl Deserializer {
fn _check_label(lbl: &str) {
if self.pos < self.parent.end {
let TaggedDoc { tag: r_tag, doc: r_doc } =
doc_at(self.parent.data, self.pos);
if r_tag == (EsLabel as uint) {
self.pos = r_doc.end;
let str = doc_as_str(r_doc);
if lbl != str {
fail fmt!("Expected label %s but found %s", lbl, str);
}
}
}
}
fn next_doc(exp_tag: EbmlSerializerTag) -> Doc {
debug!(". next_doc(exp_tag=%?)", exp_tag);
if self.pos >= self.parent.end {
fail ~"no more documents in current node!";
}
let TaggedDoc { tag: r_tag, doc: r_doc } =
doc_at(self.parent.data, self.pos);
debug!("self.parent=%?-%? self.pos=%? r_tag=%? r_doc=%?-%?",
copy self.parent.start, copy self.parent.end,
copy self.pos, r_tag, r_doc.start, r_doc.end);
if r_tag != (exp_tag as uint) {
fail fmt!("expected EMBL doc with tag %? but found tag %?",
exp_tag, r_tag);
}
if r_doc.end > self.parent.end {
fail fmt!("invalid EBML, child extends to 0x%x, parent to 0x%x",
r_doc.end, self.parent.end);
}
self.pos = r_doc.end;
r_doc
}
fn push_doc<T>(d: Doc, f: fn() -> T) -> T{
let old_parent = self.parent;
let old_pos = self.pos;
self.parent = d;
self.pos = d.start;
let r = f();
self.parent = old_parent;
self.pos = old_pos;
move r
}
fn _next_uint(exp_tag: EbmlSerializerTag) -> uint {
let r = doc_as_u32(self.next_doc(exp_tag));
debug!("_next_uint exp_tag=%? result=%?", exp_tag, r);
r as uint
}
}
impl Deserializer {
fn read_opaque<R>(&self, op: fn(Doc) -> R) -> R {
do self.push_doc(self.next_doc(EsOpaque)) {
op(copy self.parent)
}
}
}
impl Deserializer: serialization2::Deserializer {
fn read_nil(&self) -> () { () }
fn read_u64(&self) -> u64 { doc_as_u64(self.next_doc(EsU64)) }
fn read_u32(&self) -> u32 { doc_as_u32(self.next_doc(EsU32)) }
fn read_u16(&self) -> u16 { doc_as_u16(self.next_doc(EsU16)) }
fn read_u8 (&self) -> u8 { doc_as_u8 (self.next_doc(EsU8 )) }
fn read_uint(&self) -> uint {
let v = doc_as_u64(self.next_doc(EsUint));
if v > (core::uint::max_value as u64) {
fail fmt!("uint %? too large for this architecture", v);
}
v as uint
}
fn read_i64(&self) -> i64 { doc_as_u64(self.next_doc(EsI64)) as i64 }
fn read_i32(&self) -> i32 { doc_as_u32(self.next_doc(EsI32)) as i32 }
fn read_i16(&self) -> i16 { doc_as_u16(self.next_doc(EsI16)) as i16 }
fn read_i8 (&self) -> i8 { doc_as_u8 (self.next_doc(EsI8 )) as i8 }
fn read_int(&self) -> int {
let v = doc_as_u64(self.next_doc(EsInt)) as i64;
if v > (int::max_value as i64) || v < (int::min_value as i64) {
fail fmt!("int %? out of range for this architecture", v);
}
v as int
}
fn read_bool(&self) -> bool { doc_as_u8(self.next_doc(EsBool)) as bool }
fn read_f64(&self) -> f64 { fail ~"read_f64()"; }
fn read_f32(&self) -> f32 { fail ~"read_f32()"; }
fn read_float(&self) -> float { fail ~"read_float()"; }
fn read_char(&self) -> char { fail ~"read_char()"; }
fn read_owned_str(&self) -> ~str { doc_as_str(self.next_doc(EsStr)) }
fn read_managed_str(&self) -> @str { fail ~"read_managed_str()"; }
// Compound types:
fn read_owned<T>(&self, f: fn() -> T) -> T {
debug!("read_owned()");
f()
}
fn read_managed<T>(&self, f: fn() -> T) -> T {
debug!("read_managed()");
f()
}
fn read_enum<T>(&self, name: &str, f: fn() -> T) -> T {
debug!("read_enum(%s)", name);
self._check_label(name);
self.push_doc(self.next_doc(EsEnum), f)
}
fn read_enum_variant<T>(&self, f: fn(uint) -> T) -> T {
debug!("read_enum_variant()");
let idx = self._next_uint(EsEnumVid);
debug!(" idx=%u", idx);
do self.push_doc(self.next_doc(EsEnumBody)) {
f(idx)
}
}
fn read_enum_variant_arg<T>(&self, idx: uint, f: fn() -> T) -> T {
debug!("read_enum_variant_arg(idx=%u)", idx);
f()
}
fn read_owned_vec<T>(&self, f: fn(uint) -> T) -> T {
debug!("read_owned_vec()");
do self.push_doc(self.next_doc(EsVec)) {
let len = self._next_uint(EsVecLen);
debug!(" len=%u", len);
f(len)
}
}
fn read_managed_vec<T>(&self, f: fn(uint) -> T) -> T {
debug!("read_managed_vec()");
do self.push_doc(self.next_doc(EsVec)) {
let len = self._next_uint(EsVecLen);
debug!(" len=%u", len);
f(len)
}
}
fn read_vec_elt<T>(&self, idx: uint, f: fn() -> T) -> T {
debug!("read_vec_elt(idx=%u)", idx);
self.push_doc(self.next_doc(EsVecElt), f)
}
fn read_rec<T>(&self, f: fn() -> T) -> T {
debug!("read_rec()");
f()
}
fn read_struct<T>(&self, name: &str, f: fn() -> T) -> T {
debug!("read_struct(name=%s)", name);
f()
}
fn read_field<T>(&self, name: &str, idx: uint, f: fn() -> T) -> T {
debug!("read_field(name=%s, idx=%u)", name, idx);
self._check_label(name);
f()
}
fn read_tup<T>(&self, len: uint, f: fn() -> T) -> T {
debug!("read_tup(len=%u)", len);
f()
}
fn read_tup_elt<T>(&self, idx: uint, f: fn() -> T) -> T {
debug!("read_tup_elt(idx=%u)", idx);
f()
}
}
// ___________________________________________________________________________
// Testing
#[cfg(test)]
mod tests {
#[test]
fn test_option_int() {
fn test_v(v: Option<int>) {
debug!("v == %?", v);
let bytes = do io::with_bytes_writer |wr| {
let ebml_w = Serializer(wr);
v.serialize(&ebml_w)
};
let ebml_doc = Doc(@bytes);
let deser = Deserializer(ebml_doc);
let v1 = serialization2::deserialize(&deser);
debug!("v1 == %?", v1);
assert v == v1;
}
test_v(Some(22));
test_v(None);
test_v(Some(3));
}
}

View file

@ -82,7 +82,7 @@ pub type Opt = {name: Name, hasarg: HasArg, occur: Occur};
fn mkname(nm: &str) -> Name {
let unm = str::from_slice(nm);
return if str::len(nm) == 1u {
return if nm.len() == 1u {
Short(str::char_at(unm, 0u))
} else { Long(unm) };
}
@ -114,6 +114,22 @@ impl Occur : Eq {
pure fn ne(other: &Occur) -> bool { !self.eq(other) }
}
impl HasArg : Eq {
pure fn eq(other: &HasArg) -> bool {
(self as uint) == ((*other) as uint)
}
pure fn ne(other: &HasArg) -> bool { !self.eq(other) }
}
impl Opt : Eq {
pure fn eq(other: &Opt) -> bool {
self.name == (*other).name &&
self.hasarg == (*other).hasarg &&
self.occur == (*other).occur
}
pure fn ne(other: &Opt) -> bool { !self.eq(other) }
}
/// Create an option that is required and takes an argument
pub fn reqopt(name: &str) -> Opt {
return {name: mkname(name), hasarg: Yes, occur: Req};
@ -150,8 +166,29 @@ enum Optval { Val(~str), Given, }
*/
pub type Matches = {opts: ~[Opt], vals: ~[~[Optval]], free: ~[~str]};
impl Optval : Eq {
pure fn eq(other: &Optval) -> bool {
match self {
Val(ref s) => match *other { Val (ref os) => s == os,
Given => false },
Given => match *other { Val(_) => false,
Given => true }
}
}
pure fn ne(other: &Optval) -> bool { !self.eq(other) }
}
impl Matches : Eq {
pure fn eq(other: &Matches) -> bool {
self.opts == (*other).opts &&
self.vals == (*other).vals &&
self.free == (*other).free
}
pure fn ne(other: &Matches) -> bool { !self.eq(other) }
}
fn is_arg(arg: &str) -> bool {
return str::len(arg) > 1u && arg[0] == '-' as u8;
return arg.len() > 1u && arg[0] == '-' as u8;
}
fn name_str(nm: &Name) -> ~str {
@ -177,6 +214,35 @@ pub enum Fail_ {
UnexpectedArgument(~str),
}
impl Fail_ : Eq {
// this whole thing should be easy to infer...
pure fn eq(other: &Fail_) -> bool {
match self {
ArgumentMissing(ref s) => {
match *other { ArgumentMissing(ref so) => s == so,
_ => false }
}
UnrecognizedOption(ref s) => {
match *other { UnrecognizedOption(ref so) => s == so,
_ => false }
}
OptionMissing(ref s) => {
match *other { OptionMissing(ref so) => s == so,
_ => false }
}
OptionDuplicated(ref s) => {
match *other { OptionDuplicated(ref so) => s == so,
_ => false }
}
UnexpectedArgument(ref s) => {
match *other { UnexpectedArgument(ref so) => s == so,
_ => false }
}
}
}
pure fn ne(other: &Fail_) -> bool { !self.eq(other) }
}
/// Convert a `fail_` enum into an error string
pub fn fail_str(f: Fail_) -> ~str {
return match f {
@ -220,7 +286,7 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result unsafe {
let mut i = 0u;
while i < l {
let cur = args[i];
let curlen = str::len(cur);
let curlen = cur.len();
if !is_arg(cur) {
free.push(cur);
} else if cur == ~"--" {
@ -444,6 +510,194 @@ impl FailType : Eq {
pure fn ne(other: &FailType) -> bool { !self.eq(other) }
}
/** A module which provides a way to specify descriptions and
* groups of short and long option names, together.
*/
pub mod groups {
/** one group of options, e.g., both -h and --help, along with
* their shared description and properties
*/
pub type OptGroup = {
short_name: ~str,
long_name: ~str,
hint: ~str,
desc: ~str,
hasarg: HasArg,
occur: Occur
};
impl OptGroup : Eq {
pure fn eq(other: &OptGroup) -> bool {
self.short_name == (*other).short_name &&
self.long_name == (*other).long_name &&
self.hint == (*other).hint &&
self.desc == (*other).desc &&
self.hasarg == (*other).hasarg &&
self.occur == (*other).occur
}
pure fn ne(other: &OptGroup) -> bool { !self.eq(other) }
}
/// Create a long option that is required and takes an argument
pub fn reqopt(short_name: &str, long_name: &str,
desc: &str, hint: &str) -> OptGroup {
let len = short_name.len();
assert len == 1 || len == 0;
return {short_name: str::from_slice(short_name),
long_name: str::from_slice(long_name),
hint: str::from_slice(hint),
desc: str::from_slice(desc),
hasarg: Yes,
occur: Req};
}
/// Create a long option that is optional and takes an argument
pub fn optopt(short_name: &str, long_name: &str,
desc: &str, hint: &str) -> OptGroup {
let len = short_name.len();
assert len == 1 || len == 0;
return {short_name: str::from_slice(short_name),
long_name: str::from_slice(long_name),
hint: str::from_slice(hint),
desc: str::from_slice(desc),
hasarg: Yes,
occur: Optional};
}
/// Create a long option that is optional and does not take an argument
pub fn optflag(short_name: &str, long_name: &str,
desc: &str) -> OptGroup {
let len = short_name.len();
assert len == 1 || len == 0;
return {short_name: str::from_slice(short_name),
long_name: str::from_slice(long_name),
hint: ~"",
desc: str::from_slice(desc),
hasarg: No,
occur: Optional};
}
/// Create a long option that is optional and takes an optional argument
pub fn optflagopt(short_name: &str, long_name: &str,
desc: &str, hint: &str) -> OptGroup {
let len = short_name.len();
assert len == 1 || len == 0;
return {short_name: str::from_slice(short_name),
long_name: str::from_slice(long_name),
hint: str::from_slice(hint),
desc: str::from_slice(desc),
hasarg: Maybe,
occur: Optional};
}
/**
* Create a long option that is optional, takes an argument, and may occur
* multiple times
*/
pub fn optmulti(short_name: &str, long_name: &str,
desc: &str, hint: &str) -> OptGroup {
let len = short_name.len();
assert len == 1 || len == 0;
return {short_name: str::from_slice(short_name),
long_name: str::from_slice(long_name),
hint: str::from_slice(hint),
desc: str::from_slice(desc),
hasarg: Yes,
occur: Multi};
}
// translate OptGroup into Opt
// (both short and long names correspond to different Opts)
pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] {
match ((*lopt).short_name.len(),
(*lopt).long_name.len()) {
(0,0) => fail ~"this long-format option was given no name",
(0,_) => ~[{name: Long(((*lopt).long_name)),
hasarg: (*lopt).hasarg,
occur: (*lopt).occur}],
(1,0) => ~[{name: Short(str::char_at((*lopt).short_name, 0)),
hasarg: (*lopt).hasarg,
occur: (*lopt).occur}],
(1,_) => ~[{name: Short(str::char_at((*lopt).short_name, 0)),
hasarg: (*lopt).hasarg,
occur: (*lopt).occur},
{name: Long(((*lopt).long_name)),
hasarg: (*lopt).hasarg,
occur: (*lopt).occur}],
(_,_) => fail ~"something is wrong with the long-form opt"
}
}
/*
* Parse command line args with the provided long format options
*/
pub fn getopts(args: &[~str], opts: &[OptGroup]) -> Result {
::getopts::getopts(args, vec::flat_map(opts, long_to_short))
}
/**
* Derive a usage message from a set of long options
*/
pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
let desc_sep = ~"\n" + str::repeat(~" ", 24);
let rows = vec::map(opts, |optref| {
let short_name = (*optref).short_name;
let long_name = (*optref).long_name;
let hint = (*optref).hint;
let desc = (*optref).desc;
let hasarg = (*optref).hasarg;
let mut row = str::repeat(~" ", 4);
// short option
row += match short_name.len() {
0 => ~"",
1 => ~"-" + short_name + " ",
_ => fail ~"the short name should only be 1 char long",
};
// long option
row += match long_name.len() {
0 => ~"",
_ => ~"--" + long_name + " ",
};
// arg
row += match hasarg {
No => ~"",
Yes => hint,
Maybe => ~"[" + hint + ~"]",
};
// here we just need to indent the start of the description
let rowlen = row.len();
row += if rowlen < 24 {
str::repeat(~" ", 24 - rowlen)
} else {
desc_sep
};
// wrapped description
row += str::connect(str::split_within(desc, 54), desc_sep);
row
});
return str::from_slice(brief) +
~"\n\nOptions:\n" +
str::connect(rows, ~"\n") +
~"\n\n";
}
} // end groups module
#[cfg(test)]
mod tests {
#[legacy_exports];
@ -943,6 +1197,158 @@ mod tests {
assert opts_present(matches, ~[~"L"]);
assert opts_str(matches, ~[~"L"]) == ~"foo";
}
#[test]
fn test_groups_reqopt() {
let opt = groups::reqopt(~"b", ~"banana", ~"some bananas", ~"VAL");
assert opt == { short_name: ~"b",
long_name: ~"banana",
hint: ~"VAL",
desc: ~"some bananas",
hasarg: Yes,
occur: Req }
}
#[test]
fn test_groups_optopt() {
let opt = groups::optopt(~"a", ~"apple", ~"some apples", ~"VAL");
assert opt == { short_name: ~"a",
long_name: ~"apple",
hint: ~"VAL",
desc: ~"some apples",
hasarg: Yes,
occur: Optional }
}
#[test]
fn test_groups_optflag() {
let opt = groups::optflag(~"k", ~"kiwi", ~"some kiwis");
assert opt == { short_name: ~"k",
long_name: ~"kiwi",
hint: ~"",
desc: ~"some kiwis",
hasarg: No,
occur: Optional }
}
#[test]
fn test_groups_optflagopt() {
let opt = groups::optflagopt(~"p", ~"pineapple",
~"some pineapples", ~"VAL");
assert opt == { short_name: ~"p",
long_name: ~"pineapple",
hint: ~"VAL",
desc: ~"some pineapples",
hasarg: Maybe,
occur: Optional }
}
#[test]
fn test_groups_optmulti() {
let opt = groups::optmulti(~"l", ~"lime",
~"some limes", ~"VAL");
assert opt == { short_name: ~"l",
long_name: ~"lime",
hint: ~"VAL",
desc: ~"some limes",
hasarg: Yes,
occur: Multi }
}
#[test]
fn test_groups_long_to_short() {
let short = ~[reqopt(~"b"), reqopt(~"banana")];
let verbose = groups::reqopt(~"b", ~"banana",
~"some bananas", ~"VAL");
assert groups::long_to_short(&verbose) == short;
}
#[test]
fn test_groups_getopts() {
let short = ~[
reqopt(~"b"), reqopt(~"banana"),
optopt(~"a"), optopt(~"apple"),
optflag(~"k"), optflagopt(~"kiwi"),
optflagopt(~"p"),
optmulti(~"l")
];
let verbose = ~[
groups::reqopt(~"b", ~"banana", ~"Desc", ~"VAL"),
groups::optopt(~"a", ~"apple", ~"Desc", ~"VAL"),
groups::optflag(~"k", ~"kiwi", ~"Desc"),
groups::optflagopt(~"p", ~"", ~"Desc", ~"VAL"),
groups::optmulti(~"l", ~"", ~"Desc", ~"VAL"),
];
let sample_args = ~[~"-k", ~"15", ~"--apple", ~"1", ~"k",
~"-p", ~"16", ~"l", ~"35"];
// NOTE: we should sort before comparing
assert getopts(sample_args, short)
== groups::getopts(sample_args, verbose);
}
#[test]
fn test_groups_usage() {
let optgroups = ~[
groups::reqopt(~"b", ~"banana", ~"Desc", ~"VAL"),
groups::optopt(~"a", ~"012345678901234567890123456789",
~"Desc", ~"VAL"),
groups::optflag(~"k", ~"kiwi", ~"Desc"),
groups::optflagopt(~"p", ~"", ~"Desc", ~"VAL"),
groups::optmulti(~"l", ~"", ~"Desc", ~"VAL"),
];
let expected =
~"Usage: fruits
Options:
-b --banana VAL Desc
-a --012345678901234567890123456789 VAL
Desc
-k --kiwi Desc
-p [VAL] Desc
-l VAL Desc
";
let generated_usage = groups::usage(~"Usage: fruits", optgroups);
debug!("expected: <<%s>>", expected);
debug!("generated: <<%s>>", generated_usage);
assert generated_usage == expected;
}
#[test]
fn test_groups_usage_description_wrapping() {
// indentation should be 24 spaces
// lines wrap after 78: or rather descriptions wrap after 54
let optgroups = ~[
groups::optflag(~"k", ~"kiwi",
~"This is a long description which won't be wrapped..+.."), // 54
groups::optflag(~"a", ~"apple",
~"This is a long description which _will_ be wrapped..+.."), // 55
];
let expected =
~"Usage: fruits
Options:
-k --kiwi This is a long description which won't be wrapped..+..
-a --apple This is a long description which _will_ be
wrapped..+..
";
let usage = groups::usage(~"Usage: fruits", optgroups);
debug!("expected: <<%s>>", expected);
debug!("generated: <<%s>>", usage);
assert usage == expected
}
}
// Local Variables:

View file

@ -51,7 +51,7 @@ fn escape_str(s: &str) -> ~str {
fn spaces(n: uint) -> ~str {
let mut ss = ~"";
for n.times { str::push_str(&ss, " "); }
for n.times { str::push_str(&mut ss, " "); }
return ss;
}
@ -63,7 +63,7 @@ pub fn Serializer(wr: io::Writer) -> Serializer {
Serializer { wr: wr }
}
pub impl Serializer: serialization2::Serializer {
pub impl Serializer: serialization::Serializer {
fn emit_nil(&self) { self.wr.write_str("null") }
fn emit_uint(&self, v: uint) { self.emit_float(v as float); }
@ -167,7 +167,7 @@ pub fn PrettySerializer(wr: io::Writer) -> PrettySerializer {
PrettySerializer { wr: wr, indent: 0 }
}
pub impl PrettySerializer: serialization2::Serializer {
pub impl PrettySerializer: serialization::Serializer {
fn emit_nil(&self) { self.wr.write_str("null") }
fn emit_uint(&self, v: uint) { self.emit_float(v as float); }
@ -273,8 +273,36 @@ pub impl PrettySerializer: serialization2::Serializer {
}
}
pub impl Json: serialization2::Serializable {
fn serialize<S: serialization2::Serializer>(&self, s: &S) {
#[cfg(stage0)]
pub impl Json: serialization::Serializable {
fn serialize<S: serialization::Serializer>(&self, s: &S) {
match *self {
Number(v) => v.serialize(s),
String(ref v) => v.serialize(s),
Boolean(v) => v.serialize(s),
List(v) => v.serialize(s),
Object(ref v) => {
do s.emit_rec || {
let mut idx = 0;
for v.each |key, value| {
do s.emit_field(*key, idx) {
value.serialize(s);
}
idx += 1;
}
}
},
Null => s.emit_nil(),
}
}
}
#[cfg(stage1)]
#[cfg(stage2)]
pub impl<
S: serialization::Serializer
> Json: serialization::Serializable<S> {
fn serialize(&self, s: &S) {
match *self {
Number(v) => v.serialize(s),
String(ref v) => v.serialize(s),
@ -302,7 +330,8 @@ pub fn to_writer(wr: io::Writer, json: &Json) {
}
/// Serializes a json value into a string
pub fn to_str(json: &Json) -> ~str {
pub pure fn to_str(json: &Json) -> ~str unsafe {
// ugh, should be safe
io::with_str_writer(|wr| to_writer(wr, json))
}
@ -328,8 +357,8 @@ pub fn Parser(rdr: io::Reader) -> Parser {
Parser {
rdr: rdr,
ch: rdr.read_char(),
line: 1u,
col: 1u,
line: 1,
col: 1,
}
}
@ -341,7 +370,7 @@ pub impl Parser {
self.parse_whitespace();
// Make sure there is no trailing characters.
if self.eof() {
Ok(value)
Ok(move value)
} else {
self.error(~"trailing characters")
}
@ -546,14 +575,14 @@ priv impl Parser {
if (escape) {
match self.ch {
'"' => str::push_char(&res, '"'),
'\\' => str::push_char(&res, '\\'),
'/' => str::push_char(&res, '/'),
'b' => str::push_char(&res, '\x08'),
'f' => str::push_char(&res, '\x0c'),
'n' => str::push_char(&res, '\n'),
'r' => str::push_char(&res, '\r'),
't' => str::push_char(&res, '\t'),
'"' => str::push_char(&mut res, '"'),
'\\' => str::push_char(&mut res, '\\'),
'/' => str::push_char(&mut res, '/'),
'b' => str::push_char(&mut res, '\x08'),
'f' => str::push_char(&mut res, '\x0c'),
'n' => str::push_char(&mut res, '\n'),
'r' => str::push_char(&mut res, '\r'),
't' => str::push_char(&mut res, '\t'),
'u' => {
// Parse \u1234.
let mut i = 0u;
@ -582,7 +611,7 @@ priv impl Parser {
~"invalid \\u escape (not four digits)");
}
str::push_char(&res, n as char);
str::push_char(&mut res, n as char);
}
_ => return self.error(~"invalid escape")
}
@ -594,7 +623,7 @@ priv impl Parser {
self.bump();
return Ok(res);
}
str::push_char(&res, self.ch);
str::push_char(&mut res, self.ch);
}
}
@ -609,12 +638,12 @@ priv impl Parser {
if self.ch == ']' {
self.bump();
return Ok(List(values));
return Ok(List(move values));
}
loop {
match move self.parse_value() {
Ok(move v) => values.push(v),
Ok(move v) => values.push(move v),
Err(move e) => return Err(e)
}
@ -625,7 +654,7 @@ priv impl Parser {
match self.ch {
',' => self.bump(),
']' => { self.bump(); return Ok(List(values)); }
']' => { self.bump(); return Ok(List(move values)); }
_ => return self.error(~"expected `,` or `]`")
}
};
@ -639,7 +668,7 @@ priv impl Parser {
if self.ch == '}' {
self.bump();
return Ok(Object(values));
return Ok(Object(move values));
}
while !self.eof() {
@ -663,14 +692,14 @@ priv impl Parser {
self.bump();
match move self.parse_value() {
Ok(move value) => { values.insert(key, value); }
Ok(move value) => { values.insert(key, move value); }
Err(move e) => return Err(e)
}
self.parse_whitespace();
match self.ch {
',' => self.bump(),
'}' => { self.bump(); return Ok(Object(values)); }
'}' => { self.bump(); return Ok(Object(move values)); }
_ => {
if self.eof() { break; }
return self.error(~"expected `,` or `}`");
@ -702,7 +731,7 @@ pub struct Deserializer {
pub fn Deserializer(rdr: io::Reader) -> Result<Deserializer, Error> {
match move from_reader(rdr) {
Ok(move json) => {
let des = Deserializer { json: json, stack: ~[] };
let des = Deserializer { json: move json, stack: ~[] };
Ok(move des)
}
Err(move e) => Err(e)
@ -721,7 +750,7 @@ priv impl Deserializer {
}
}
pub impl Deserializer: serialization2::Deserializer {
pub impl Deserializer: serialization::Deserializer {
fn read_nil(&self) -> () {
debug!("read_nil");
match *self.pop() {
@ -818,7 +847,7 @@ pub impl Deserializer: serialization2::Deserializer {
};
let res = f(len);
self.pop();
res
move res
}
fn read_managed_vec<T>(&self, f: fn(uint) -> T) -> T {
@ -829,7 +858,7 @@ pub impl Deserializer: serialization2::Deserializer {
};
let res = f(len);
self.pop();
res
move res
}
fn read_vec_elt<T>(&self, idx: uint, f: fn() -> T) -> T {
@ -850,14 +879,14 @@ pub impl Deserializer: serialization2::Deserializer {
debug!("read_rec()");
let value = f();
self.pop();
value
move value
}
fn read_struct<T>(&self, _name: &str, f: fn() -> T) -> T {
debug!("read_struct()");
let value = f();
self.pop();
value
move value
}
fn read_field<T>(&self, name: &str, idx: uint, f: fn() -> T) -> T {
@ -868,7 +897,7 @@ pub impl Deserializer: serialization2::Deserializer {
// FIXME(#3148) This hint should not be necessary.
let obj: &self/~Object = obj;
match obj.find_ref(&name.to_unique()) {
match obj.find_ref(&name.to_owned()) {
None => fail fmt!("no such field: %s", name),
Some(json) => {
self.stack.push(json);
@ -890,7 +919,7 @@ pub impl Deserializer: serialization2::Deserializer {
debug!("read_tup(len=%u)", len);
let value = f();
self.pop();
value
move value
}
fn read_tup_elt<T>(&self, idx: uint, f: fn() -> T) -> T {
@ -1166,11 +1195,11 @@ impl <A: ToJson> Option<A>: ToJson {
}
impl Json: to_str::ToStr {
fn to_str() -> ~str { to_str(&self) }
pure fn to_str() -> ~str { to_str(&self) }
}
impl Error: to_str::ToStr {
fn to_str() -> ~str {
pure fn to_str() -> ~str {
fmt!("%u:%u: %s", self.line, self.col, *self.msg)
}
}
@ -1182,11 +1211,11 @@ mod tests {
for items.each |item| {
match *item {
(copy key, copy value) => { d.insert(key, value); },
(copy key, copy value) => { d.insert(key, move value); },
}
};
Object(d)
Object(move d)
}
#[test]

View file

@ -341,7 +341,8 @@ pub mod chained {
wr.write_str(~" }");
}
fn to_str() -> ~str {
pure fn to_str() -> ~str unsafe {
// Meh -- this should be safe
do io::with_str_writer |wr| { self.to_writer(wr) }
}
}
@ -722,7 +723,7 @@ mod tests {
let map = map::HashMap::<~str, ~str>();
assert (option::is_none(&map.find(key)));
map.insert(key, ~"val");
assert (option::get(&map.find(key)) == ~"val");
assert (option::get(map.find(key)) == ~"val");
}
#[test]

View file

@ -10,8 +10,10 @@ use addrinfo = uv::ll::addrinfo;
use uv_getaddrinfo_t = uv::ll::uv_getaddrinfo_t;
use uv_ip4_addr = uv::ll::ip4_addr;
use uv_ip4_name = uv::ll::ip4_name;
use uv_ip4_port = uv::ll::ip4_port;
use uv_ip6_addr = uv::ll::ip6_addr;
use uv_ip6_name = uv::ll::ip6_name;
use uv_ip6_port = uv::ll::ip6_port;
use uv_getaddrinfo = uv::ll::getaddrinfo;
use uv_freeaddrinfo = uv::ll::freeaddrinfo;
use create_uv_getaddrinfo_t = uv::ll::getaddrinfo_t;
@ -33,11 +35,11 @@ type ParseAddrErr = {
};
/**
* Convert a `ip_addr` to a str
* Convert a `IpAddr` to a str
*
* # Arguments
*
* * ip - a `std::net::ip::ip_addr`
* * ip - a `std::net::ip::IpAddr`
*/
pub fn format_addr(ip: &IpAddr) -> ~str {
match *ip {
@ -58,6 +60,23 @@ pub fn format_addr(ip: &IpAddr) -> ~str {
}
}
/**
* Get the associated port
*
* # Arguments
* * ip - a `std::net::ip::IpAddr`
*/
pub fn get_port(ip: &IpAddr) -> uint {
match *ip {
Ipv4(ref addr) => unsafe {
uv_ip4_port(addr)
},
Ipv6(ref addr) => unsafe {
uv_ip6_port(addr)
}
}
}
/// Represents errors returned from `net::ip::get_addr()`
enum IpGetAddrErr {
GetAddrUnknownError
@ -128,7 +147,7 @@ pub mod v4 {
*/
pub fn parse_addr(ip: &str) -> IpAddr {
match try_parse_addr(ip) {
result::Ok(copy addr) => addr,
result::Ok(move addr) => move addr,
result::Err(ref err_data) => fail err_data.err_msg
}
}
@ -214,7 +233,7 @@ pub mod v6 {
*/
pub fn parse_addr(ip: &str) -> IpAddr {
match try_parse_addr(ip) {
result::Ok(copy addr) => addr,
result::Ok(move addr) => move addr,
result::Err(copy err_data) => fail err_data.err_msg
}
}
@ -353,7 +372,7 @@ mod test {
}
// note really sure how to realiably test/assert
// this.. mostly just wanting to see it work, atm.
let results = result::unwrap(ga_result);
let results = result::unwrap(move ga_result);
log(debug, fmt!("test_get_addr: Number of results for %s: %?",
localhost_name, vec::len(results)));
for vec::each(results) |r| {
@ -366,7 +385,7 @@ mod test {
}
// at least one result.. this is going to vary from system
// to system, based on stuff like the contents of /etc/hosts
assert vec::len(results) > 0;
assert !results.is_empty();
}
#[test]
#[ignore(reason = "valgrind says it's leaky")]

View file

@ -6,9 +6,7 @@ use ip = net_ip;
use uv::iotask;
use uv::iotask::IoTask;
use future_spawn = future::spawn;
// FIXME #1935
// should be able to, but can't atm, replace w/ result::{result, extensions};
use result::*;
use result::{Result};
use libc::size_t;
use io::{Reader, ReaderUtil, Writer};
use comm = core::comm;
@ -136,6 +134,10 @@ pub fn connect(input_ip: ip::IpAddr, port: uint,
stream_handle_ptr: stream_handle_ptr,
connect_req: uv::ll::connect_t(),
write_req: uv::ll::write_t(),
ipv6: match input_ip {
ip::Ipv4(_) => { false }
ip::Ipv6(_) => { true }
},
iotask: iotask
};
let socket_data_ptr = ptr::addr_of(&(*socket_data));
@ -477,6 +479,7 @@ pub fn accept(new_conn: TcpNewConnection)
stream_handle_ptr : stream_handle_ptr,
connect_req : uv::ll::connect_t(),
write_req : uv::ll::write_t(),
ipv6: (*server_data_ptr).ipv6,
iotask : iotask
};
let client_socket_data_ptr = ptr::addr_of(&(*client_socket_data));
@ -564,7 +567,8 @@ pub fn listen(host_ip: ip::IpAddr, port: uint, backlog: uint,
new_connect_cb: fn~(TcpNewConnection,
comm::Chan<Option<TcpErrData>>))
-> result::Result<(), TcpListenErrData> unsafe {
do listen_common(move host_ip, port, backlog, iotask, on_establish_cb)
do listen_common(move host_ip, port, backlog, iotask,
move on_establish_cb)
// on_connect_cb
|move new_connect_cb, handle| unsafe {
let server_data_ptr = uv::ll::get_data_for_uv_handle(handle)
@ -591,6 +595,10 @@ fn listen_common(host_ip: ip::IpAddr, port: uint, backlog: uint,
kill_ch: kill_ch,
on_connect_cb: move on_connect_cb,
iotask: iotask,
ipv6: match host_ip {
ip::Ipv4(_) => { false }
ip::Ipv6(_) => { true }
},
mut active: true
};
let server_data_ptr = ptr::addr_of(&server_data);
@ -747,6 +755,21 @@ impl TcpSocket {
-> future::Future<result::Result<(), TcpErrData>> {
write_future(&self, raw_write_data)
}
pub fn get_peer_addr() -> ip::IpAddr {
unsafe {
if self.socket_data.ipv6 {
let addr = uv::ll::ip6_addr("", 0);
uv::ll::tcp_getpeername6(self.socket_data.stream_handle_ptr,
ptr::addr_of(&addr));
ip::Ipv6(move addr)
} else {
let addr = uv::ll::ip4_addr("", 0);
uv::ll::tcp_getpeername(self.socket_data.stream_handle_ptr,
ptr::addr_of(&addr));
ip::Ipv4(move addr)
}
}
}
}
/// Implementation of `io::reader` trait for a buffered `net::tcp::tcp_socket`
@ -1004,6 +1027,7 @@ type TcpListenFcData = {
kill_ch: comm::Chan<Option<TcpErrData>>,
on_connect_cb: fn~(*uv::ll::uv_tcp_t),
iotask: IoTask,
ipv6: bool,
mut active: bool
};
@ -1093,7 +1117,7 @@ extern fn on_tcp_read_cb(stream: *uv::ll::uv_stream_t,
log(debug, fmt!("tcp on_read_cb nread: %d", nread as int));
let reader_ch = (*socket_data_ptr).reader_ch;
let buf_base = uv::ll::get_base_from_buf(buf);
let new_bytes = vec::raw::from_buf(buf_base, nread as uint);
let new_bytes = vec::from_buf(buf_base, nread as uint);
core::comm::send(reader_ch, result::Ok(new_bytes));
}
}
@ -1202,6 +1226,7 @@ type TcpSocketData = {
stream_handle_ptr: *uv::ll::uv_tcp_t,
connect_req: uv::ll::uv_connect_t,
write_req: uv::ll::uv_write_t,
ipv6: bool,
iotask: IoTask
};
@ -1224,6 +1249,10 @@ mod test {
impl_gl_tcp_ipv4_server_and_client();
}
#[test]
fn test_gl_tcp_get_peer_addr() unsafe {
impl_gl_tcp_ipv4_get_peer_addr();
}
#[test]
fn test_gl_tcp_ipv4_client_error_connection_refused() unsafe {
impl_gl_tcp_ipv4_client_error_connection_refused();
}
@ -1250,6 +1279,11 @@ mod test {
}
#[test]
#[ignore(cfg(target_os = "linux"))]
fn test_gl_tcp_get_peer_addr() unsafe {
impl_gl_tcp_ipv4_get_peer_addr();
}
#[test]
#[ignore(cfg(target_os = "linux"))]
fn test_gl_tcp_ipv4_client_error_connection_refused() unsafe {
impl_gl_tcp_ipv4_client_error_connection_refused();
}
@ -1317,6 +1351,53 @@ mod test {
assert str::contains(actual_req, expected_req);
assert str::contains(actual_resp, expected_resp);
}
fn impl_gl_tcp_ipv4_get_peer_addr() {
let hl_loop = uv::global_loop::get();
let server_ip = ~"127.0.0.1";
let server_port = 8887u;
let expected_resp = ~"pong";
let server_result_po = core::comm::Port::<~str>();
let server_result_ch = core::comm::Chan(&server_result_po);
let cont_po = core::comm::Port::<()>();
let cont_ch = core::comm::Chan(&cont_po);
// server
do task::spawn_sched(task::ManualThreads(1u)) {
let actual_req = do comm::listen |server_ch| {
run_tcp_test_server(
server_ip,
server_port,
expected_resp,
server_ch,
cont_ch,
hl_loop)
};
server_result_ch.send(actual_req);
};
core::comm::recv(cont_po);
// client
log(debug, ~"server started, firing up client..");
do core::comm::listen |client_ch| {
let server_ip_addr = ip::v4::parse_addr(server_ip);
let iotask = uv::global_loop::get();
let connect_result = connect(move server_ip_addr, server_port,
iotask);
let sock = result::unwrap(move connect_result);
// This is what we are actually testing!
assert net::ip::format_addr(&sock.get_peer_addr()) ==
~"127.0.0.1";
assert net::ip::get_port(&sock.get_peer_addr()) == 8887;
// Fulfill the protocol the test server expects
let resp_bytes = str::to_bytes(~"ping");
tcp_write_single(&sock, resp_bytes);
let read_result = sock.read(0u);
client_ch.send(str::from_bytes(read_result.get()));
};
}
fn impl_gl_tcp_ipv4_client_error_connection_refused() {
let hl_loop = uv::global_loop::get();
let server_ip = ~"127.0.0.1";
@ -1512,8 +1593,11 @@ mod test {
~"SERVER/WORKER: send on cont ch");
cont_ch.send(());
let sock = result::unwrap(move accept_result);
let peer_addr = sock.get_peer_addr();
log(debug, ~"SERVER: successfully accepted"+
~"connection!");
fmt!(" connection from %s:%u",
ip::format_addr(&peer_addr),
ip::get_port(&peer_addr)));
let received_req_bytes = read(&sock, 0u);
match move received_req_bytes {
result::Ok(move data) => {

View file

@ -65,10 +65,10 @@ fn encode_inner(s: &str, full_url: bool) -> ~str {
str::push_char(&mut out, ch);
}
_ => out += #fmt("%%%X", ch as uint)
_ => out += fmt!("%%%X", ch as uint)
}
} else {
out += #fmt("%%%X", ch as uint);
out += fmt!("%%%X", ch as uint);
}
}
}
@ -94,6 +94,7 @@ pub fn encode(s: &str) -> ~str {
*
* This function is compliant with RFC 3986.
*/
pub fn encode_component(s: &str) -> ~str {
encode_inner(s, false)
}
@ -163,7 +164,7 @@ fn encode_plus(s: &str) -> ~str {
str::push_char(&mut out, ch);
}
' ' => str::push_char(&mut out, '+'),
_ => out += #fmt("%%%X", ch as uint)
_ => out += fmt!("%%%X", ch as uint)
}
}
@ -189,7 +190,7 @@ pub fn encode_form_urlencoded(m: HashMap<~str, @DVec<@~str>>) -> ~str {
first = false;
}
out += #fmt("%s=%s", key, encode_plus(**value));
out += fmt!("%s=%s", key, encode_plus(**value));
}
}
@ -297,7 +298,7 @@ fn userinfo_from_str(uinfo: &str) -> UserInfo {
return UserInfo(user, pass);
}
fn userinfo_to_str(userinfo: UserInfo) -> ~str {
pure fn userinfo_to_str(userinfo: UserInfo) -> ~str {
if option::is_some(&userinfo.pass) {
return str::concat(~[copy userinfo.user, ~":",
option::unwrap(copy userinfo.pass),
@ -325,11 +326,15 @@ fn query_from_str(rawquery: &str) -> Query {
return query;
}
pub fn query_to_str(query: Query) -> ~str {
pub pure fn query_to_str(query: Query) -> ~str {
let mut strvec = ~[];
for query.each |kv| {
let (k, v) = copy *kv;
strvec += ~[#fmt("%s=%s", encode_component(k), encode_component(v))];
// This is really safe...
unsafe {
strvec += ~[fmt!("%s=%s",
encode_component(k), encode_component(v))];
}
};
return str::connect(strvec, ~"&");
}
@ -672,7 +677,7 @@ impl Url : FromStr {
* result in just "http://somehost.com".
*
*/
pub fn to_str(url: Url) -> ~str {
pub pure fn to_str(url: Url) -> ~str {
let user = if url.user.is_some() {
userinfo_to_str(option::unwrap(copy url.user))
} else {
@ -688,7 +693,8 @@ pub fn to_str(url: Url) -> ~str {
} else {
str::concat(~[~"?", query_to_str(url.query)])
};
let fragment = if url.fragment.is_some() {
// ugh, this really is safe
let fragment = if url.fragment.is_some() unsafe {
str::concat(~[~"#", encode_component(
option::unwrap(copy url.fragment))])
} else {
@ -704,7 +710,7 @@ pub fn to_str(url: Url) -> ~str {
}
impl Url: to_str::ToStr {
pub fn to_str() -> ~str {
pub pure fn to_str() -> ~str {
to_str(self)
}
}
@ -844,7 +850,7 @@ mod tests {
fn test_url_parse_host_slash() {
let urlstr = ~"http://0.42.42.42/";
let url = from_str(urlstr).get();
#debug("url: %?", url);
debug!("url: %?", url);
assert url.host == ~"0.42.42.42";
assert url.path == ~"/";
}
@ -853,7 +859,7 @@ mod tests {
fn test_url_with_underscores() {
let urlstr = ~"http://dotcom.com/file_name.html";
let url = from_str(urlstr).get();
#debug("url: %?", url);
debug!("url: %?", url);
assert url.path == ~"/file_name.html";
}
@ -861,7 +867,7 @@ mod tests {
fn test_url_with_dashes() {
let urlstr = ~"http://dotcom.com/file-name.html";
let url = from_str(urlstr).get();
#debug("url: %?", url);
debug!("url: %?", url);
assert url.path == ~"/file-name.html";
}

View file

@ -2,131 +2,175 @@
use io::Writer;
use io::WriterUtil;
use serialization::Serializer;
use serialization;
impl Writer: Serializer {
fn emit_nil() {
self.write_str(~"()")
pub struct Serializer {
wr: io::Writer,
}
pub fn Serializer(wr: io::Writer) -> Serializer {
Serializer { wr: wr }
}
pub impl Serializer: serialization::Serializer {
fn emit_nil(&self) {
self.wr.write_str(~"()")
}
fn emit_uint(v: uint) {
self.write_str(fmt!("%?u", v));
fn emit_uint(&self, v: uint) {
self.wr.write_str(fmt!("%?u", v));
}
fn emit_u64(v: u64) {
self.write_str(fmt!("%?_u64", v));
fn emit_u64(&self, v: u64) {
self.wr.write_str(fmt!("%?_u64", v));
}
fn emit_u32(v: u32) {
self.write_str(fmt!("%?_u32", v));
fn emit_u32(&self, v: u32) {
self.wr.write_str(fmt!("%?_u32", v));
}
fn emit_u16(v: u16) {
self.write_str(fmt!("%?_u16", v));
fn emit_u16(&self, v: u16) {
self.wr.write_str(fmt!("%?_u16", v));
}
fn emit_u8(v: u8) {
self.write_str(fmt!("%?_u8", v));
fn emit_u8(&self, v: u8) {
self.wr.write_str(fmt!("%?_u8", v));
}
fn emit_int(v: int) {
self.write_str(fmt!("%?", v));
fn emit_int(&self, v: int) {
self.wr.write_str(fmt!("%?", v));
}
fn emit_i64(v: i64) {
self.write_str(fmt!("%?_i64", v));
fn emit_i64(&self, v: i64) {
self.wr.write_str(fmt!("%?_i64", v));
}
fn emit_i32(v: i32) {
self.write_str(fmt!("%?_i32", v));
fn emit_i32(&self, v: i32) {
self.wr.write_str(fmt!("%?_i32", v));
}
fn emit_i16(v: i16) {
self.write_str(fmt!("%?_i16", v));
fn emit_i16(&self, v: i16) {
self.wr.write_str(fmt!("%?_i16", v));
}
fn emit_i8(v: i8) {
self.write_str(fmt!("%?_i8", v));
fn emit_i8(&self, v: i8) {
self.wr.write_str(fmt!("%?_i8", v));
}
fn emit_bool(v: bool) {
self.write_str(fmt!("%b", v));
fn emit_bool(&self, v: bool) {
self.wr.write_str(fmt!("%b", v));
}
fn emit_float(v: float) {
self.write_str(fmt!("%?_f", v));
fn emit_float(&self, v: float) {
self.wr.write_str(fmt!("%?_f", v));
}
fn emit_f64(v: f64) {
self.write_str(fmt!("%?_f64", v));
fn emit_f64(&self, v: f64) {
self.wr.write_str(fmt!("%?_f64", v));
}
fn emit_f32(v: f32) {
self.write_str(fmt!("%?_f32", v));
fn emit_f32(&self, v: f32) {
self.wr.write_str(fmt!("%?_f32", v));
}
fn emit_str(v: &str) {
self.write_str(fmt!("%?", v));
fn emit_char(&self, v: char) {
self.wr.write_str(fmt!("%?", v));
}
fn emit_enum(_name: &str, f: fn()) {
fn emit_borrowed_str(&self, v: &str) {
self.wr.write_str(fmt!("&%?", v));
}
fn emit_owned_str(&self, v: &str) {
self.wr.write_str(fmt!("~%?", v));
}
fn emit_managed_str(&self, v: &str) {
self.wr.write_str(fmt!("@%?", v));
}
fn emit_borrowed(&self, f: fn()) {
self.wr.write_str(~"&");
f();
}
fn emit_enum_variant(v_name: &str, _v_id: uint, sz: uint, f: fn()) {
self.write_str(v_name);
if sz > 0u { self.write_str(~"("); }
f();
if sz > 0u { self.write_str(~")"); }
}
fn emit_enum_variant_arg(idx: uint, f: fn()) {
if idx > 0u { self.write_str(~", "); }
fn emit_owned(&self, f: fn()) {
self.wr.write_str(~"~");
f();
}
fn emit_vec(_len: uint, f: fn()) {
self.write_str(~"[");
f();
self.write_str(~"]");
}
fn emit_vec_elt(idx: uint, f: fn()) {
if idx > 0u { self.write_str(~", "); }
fn emit_managed(&self, f: fn()) {
self.wr.write_str(~"@");
f();
}
fn emit_box(f: fn()) {
self.write_str(~"@");
fn emit_enum(&self, _name: &str, f: fn()) {
f();
}
fn emit_uniq(f: fn()) {
self.write_str(~"~");
fn emit_enum_variant(&self, v_name: &str, _v_id: uint, sz: uint,
f: fn()) {
self.wr.write_str(v_name);
if sz > 0u { self.wr.write_str(~"("); }
f();
if sz > 0u { self.wr.write_str(~")"); }
}
fn emit_enum_variant_arg(&self, idx: uint, f: fn()) {
if idx > 0u { self.wr.write_str(~", "); }
f();
}
fn emit_rec(f: fn()) {
self.write_str(~"{");
fn emit_borrowed_vec(&self, _len: uint, f: fn()) {
self.wr.write_str(~"&[");
f();
self.write_str(~"}");
self.wr.write_str(~"]");
}
fn emit_rec_field(f_name: &str, f_idx: uint, f: fn()) {
if f_idx > 0u { self.write_str(~", "); }
self.write_str(f_name);
self.write_str(~": ");
fn emit_owned_vec(&self, _len: uint, f: fn()) {
self.wr.write_str(~"~[");
f();
self.wr.write_str(~"]");
}
fn emit_managed_vec(&self, _len: uint, f: fn()) {
self.wr.write_str(~"@[");
f();
self.wr.write_str(~"]");
}
fn emit_vec_elt(&self, idx: uint, f: fn()) {
if idx > 0u { self.wr.write_str(~", "); }
f();
}
fn emit_tup(_sz: uint, f: fn()) {
self.write_str(~"(");
fn emit_rec(&self, f: fn()) {
self.wr.write_str(~"{");
f();
self.write_str(~")");
self.wr.write_str(~"}");
}
fn emit_tup_elt(idx: uint, f: fn()) {
if idx > 0u { self.write_str(~", "); }
fn emit_struct(&self, name: &str, f: fn()) {
self.wr.write_str(fmt!("%s {", name));
f();
self.wr.write_str(~"}");
}
fn emit_field(&self, name: &str, idx: uint, f: fn()) {
if idx > 0u { self.wr.write_str(~", "); }
self.wr.write_str(name);
self.wr.write_str(~": ");
f();
}
fn emit_tup(&self, _len: uint, f: fn()) {
self.wr.write_str(~"(");
f();
self.wr.write_str(~")");
}
fn emit_tup_elt(&self, idx: uint, f: fn()) {
if idx > 0u { self.wr.write_str(~", "); }
f();
}
}

View file

@ -1,176 +0,0 @@
#[forbid(deprecated_mode)];
use io::Writer;
use io::WriterUtil;
use serialization2;
pub struct Serializer {
wr: io::Writer,
}
pub fn Serializer(wr: io::Writer) -> Serializer {
Serializer { wr: wr }
}
pub impl Serializer: serialization2::Serializer {
fn emit_nil(&self) {
self.wr.write_str(~"()")
}
fn emit_uint(&self, v: uint) {
self.wr.write_str(fmt!("%?u", v));
}
fn emit_u64(&self, v: u64) {
self.wr.write_str(fmt!("%?_u64", v));
}
fn emit_u32(&self, v: u32) {
self.wr.write_str(fmt!("%?_u32", v));
}
fn emit_u16(&self, v: u16) {
self.wr.write_str(fmt!("%?_u16", v));
}
fn emit_u8(&self, v: u8) {
self.wr.write_str(fmt!("%?_u8", v));
}
fn emit_int(&self, v: int) {
self.wr.write_str(fmt!("%?", v));
}
fn emit_i64(&self, v: i64) {
self.wr.write_str(fmt!("%?_i64", v));
}
fn emit_i32(&self, v: i32) {
self.wr.write_str(fmt!("%?_i32", v));
}
fn emit_i16(&self, v: i16) {
self.wr.write_str(fmt!("%?_i16", v));
}
fn emit_i8(&self, v: i8) {
self.wr.write_str(fmt!("%?_i8", v));
}
fn emit_bool(&self, v: bool) {
self.wr.write_str(fmt!("%b", v));
}
fn emit_float(&self, v: float) {
self.wr.write_str(fmt!("%?_f", v));
}
fn emit_f64(&self, v: f64) {
self.wr.write_str(fmt!("%?_f64", v));
}
fn emit_f32(&self, v: f32) {
self.wr.write_str(fmt!("%?_f32", v));
}
fn emit_char(&self, v: char) {
self.wr.write_str(fmt!("%?", v));
}
fn emit_borrowed_str(&self, v: &str) {
self.wr.write_str(fmt!("&%?", v));
}
fn emit_owned_str(&self, v: &str) {
self.wr.write_str(fmt!("~%?", v));
}
fn emit_managed_str(&self, v: &str) {
self.wr.write_str(fmt!("@%?", v));
}
fn emit_borrowed(&self, f: fn()) {
self.wr.write_str(~"&");
f();
}
fn emit_owned(&self, f: fn()) {
self.wr.write_str(~"~");
f();
}
fn emit_managed(&self, f: fn()) {
self.wr.write_str(~"@");
f();
}
fn emit_enum(&self, _name: &str, f: fn()) {
f();
}
fn emit_enum_variant(&self, v_name: &str, _v_id: uint, sz: uint,
f: fn()) {
self.wr.write_str(v_name);
if sz > 0u { self.wr.write_str(~"("); }
f();
if sz > 0u { self.wr.write_str(~")"); }
}
fn emit_enum_variant_arg(&self, idx: uint, f: fn()) {
if idx > 0u { self.wr.write_str(~", "); }
f();
}
fn emit_borrowed_vec(&self, _len: uint, f: fn()) {
self.wr.write_str(~"&[");
f();
self.wr.write_str(~"]");
}
fn emit_owned_vec(&self, _len: uint, f: fn()) {
self.wr.write_str(~"~[");
f();
self.wr.write_str(~"]");
}
fn emit_managed_vec(&self, _len: uint, f: fn()) {
self.wr.write_str(~"@[");
f();
self.wr.write_str(~"]");
}
fn emit_vec_elt(&self, idx: uint, f: fn()) {
if idx > 0u { self.wr.write_str(~", "); }
f();
}
fn emit_rec(&self, f: fn()) {
self.wr.write_str(~"{");
f();
self.wr.write_str(~"}");
}
fn emit_struct(&self, name: &str, f: fn()) {
self.wr.write_str(fmt!("%s {", name));
f();
self.wr.write_str(~"}");
}
fn emit_field(&self, name: &str, idx: uint, f: fn()) {
if idx > 0u { self.wr.write_str(~", "); }
self.wr.write_str(name);
self.wr.write_str(~": ");
f();
}
fn emit_tup(&self, _len: uint, f: fn()) {
self.wr.write_str(~"(");
f();
self.wr.write_str(~")");
}
fn emit_tup_elt(&self, idx: uint, f: fn()) {
if idx > 0u { self.wr.write_str(~", "); }
f();
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,563 +0,0 @@
//! Support code for serialization.
/*
Core serialization interfaces.
*/
#[forbid(deprecated_mode)];
#[forbid(non_camel_case_types)];
pub trait Serializer {
// Primitive types:
fn emit_nil(&self);
fn emit_uint(&self, v: uint);
fn emit_u64(&self, v: u64);
fn emit_u32(&self, v: u32);
fn emit_u16(&self, v: u16);
fn emit_u8(&self, v: u8);
fn emit_int(&self, v: int);
fn emit_i64(&self, v: i64);
fn emit_i32(&self, v: i32);
fn emit_i16(&self, v: i16);
fn emit_i8(&self, v: i8);
fn emit_bool(&self, v: bool);
fn emit_float(&self, v: float);
fn emit_f64(&self, v: f64);
fn emit_f32(&self, v: f32);
fn emit_char(&self, v: char);
fn emit_borrowed_str(&self, v: &str);
fn emit_owned_str(&self, v: &str);
fn emit_managed_str(&self, v: &str);
// Compound types:
fn emit_borrowed(&self, f: fn());
fn emit_owned(&self, f: fn());
fn emit_managed(&self, f: fn());
fn emit_enum(&self, name: &str, f: fn());
fn emit_enum_variant(&self, v_name: &str, v_id: uint, sz: uint, f: fn());
fn emit_enum_variant_arg(&self, idx: uint, f: fn());
fn emit_borrowed_vec(&self, len: uint, f: fn());
fn emit_owned_vec(&self, len: uint, f: fn());
fn emit_managed_vec(&self, len: uint, f: fn());
fn emit_vec_elt(&self, idx: uint, f: fn());
fn emit_rec(&self, f: fn());
fn emit_struct(&self, name: &str, f: fn());
fn emit_field(&self, f_name: &str, f_idx: uint, f: fn());
fn emit_tup(&self, len: uint, f: fn());
fn emit_tup_elt(&self, idx: uint, f: fn());
}
pub trait Deserializer {
// Primitive types:
fn read_nil(&self) -> ();
fn read_uint(&self) -> uint;
fn read_u64(&self) -> u64;
fn read_u32(&self) -> u32;
fn read_u16(&self) -> u16;
fn read_u8(&self) -> u8;
fn read_int(&self) -> int;
fn read_i64(&self) -> i64;
fn read_i32(&self) -> i32;
fn read_i16(&self) -> i16;
fn read_i8(&self) -> i8;
fn read_bool(&self) -> bool;
fn read_f64(&self) -> f64;
fn read_f32(&self) -> f32;
fn read_float(&self) -> float;
fn read_char(&self) -> char;
fn read_owned_str(&self) -> ~str;
fn read_managed_str(&self) -> @str;
// Compound types:
fn read_enum<T>(&self, name: &str, f: fn() -> T) -> T;
fn read_enum_variant<T>(&self, f: fn(uint) -> T) -> T;
fn read_enum_variant_arg<T>(&self, idx: uint, f: fn() -> T) -> T;
fn read_owned<T>(&self, f: fn() -> T) -> T;
fn read_managed<T>(&self, f: fn() -> T) -> T;
fn read_owned_vec<T>(&self, f: fn(uint) -> T) -> T;
fn read_managed_vec<T>(&self, f: fn(uint) -> T) -> T;
fn read_vec_elt<T>(&self, idx: uint, f: fn() -> T) -> T;
fn read_rec<T>(&self, f: fn() -> T) -> T;
fn read_struct<T>(&self, name: &str, f: fn() -> T) -> T;
fn read_field<T>(&self, name: &str, idx: uint, f: fn() -> T) -> T;
fn read_tup<T>(&self, sz: uint, f: fn() -> T) -> T;
fn read_tup_elt<T>(&self, idx: uint, f: fn() -> T) -> T;
}
pub trait Serializable {
fn serialize<S: Serializer>(&self, s: &S);
}
pub trait Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> self;
}
pub impl uint: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_uint(*self) }
}
pub impl uint: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> uint {
d.read_uint()
}
}
pub impl u8: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_u8(*self) }
}
pub impl u8: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> u8 {
d.read_u8()
}
}
pub impl u16: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_u16(*self) }
}
pub impl u16: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> u16 {
d.read_u16()
}
}
pub impl u32: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_u32(*self) }
}
pub impl u32: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> u32 {
d.read_u32()
}
}
pub impl u64: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_u64(*self) }
}
pub impl u64: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> u64 {
d.read_u64()
}
}
pub impl int: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_int(*self) }
}
pub impl int: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> int {
d.read_int()
}
}
pub impl i8: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_i8(*self) }
}
pub impl i8: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> i8 {
d.read_i8()
}
}
pub impl i16: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_i16(*self) }
}
pub impl i16: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> i16 {
d.read_i16()
}
}
pub impl i32: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_i32(*self) }
}
pub impl i32: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> i32 {
d.read_i32()
}
}
pub impl i64: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_i64(*self) }
}
pub impl i64: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> i64 {
d.read_i64()
}
}
pub impl &str: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_borrowed_str(*self) }
}
pub impl ~str: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_owned_str(*self) }
}
pub impl ~str: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> ~str {
d.read_owned_str()
}
}
pub impl @str: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_managed_str(*self) }
}
pub impl @str: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> @str {
d.read_managed_str()
}
}
pub impl float: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_float(*self) }
}
pub impl float: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> float {
d.read_float()
}
}
pub impl f32: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_f32(*self) }
}
pub impl f32: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> f32 {
d.read_f32() }
}
pub impl f64: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_f64(*self) }
}
pub impl f64: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> f64 {
d.read_f64()
}
}
pub impl bool: Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_bool(*self) }
}
pub impl bool: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> bool {
d.read_bool()
}
}
pub impl (): Serializable {
fn serialize<S: Serializer>(&self, s: &S) { s.emit_nil() }
}
pub impl (): Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> () {
d.read_nil()
}
}
pub impl<T: Serializable> &T: Serializable {
fn serialize<S: Serializer>(&self, s: &S) {
s.emit_borrowed(|| (**self).serialize(s))
}
}
pub impl<T: Serializable> ~T: Serializable {
fn serialize<S: Serializer>(&self, s: &S) {
s.emit_owned(|| (**self).serialize(s))
}
}
pub impl<T: Deserializable> ~T: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> ~T {
d.read_owned(|| ~deserialize(d))
}
}
pub impl<T: Serializable> @T: Serializable {
fn serialize<S: Serializer>(&self, s: &S) {
s.emit_managed(|| (**self).serialize(s))
}
}
pub impl<T: Deserializable> @T: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> @T {
d.read_managed(|| @deserialize(d))
}
}
pub impl<T: Serializable> &[T]: Serializable {
fn serialize<S: Serializer>(&self, s: &S) {
do s.emit_borrowed_vec(self.len()) {
for self.eachi |i, e| {
s.emit_vec_elt(i, || e.serialize(s))
}
}
}
}
pub impl<T: Serializable> ~[T]: Serializable {
fn serialize<S: Serializer>(&self, s: &S) {
do s.emit_owned_vec(self.len()) {
for self.eachi |i, e| {
s.emit_vec_elt(i, || e.serialize(s))
}
}
}
}
pub impl<T: Deserializable> ~[T]: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> ~[T] {
do d.read_owned_vec |len| {
do vec::from_fn(len) |i| {
d.read_vec_elt(i, || deserialize(d))
}
}
}
}
pub impl<T: Serializable> @[T]: Serializable {
fn serialize<S: Serializer>(&self, s: &S) {
do s.emit_managed_vec(self.len()) {
for self.eachi |i, e| {
s.emit_vec_elt(i, || e.serialize(s))
}
}
}
}
pub impl<T: Deserializable> @[T]: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> @[T] {
do d.read_managed_vec |len| {
do at_vec::from_fn(len) |i| {
d.read_vec_elt(i, || deserialize(d))
}
}
}
}
pub impl<T: Serializable> Option<T>: Serializable {
fn serialize<S: Serializer>(&self, s: &S) {
do s.emit_enum(~"option") {
match *self {
None => do s.emit_enum_variant(~"none", 0u, 0u) {
},
Some(ref v) => do s.emit_enum_variant(~"some", 1u, 1u) {
s.emit_enum_variant_arg(0u, || v.serialize(s))
}
}
}
}
}
pub impl<T: Deserializable> Option<T>: Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> Option<T> {
do d.read_enum(~"option") {
do d.read_enum_variant |i| {
match i {
0 => None,
1 => Some(d.read_enum_variant_arg(0u, || deserialize(d))),
_ => fail(#fmt("Bad variant for option: %u", i))
}
}
}
}
}
pub impl<
T0: Serializable,
T1: Serializable
> (T0, T1): Serializable {
fn serialize<S: Serializer>(&self, s: &S) {
match *self {
(ref t0, ref t1) => {
do s.emit_tup(2) {
s.emit_tup_elt(0, || t0.serialize(s));
s.emit_tup_elt(1, || t1.serialize(s));
}
}
}
}
}
pub impl<
T0: Deserializable,
T1: Deserializable
> (T0, T1): Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> (T0, T1) {
do d.read_tup(2) {
(
d.read_tup_elt(0, || deserialize(d)),
d.read_tup_elt(1, || deserialize(d))
)
}
}
}
pub impl<
T0: Serializable,
T1: Serializable,
T2: Serializable
> (T0, T1, T2): Serializable {
fn serialize<S: Serializer>(&self, s: &S) {
match *self {
(ref t0, ref t1, ref t2) => {
do s.emit_tup(3) {
s.emit_tup_elt(0, || t0.serialize(s));
s.emit_tup_elt(1, || t1.serialize(s));
s.emit_tup_elt(2, || t2.serialize(s));
}
}
}
}
}
pub impl<
T0: Deserializable,
T1: Deserializable,
T2: Deserializable
> (T0, T1, T2): Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> (T0, T1, T2) {
do d.read_tup(3) {
(
d.read_tup_elt(0, || deserialize(d)),
d.read_tup_elt(1, || deserialize(d)),
d.read_tup_elt(2, || deserialize(d))
)
}
}
}
pub impl<
T0: Serializable,
T1: Serializable,
T2: Serializable,
T3: Serializable
> (T0, T1, T2, T3): Serializable {
fn serialize<S: Serializer>(&self, s: &S) {
match *self {
(ref t0, ref t1, ref t2, ref t3) => {
do s.emit_tup(4) {
s.emit_tup_elt(0, || t0.serialize(s));
s.emit_tup_elt(1, || t1.serialize(s));
s.emit_tup_elt(2, || t2.serialize(s));
s.emit_tup_elt(3, || t3.serialize(s));
}
}
}
}
}
pub impl<
T0: Deserializable,
T1: Deserializable,
T2: Deserializable,
T3: Deserializable
> (T0, T1, T2, T3): Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D) -> (T0, T1, T2, T3) {
do d.read_tup(4) {
(
d.read_tup_elt(0, || deserialize(d)),
d.read_tup_elt(1, || deserialize(d)),
d.read_tup_elt(2, || deserialize(d)),
d.read_tup_elt(3, || deserialize(d))
)
}
}
}
pub impl<
T0: Serializable,
T1: Serializable,
T2: Serializable,
T3: Serializable,
T4: Serializable
> (T0, T1, T2, T3, T4): Serializable {
fn serialize<S: Serializer>(&self, s: &S) {
match *self {
(ref t0, ref t1, ref t2, ref t3, ref t4) => {
do s.emit_tup(5) {
s.emit_tup_elt(0, || t0.serialize(s));
s.emit_tup_elt(1, || t1.serialize(s));
s.emit_tup_elt(2, || t2.serialize(s));
s.emit_tup_elt(3, || t3.serialize(s));
s.emit_tup_elt(4, || t4.serialize(s));
}
}
}
}
}
pub impl<
T0: Deserializable,
T1: Deserializable,
T2: Deserializable,
T3: Deserializable,
T4: Deserializable
> (T0, T1, T2, T3, T4): Deserializable {
static fn deserialize<D: Deserializer>(&self, d: &D)
-> (T0, T1, T2, T3, T4) {
do d.read_tup(5) {
(
d.read_tup_elt(0, || deserialize(d)),
d.read_tup_elt(1, || deserialize(d)),
d.read_tup_elt(2, || deserialize(d)),
d.read_tup_elt(3, || deserialize(d)),
d.read_tup_elt(4, || deserialize(d))
)
}
}
}
// ___________________________________________________________________________
// Helper routines
//
// In some cases, these should eventually be coded as traits.
pub trait SerializerHelpers {
fn emit_from_vec<T>(&self, v: &[T], f: fn(&T));
}
pub impl<S: Serializer> S: SerializerHelpers {
fn emit_from_vec<T>(&self, v: &[T], f: fn(&T)) {
do self.emit_owned_vec(v.len()) {
for v.eachi |i, e| {
do self.emit_vec_elt(i) {
f(e)
}
}
}
}
}
pub trait DeserializerHelpers {
fn read_to_vec<T>(&self, f: fn() -> T) -> ~[T];
}
pub impl<D: Deserializer> D: DeserializerHelpers {
fn read_to_vec<T>(&self, f: fn() -> T) -> ~[T] {
do self.read_owned_vec |len| {
do vec::from_fn(len) |i| {
self.read_vec_elt(i, || f())
}
}
}
}

View file

@ -899,7 +899,7 @@ mod test_qsort {
do sort::quick_sort(names) |x, y| { int::le(*x, *y) };
let immut_names = vec::from_mut(names);
let immut_names = vec::from_mut(move names);
let pairs = vec::zip(expected, immut_names);
for vec::each(pairs) |p| {

View file

@ -8,7 +8,7 @@ not required in or otherwise suitable for the core library.
*/
#[link(name = "std",
vers = "0.4",
vers = "0.5",
uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297",
url = "https://github.com/mozilla/rust/tree/master/src/libstd")];
@ -25,7 +25,7 @@ not required in or otherwise suitable for the core library.
#[allow(deprecated_mode)];
#[forbid(deprecated_pattern)];
extern mod core(vers = "0.4");
extern mod core(vers = "0.5");
use core::*;
// General io and system-services modules
@ -69,7 +69,6 @@ pub mod treemap;
// And ... other stuff
pub mod ebml;
pub mod ebml2;
pub mod dbg;
pub mod getopts;
pub mod json;
@ -79,7 +78,6 @@ pub mod tempfile;
pub mod term;
pub mod time;
pub mod prettyprint;
pub mod prettyprint2;
pub mod arena;
pub mod par;
pub mod cmp;
@ -93,7 +91,6 @@ mod unicode;
pub mod test;
pub mod serialization;
pub mod serialization2;
// Local Variables:
// mode: rust;

View file

@ -25,7 +25,7 @@ struct Waitqueue { head: pipes::Port<SignalEnd>,
fn new_waitqueue() -> Waitqueue {
let (block_tail, block_head) = pipes::stream();
Waitqueue { head: block_head, tail: block_tail }
Waitqueue { head: move block_head, tail: move block_tail }
}
// Signals one live task from the queue.
@ -71,7 +71,7 @@ enum Sem<Q: Send> = Exclusive<SemInner<Q>>;
#[doc(hidden)]
fn new_sem<Q: Send>(count: int, q: Q) -> Sem<Q> {
Sem(exclusive(SemInner {
mut count: count, waiters: new_waitqueue(), blocked: q }))
mut count: count, waiters: new_waitqueue(), blocked: move q }))
}
#[doc(hidden)]
fn new_sem_and_signal(count: int, num_condvars: uint)
@ -146,7 +146,7 @@ impl &Sem<~[mut Waitqueue]> {
}
}
// FIXME(#3136) should go inside of access()
// FIXME(#3588) should go inside of access()
#[doc(hidden)]
struct SemRelease {
sem: &Sem<()>,
@ -577,7 +577,7 @@ impl &RWlock {
}
}
// FIXME(#3136) should go inside of read()
// FIXME(#3588) should go inside of read()
#[doc(hidden)]
struct RWlockReleaseRead {
lock: &RWlock,
@ -606,7 +606,7 @@ fn RWlockReleaseRead(lock: &r/RWlock) -> RWlockReleaseRead/&r {
}
}
// FIXME(#3136) should go inside of downgrade()
// FIXME(#3588) should go inside of downgrade()
#[doc(hidden)]
struct RWlockReleaseDowngrade {
lock: &RWlock,
@ -686,7 +686,7 @@ mod tests {
fn test_sem_as_mutex() {
let s = ~semaphore(1);
let s2 = ~s.clone();
do task::spawn {
do task::spawn |move s2| {
do s2.access {
for 5.times { task::yield(); }
}
@ -701,7 +701,7 @@ mod tests {
let (c,p) = pipes::stream();
let s = ~semaphore(0);
let s2 = ~s.clone();
do task::spawn {
do task::spawn |move s2, move c| {
s2.acquire();
c.send(());
}
@ -713,7 +713,7 @@ mod tests {
let (c,p) = pipes::stream();
let s = ~semaphore(0);
let s2 = ~s.clone();
do task::spawn {
do task::spawn |move s2, move p| {
for 5.times { task::yield(); }
s2.release();
let _ = p.recv();
@ -729,7 +729,7 @@ mod tests {
let s2 = ~s.clone();
let (c1,p1) = pipes::stream();
let (c2,p2) = pipes::stream();
do task::spawn {
do task::spawn |move s2, move c1, move p2| {
do s2.access {
let _ = p2.recv();
c1.send(());
@ -748,10 +748,10 @@ mod tests {
let s = ~semaphore(1);
let s2 = ~s.clone();
let (c,p) = pipes::stream();
let child_data = ~mut Some((s2,c));
let child_data = ~mut Some((move s2, move c));
do s.access {
let (s2,c) = option::swap_unwrap(child_data);
do task::spawn {
do task::spawn |move c, move s2| {
c.send(());
do s2.access { }
c.send(());
@ -774,7 +774,7 @@ mod tests {
let m2 = ~m.clone();
let mut sharedstate = ~0;
let ptr = ptr::addr_of(&(*sharedstate));
do task::spawn {
do task::spawn |move m2, move c| {
let sharedstate: &mut int =
unsafe { cast::reinterpret_cast(&ptr) };
access_shared(sharedstate, m2, 10);
@ -803,7 +803,7 @@ mod tests {
// Child wakes up parent
do m.lock_cond |cond| {
let m2 = ~m.clone();
do task::spawn {
do task::spawn |move m2| {
do m2.lock_cond |cond| {
let woken = cond.signal();
assert woken;
@ -814,7 +814,7 @@ mod tests {
// Parent wakes up child
let (chan,port) = pipes::stream();
let m3 = ~m.clone();
do task::spawn {
do task::spawn |move chan, move m3| {
do m3.lock_cond |cond| {
chan.send(());
cond.wait();
@ -836,8 +836,8 @@ mod tests {
for num_waiters.times {
let mi = ~m.clone();
let (chan, port) = pipes::stream();
ports.push(port);
do task::spawn {
ports.push(move port);
do task::spawn |move chan, move mi| {
do mi.lock_cond |cond| {
chan.send(());
cond.wait();
@ -867,7 +867,7 @@ mod tests {
fn test_mutex_cond_no_waiter() {
let m = ~Mutex();
let m2 = ~m.clone();
do task::try {
do task::try |move m| {
do m.lock_cond |_x| { }
};
do m2.lock_cond |cond| {
@ -880,7 +880,7 @@ mod tests {
let m = ~Mutex();
let m2 = ~m.clone();
let result: result::Result<(),()> = do task::try {
let result: result::Result<(),()> = do task::try |move m2| {
do m2.lock {
fail;
}
@ -896,9 +896,9 @@ mod tests {
let m = ~Mutex();
let m2 = ~m.clone();
let result: result::Result<(),()> = do task::try {
let result: result::Result<(),()> = do task::try |move m2| {
let (c,p) = pipes::stream();
do task::spawn { // linked
do task::spawn |move p| { // linked
let _ = p.recv(); // wait for sibling to get in the mutex
task::yield();
fail;
@ -921,19 +921,19 @@ mod tests {
let m2 = ~m.clone();
let (c,p) = pipes::stream();
let result: result::Result<(),()> = do task::try {
let result: result::Result<(),()> = do task::try |move c, move m2| {
let mut sibling_convos = ~[];
for 2.times {
let (c,p) = pipes::stream();
let c = ~mut Some(c);
sibling_convos.push(p);
let c = ~mut Some(move c);
sibling_convos.push(move p);
let mi = ~m2.clone();
// spawn sibling task
do task::spawn { // linked
do task::spawn |move mi, move c| { // linked
do mi.lock_cond |cond| {
let c = option::swap_unwrap(c);
c.send(()); // tell sibling to go ahead
let _z = SendOnFailure(c);
let _z = SendOnFailure(move c);
cond.wait(); // block forever
}
}
@ -942,7 +942,7 @@ mod tests {
let _ = p.recv(); // wait for sibling to get in the mutex
}
do m2.lock { }
c.send(sibling_convos); // let parent wait on all children
c.send(move sibling_convos); // let parent wait on all children
fail;
};
assert result.is_err();
@ -959,7 +959,7 @@ mod tests {
fn SendOnFailure(c: pipes::Chan<()>) -> SendOnFailure {
SendOnFailure {
c: c
c: move c
}
}
}
@ -969,7 +969,7 @@ mod tests {
let m = ~Mutex();
do m.lock_cond |cond| {
let m2 = ~m.clone();
do task::spawn {
do task::spawn |move m2| {
do m2.lock_cond |cond| {
cond.signal_on(0);
}
@ -983,7 +983,7 @@ mod tests {
let m = ~mutex_with_condvars(2);
let m2 = ~m.clone();
let (c,p) = pipes::stream();
do task::spawn {
do task::spawn |move m2, move c| {
do m2.lock_cond |cond| {
c.send(());
cond.wait_on(1);
@ -1032,7 +1032,7 @@ mod tests {
},
DowngradeRead =>
do x.write_downgrade |mode| {
let mode = x.downgrade(mode);
let mode = x.downgrade(move mode);
(&mode).read(blk);
},
}
@ -1046,7 +1046,7 @@ mod tests {
let x2 = ~x.clone();
let mut sharedstate = ~0;
let ptr = ptr::addr_of(&(*sharedstate));
do task::spawn {
do task::spawn |move c, move x2| {
let sharedstate: &mut int =
unsafe { cast::reinterpret_cast(&ptr) };
access_shared(sharedstate, x2, mode1, 10);
@ -1089,7 +1089,7 @@ mod tests {
let x2 = ~x.clone();
let (c1,p1) = pipes::stream();
let (c2,p2) = pipes::stream();
do task::spawn {
do task::spawn |move c1, move x2, move p2| {
if !make_mode2_go_first {
let _ = p2.recv(); // parent sends to us once it locks, or ...
}
@ -1126,10 +1126,10 @@ mod tests {
// Tests that downgrade can unlock the lock in both modes
let x = ~RWlock();
do lock_rwlock_in_mode(x, Downgrade) { }
test_rwlock_handshake(x, Read, Read, false);
test_rwlock_handshake(move x, Read, Read, false);
let y = ~RWlock();
do lock_rwlock_in_mode(y, DowngradeRead) { }
test_rwlock_exclusion(y, Write, Write);
test_rwlock_exclusion(move y, Write, Write);
}
#[test]
fn test_rwlock_read_recursive() {
@ -1144,7 +1144,7 @@ mod tests {
// Child wakes up parent
do x.write_cond |cond| {
let x2 = ~x.clone();
do task::spawn {
do task::spawn |move x2| {
do x2.write_cond |cond| {
let woken = cond.signal();
assert woken;
@ -1155,7 +1155,7 @@ mod tests {
// Parent wakes up child
let (chan,port) = pipes::stream();
let x3 = ~x.clone();
do task::spawn {
do task::spawn |move x3, move chan| {
do x3.write_cond |cond| {
chan.send(());
cond.wait();
@ -1190,8 +1190,8 @@ mod tests {
for num_waiters.times {
let xi = ~x.clone();
let (chan, port) = pipes::stream();
ports.push(port);
do task::spawn {
ports.push(move port);
do task::spawn |move chan, move xi| {
do lock_cond(xi, dg1) |cond| {
chan.send(());
cond.wait();
@ -1226,7 +1226,7 @@ mod tests {
let x = ~RWlock();
let x2 = ~x.clone();
let result: result::Result<(),()> = do task::try {
let result: result::Result<(),()> = do task::try |move x2| {
do lock_rwlock_in_mode(x2, mode1) {
fail;
}
@ -1264,7 +1264,7 @@ mod tests {
let x = ~RWlock();
let y = ~RWlock();
do x.write_downgrade |xwrite| {
let mut xopt = Some(xwrite);
let mut xopt = Some(move xwrite);
do y.write_downgrade |_ywrite| {
y.downgrade(option::swap_unwrap(&mut xopt));
error!("oops, y.downgrade(x) should have failed!");

View file

@ -130,7 +130,7 @@ pub fn run_tests_console(opts: &TestOpts,
st.failed += 1u;
write_failed(st.out, st.use_color);
st.out.write_line(~"");
st.failures.push(test);
st.failures.push(move test);
}
TrIgnored => {
st.ignored += 1u;
@ -249,7 +249,7 @@ fn should_sort_failures_before_printing_them() {
mut passed: 0u,
mut failed: 0u,
mut ignored: 0u,
mut failures: ~[test_b, test_a]};
mut failures: ~[move test_b, move test_a]};
print_failures(st);
};
@ -534,9 +534,9 @@ mod tests {
for vec::each(names) |name| {
let test = {name: *name, testfn: copy testfn, ignore: false,
should_fail: false};
tests.push(test);
tests.push(move test);
}
tests
move tests
};
let filtered = filter_tests(&opts, tests);
@ -549,7 +549,7 @@ mod tests {
~"test::parse_ignored_flag",
~"test::sort_tests"];
let pairs = vec::zip(expected, filtered);
let pairs = vec::zip(expected, move filtered);
for vec::each(pairs) |p| {
match *p {

View file

@ -595,8 +595,7 @@ pub fn strptime(s: &str, format: &str) -> Result<Tm, ~str> {
fn strftime(format: &str, tm: Tm) -> ~str {
fn parse_type(ch: char, tm: &Tm) -> ~str {
//FIXME (#2350): Implement missing types.
let die = || #fmt("strftime: can't understand this format %c ",
ch);
let die = || fmt!("strftime: can't understand this format %c ", ch);
match ch {
'A' => match tm.tm_wday as int {
0 => ~"Sunday",

View file

@ -23,7 +23,7 @@ use comm = core::comm;
* * ch - a channel of type T to send a `val` on
* * val - a value of type T to send over the provided `ch`
*/
pub fn delayed_send<T: Copy Send>(iotask: IoTask,
pub fn delayed_send<T: Send>(iotask: IoTask,
msecs: uint, ch: comm::Chan<T>, val: T) {
unsafe {
let timer_done_po = core::comm::Port::<()>();
@ -55,7 +55,7 @@ pub fn delayed_send<T: Copy Send>(iotask: IoTask,
// delayed_send_cb has been processed by libuv
core::comm::recv(timer_done_po);
// notify the caller immediately
core::comm::send(ch, copy(val));
core::comm::send(ch, move(val));
// uv_close for this timer has been processed
core::comm::recv(timer_done_po);
};

View file

@ -11,28 +11,28 @@ use core::cmp::{Eq, Ord};
use core::option::{Some, None};
use Option = core::Option;
pub type TreeMap<K, V> = @mut TreeEdge<K, V>;
pub type TreeMap<K: Copy Eq Ord, V: Copy> = @mut TreeEdge<K, V>;
type TreeEdge<K, V> = Option<@TreeNode<K, V>>;
type TreeEdge<K: Copy Eq Ord, V: Copy> = Option<@TreeNode<K, V>>;
enum TreeNode<K, V> = {
struct TreeNode<K: Copy Eq Ord, V: Copy> {
key: K,
mut value: V,
mut left: TreeEdge<K, V>,
mut right: TreeEdge<K, V>
};
}
/// Create a treemap
pub fn TreeMap<K, V>() -> TreeMap<K, V> { @mut None }
pub fn TreeMap<K: Copy Eq Ord, V: Copy>() -> TreeMap<K, V> { @mut None }
/// Insert a value into the map
pub fn insert<K: Copy Eq Ord, V: Copy>(m: &mut TreeEdge<K, V>, k: K, v: V) {
match copy *m {
None => {
*m = Some(@TreeNode({key: k,
mut value: v,
mut left: None,
mut right: None}));
*m = Some(@TreeNode {key: k,
mut value: v,
mut left: None,
mut right: None});
return;
}
Some(node) => {
@ -67,7 +67,8 @@ pub fn find<K: Copy Eq Ord, V: Copy>(m: &const TreeEdge<K, V>, k: K)
}
/// Visit all pairs in the map in order.
pub fn traverse<K, V: Copy>(m: &const TreeEdge<K, V>, f: fn((&K), (&V))) {
pub fn traverse<K: Copy Eq Ord, V: Copy>(m: &const TreeEdge<K, V>,
f: fn((&K), (&V))) {
match copy *m {
None => (),
Some(node) => {
@ -79,6 +80,19 @@ pub fn traverse<K, V: Copy>(m: &const TreeEdge<K, V>, f: fn((&K), (&V))) {
}
}
/// Compare two treemaps and return true iff
/// they contain same keys and values
pub fn equals<K: Copy Eq Ord, V: Copy Eq>(t1: &const TreeEdge<K, V>,
t2: &const TreeEdge<K, V>)
-> bool {
let mut v1 = ~[];
let mut v2 = ~[];
traverse(t1, |k,v| { v1.push((copy *k, copy *v)) });
traverse(t2, |k,v| { v2.push((copy *k, copy *v)) });
return v1 == v2;
}
#[cfg(test)]
mod tests {
#[legacy_exports];
@ -127,6 +141,28 @@ mod tests {
traverse(m, |x,y| t(n, *x, *y));
}
#[test]
fn equality() {
let m1 = TreeMap();
insert(m1, 3, ());
insert(m1, 0, ());
insert(m1, 4, ());
insert(m1, 2, ());
insert(m1, 1, ());
let m2 = TreeMap();
insert(m2, 2, ());
insert(m2, 1, ());
insert(m2, 3, ());
insert(m2, 0, ());
insert(m2, 4, ());
assert equals(m1, m2);
let m3 = TreeMap();
assert !equals(m1,m3);
}
#[test]
fn u8_map() {
let m = TreeMap();

View file

@ -590,6 +590,8 @@ extern mod rustrt {
-> libc::c_int;
fn rust_uv_ip6_name(src: *sockaddr_in6, dst: *u8, size: libc::size_t)
-> libc::c_int;
fn rust_uv_ip4_port(src: *sockaddr_in) -> libc::c_uint;
fn rust_uv_ip6_port(src: *sockaddr_in6) -> libc::c_uint;
// FIXME ref #2064
fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t,
tcp_handle_ptr: *uv_tcp_t,
@ -606,6 +608,10 @@ extern mod rustrt {
// FIXME ref #2064
fn rust_uv_tcp_bind6(tcp_server: *uv_tcp_t,
++addr: *sockaddr_in6) -> libc::c_int;
fn rust_uv_tcp_getpeername(tcp_handle_ptr: *uv_tcp_t,
++name: *sockaddr_in) -> libc::c_int;
fn rust_uv_tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t,
++name: *sockaddr_in6) ->libc::c_int;
fn rust_uv_listen(stream: *libc::c_void, backlog: libc::c_int,
cb: *u8) -> libc::c_int;
fn rust_uv_accept(server: *libc::c_void, client: *libc::c_void)
@ -736,6 +742,16 @@ pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t,
addr_ptr);
}
pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t,
name: *sockaddr_in) -> libc::c_int {
return rustrt::rust_uv_tcp_getpeername(tcp_handle_ptr, name);
}
pub unsafe fn tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t,
name: *sockaddr_in6) ->libc::c_int {
return rustrt::rust_uv_tcp_getpeername6(tcp_handle_ptr, name);
}
pub unsafe fn listen<T>(stream: *T, backlog: libc::c_int,
cb: *u8) -> libc::c_int {
return rustrt::rust_uv_listen(stream as *libc::c_void, backlog, cb);
@ -857,6 +873,12 @@ pub unsafe fn ip6_name(src: &sockaddr_in6) -> ~str {
}
}
}
pub unsafe fn ip4_port(src: &sockaddr_in) -> uint {
rustrt::rust_uv_ip4_port(to_unsafe_ptr(src)) as uint
}
pub unsafe fn ip6_port(src: &sockaddr_in6) -> uint {
rustrt::rust_uv_ip6_port(to_unsafe_ptr(src)) as uint
}
pub unsafe fn timer_init(loop_ptr: *libc::c_void,
timer_ptr: *uv_timer_t) -> libc::c_int {
@ -1048,7 +1070,7 @@ pub mod test {
as *request_wrapper;
let buf_base = get_base_from_buf(buf);
let buf_len = get_len_from_buf(buf);
let bytes = vec::raw::from_buf(buf_base, buf_len as uint);
let bytes = vec::from_buf(buf_base, buf_len as uint);
let read_chan = *((*client_data).read_chan);
let msg_from_server = str::from_bytes(bytes);
core::comm::send(read_chan, msg_from_server);
@ -1223,7 +1245,7 @@ pub mod test {
buf_base as uint,
buf_len as uint,
nread));
let bytes = vec::raw::from_buf(buf_base, buf_len);
let bytes = vec::from_buf(buf_base, buf_len);
let request_str = str::from_bytes(bytes);
let client_data = get_data_for_uv_handle(
@ -1462,7 +1484,7 @@ pub mod test {
fn impl_uv_tcp_server_and_request() unsafe {
let bind_ip = ~"0.0.0.0";
let request_ip = ~"127.0.0.1";
let port = 8887;
let port = 8886;
let kill_server_msg = ~"does a dog have buddha nature?";
let server_resp_msg = ~"mu!";
let client_port = core::comm::Port::<~str>();

View file

@ -1,33 +1,14 @@
// The Rust abstract syntax tree.
use std::serialization::{Serializable,
Deserializable,
Serializer,
Deserializer};
use codemap::{span, filename};
use std::serialization::{Serializer,
Deserializer,
serialize_Option,
deserialize_Option,
serialize_uint,
deserialize_uint,
serialize_int,
deserialize_int,
serialize_i64,
deserialize_i64,
serialize_u64,
deserialize_u64,
serialize_str,
deserialize_str,
serialize_bool,
deserialize_bool};
use parse::token;
/* Note #1972 -- spans are serialized but not deserialized */
fn serialize_span<S>(_s: S, _v: span) {
}
fn deserialize_span<D>(_d: D) -> span {
ast_util::dummy_sp()
}
#[auto_serialize]
#[auto_deserialize]
type spanned<T> = {node: T, span: span};
@ -42,25 +23,62 @@ macro_rules! interner_key (
// implemented.
struct ident { repr: uint }
fn serialize_ident<S: Serializer>(s: S, i: ident) {
let intr = match unsafe{
task::local_data::local_data_get(interner_key!())
} {
None => fail ~"serialization: TLS interner not set up",
Some(intr) => intr
};
#[cfg(stage0)]
impl ident: Serializable {
fn serialize<S: Serializer>(&self, s: &S) {
let intr = match unsafe {
task::local_data::local_data_get(interner_key!())
} {
None => fail ~"serialization: TLS interner not set up",
Some(intr) => intr
};
s.emit_str(*(*intr).get(i));
s.emit_owned_str(*(*intr).get(*self));
}
}
fn deserialize_ident<D: Deserializer>(d: D) -> ident {
let intr = match unsafe{
task::local_data::local_data_get(interner_key!())
} {
None => fail ~"deserialization: TLS interner not set up",
Some(intr) => intr
};
(*intr).intern(@d.read_str())
#[cfg(stage0)]
impl ident: Deserializable {
static fn deserialize<D: Deserializer>(d: &D) -> ident {
let intr = match unsafe {
task::local_data::local_data_get(interner_key!())
} {
None => fail ~"deserialization: TLS interner not set up",
Some(intr) => intr
};
(*intr).intern(@d.read_owned_str())
}
}
#[cfg(stage1)]
#[cfg(stage2)]
impl<S: Serializer> ident: Serializable<S> {
fn serialize(&self, s: &S) {
let intr = match unsafe {
task::local_data::local_data_get(interner_key!())
} {
None => fail ~"serialization: TLS interner not set up",
Some(intr) => intr
};
s.emit_owned_str(*(*intr).get(*self));
}
}
#[cfg(stage1)]
#[cfg(stage2)]
impl<D: Deserializer> ident: Deserializable<D> {
static fn deserialize(d: &D) -> ident {
let intr = match unsafe {
task::local_data::local_data_get(interner_key!())
} {
None => fail ~"deserialization: TLS interner not set up",
Some(intr) => intr
};
(*intr).intern(@d.read_owned_str())
}
}
impl ident: cmp::Eq {
@ -75,23 +93,22 @@ impl ident: to_bytes::IterBytes {
}
// Functions may or may not have names.
#[auto_serialize]
type fn_ident = Option<ident>;
#[auto_serialize]
#[auto_deserialize]
type path = {span: span,
global: bool,
idents: ~[ident],
rp: Option<@region>,
types: ~[@ty]};
types: ~[@Ty]};
#[auto_serialize]
type crate_num = int;
#[auto_serialize]
type node_id = int;
#[auto_serialize]
#[auto_deserialize]
type def_id = {crate: crate_num, node: node_id};
impl def_id : cmp::Eq {
@ -105,21 +122,24 @@ const local_crate: crate_num = 0;
const crate_node_id: node_id = 0;
#[auto_serialize]
enum ty_param_bound {
bound_copy,
bound_send,
bound_const,
bound_owned,
bound_trait(@ty),
}
#[auto_deserialize]
// The AST represents all type param bounds as types.
// typeck::collect::compute_bounds matches these against
// the "special" built-in traits (see middle::lang_items) and
// detects Copy, Send, Owned, and Const.
enum ty_param_bound = @Ty;
#[auto_serialize]
#[auto_deserialize]
type ty_param = {ident: ident, id: node_id, bounds: @~[ty_param_bound]};
#[auto_serialize]
#[auto_deserialize]
enum def {
def_fn(def_id, purity),
def_static_method(def_id, purity),
def_static_method(/* method */ def_id,
/* trait */ Option<def_id>,
purity),
def_self(node_id),
def_mod(def_id),
def_foreign_mod(def_id),
@ -136,7 +156,7 @@ enum def {
@def, // closed over def
node_id, // expr node that creates the closure
node_id), // id for the block/body of the closure expr
def_class(def_id, bool /* has constructor */),
def_class(def_id),
def_typaram_binder(node_id), /* class, impl or trait that has ty params */
def_region(node_id),
def_label(node_id)
@ -151,9 +171,10 @@ impl def : cmp::Eq {
_ => false
}
}
def_static_method(e0a, e1a) => {
def_static_method(e0a, e1a, e2a) => {
match (*other) {
def_static_method(e0b, e1b) => e0a == e0b && e1a == e1b,
def_static_method(e0b, e1b, e2b) =>
e0a == e0b && e1a == e1b && e2a == e2b,
_ => false
}
}
@ -236,9 +257,9 @@ impl def : cmp::Eq {
_ => false
}
}
def_class(e0a, e1a) => {
def_class(e0a) => {
match (*other) {
def_class(e0b, e1b) => e0a == e0b && e1a == e1b,
def_class(e0b) => e0a == e0b,
_ => false
}
}
@ -293,20 +314,20 @@ enum crate_directive_ {
type crate_directive = spanned<crate_directive_>;
#[auto_serialize]
type meta_item = spanned<meta_item_>;
#[auto_serialize]
#[auto_deserialize]
enum meta_item_ {
meta_word(~str),
meta_list(~str, ~[@meta_item]),
meta_name_value(~str, lit),
}
#[auto_serialize]
type blk = spanned<blk_>;
#[auto_serialize]
#[auto_deserialize]
type blk_ = {view_items: ~[@view_item],
stmts: ~[@stmt],
expr: Option<@expr>,
@ -314,12 +335,15 @@ type blk_ = {view_items: ~[@view_item],
rules: blk_check_mode};
#[auto_serialize]
#[auto_deserialize]
type pat = {id: node_id, node: pat_, span: span};
#[auto_serialize]
#[auto_deserialize]
type field_pat = {ident: ident, pat: @pat};
#[auto_serialize]
#[auto_deserialize]
enum binding_mode {
bind_by_value,
bind_by_move,
@ -376,6 +400,7 @@ impl binding_mode : cmp::Eq {
}
#[auto_serialize]
#[auto_deserialize]
enum pat_ {
pat_wild,
// A pat_ident may either be a new bound variable,
@ -399,6 +424,7 @@ enum pat_ {
}
#[auto_serialize]
#[auto_deserialize]
enum mutability { m_mutbl, m_imm, m_const, }
impl mutability : to_bytes::IterBytes {
@ -415,6 +441,7 @@ impl mutability : cmp::Eq {
}
#[auto_serialize]
#[auto_deserialize]
enum proto {
proto_bare, // foreign fn
proto_uniq, // fn~
@ -430,18 +457,20 @@ impl proto : cmp::Eq {
}
#[auto_serialize]
#[auto_deserialize]
enum vstore {
// FIXME (#2112): Change uint to @expr (actually only constant exprs)
vstore_fixed(Option<uint>), // [1,2,3,4]/_ or 4
// FIXME (#3469): Change uint to @expr (actually only constant exprs)
vstore_fixed(Option<uint>), // [1,2,3,4]
vstore_uniq, // ~[1,2,3,4]
vstore_box, // @[1,2,3,4]
vstore_slice(@region) // &[1,2,3,4](foo)?
}
#[auto_serialize]
#[auto_deserialize]
enum expr_vstore {
// FIXME (#2112): Change uint to @expr (actually only constant exprs)
expr_vstore_fixed(Option<uint>), // [1,2,3,4]/_ or 4
// FIXME (#3469): Change uint to @expr (actually only constant exprs)
expr_vstore_fixed(Option<uint>), // [1,2,3,4]
expr_vstore_uniq, // ~[1,2,3,4]
expr_vstore_box, // @[1,2,3,4]
expr_vstore_slice // &[1,2,3,4]
@ -455,6 +484,7 @@ pure fn is_blockish(p: ast::proto) -> bool {
}
#[auto_serialize]
#[auto_deserialize]
enum binop {
add,
subtract,
@ -484,6 +514,7 @@ impl binop : cmp::Eq {
}
#[auto_serialize]
#[auto_deserialize]
enum unop {
box(mutability),
uniq(mutability),
@ -535,6 +566,7 @@ impl unop : cmp::Eq {
// Generally, after typeck you can get the inferred value
// using ty::resolved_T(...).
#[auto_serialize]
#[auto_deserialize]
enum inferable<T> {
expl(T),
infer(node_id)
@ -574,6 +606,7 @@ impl<T:cmp::Eq> inferable<T> : cmp::Eq {
// "resolved" mode: the real modes.
#[auto_serialize]
#[auto_deserialize]
enum rmode { by_ref, by_val, by_move, by_copy }
impl rmode : to_bytes::IterBytes {
@ -591,13 +624,12 @@ impl rmode : cmp::Eq {
}
// inferable mode.
#[auto_serialize]
type mode = inferable<rmode>;
#[auto_serialize]
type stmt = spanned<stmt_>;
#[auto_serialize]
#[auto_deserialize]
enum stmt_ {
stmt_decl(@decl, node_id),
@ -609,6 +641,7 @@ enum stmt_ {
}
#[auto_serialize]
#[auto_deserialize]
enum init_op { init_assign, init_move, }
impl init_op : cmp::Eq {
@ -632,33 +665,36 @@ impl init_op : cmp::Eq {
}
#[auto_serialize]
#[auto_deserialize]
type initializer = {op: init_op, expr: @expr};
// FIXME (pending discussion of #1697, #2178...): local should really be
// a refinement on pat.
#[auto_serialize]
type local_ = {is_mutbl: bool, ty: @ty, pat: @pat,
#[auto_deserialize]
type local_ = {is_mutbl: bool, ty: @Ty, pat: @pat,
init: Option<initializer>, id: node_id};
#[auto_serialize]
type local = spanned<local_>;
#[auto_serialize]
type decl = spanned<decl_>;
#[auto_serialize]
#[auto_deserialize]
enum decl_ { decl_local(~[@local]), decl_item(@item), }
#[auto_serialize]
#[auto_deserialize]
type arm = {pats: ~[@pat], guard: Option<@expr>, body: blk};
#[auto_serialize]
#[auto_deserialize]
type field_ = {mutbl: mutability, ident: ident, expr: @expr};
#[auto_serialize]
type field = spanned<field_>;
#[auto_serialize]
#[auto_deserialize]
enum blk_check_mode { default_blk, unsafe_blk, }
impl blk_check_mode : cmp::Eq {
@ -674,17 +710,17 @@ impl blk_check_mode : cmp::Eq {
}
#[auto_serialize]
#[auto_deserialize]
type expr = {id: node_id, callee_id: node_id, node: expr_, span: span};
// Extra node ID is only used for index, assign_op, unary, binary
#[auto_serialize]
#[auto_deserialize]
enum log_level { error, debug, other }
// 0 = error, 1 = debug, 2 = other
#[auto_serialize]
enum alt_mode { alt_check, alt_exhaustive, }
#[auto_serialize]
#[auto_deserialize]
enum expr_ {
expr_vstore(@expr, expr_vstore),
expr_vec(~[@expr], mutability),
@ -694,7 +730,7 @@ enum expr_ {
expr_binary(binop, @expr, @expr),
expr_unary(unop, @expr),
expr_lit(@lit),
expr_cast(@expr, @ty),
expr_cast(@expr, @Ty),
expr_if(@expr, blk, Option<@expr>),
expr_while(@expr, blk),
/* Conditionless loop (can be exited with break, cont, ret, or fail)
@ -718,7 +754,7 @@ enum expr_ {
expr_assign(@expr, @expr),
expr_swap(@expr, @expr),
expr_assign_op(binop, @expr, @expr),
expr_field(@expr, ident, ~[@ty]),
expr_field(@expr, ident, ~[@Ty]),
expr_index(@expr, @expr),
expr_path(@path),
expr_addr_of(mutability, @expr),
@ -741,14 +777,16 @@ enum expr_ {
}
#[auto_serialize]
type capture_item = @{
#[auto_deserialize]
type capture_item_ = {
id: int,
is_move: bool,
name: ident, // Currently, can only capture a local var.
span: span
};
#[auto_serialize]
type capture_item = @capture_item_;
type capture_clause = @~[capture_item];
//
@ -768,12 +806,13 @@ type capture_clause = @~[capture_item];
// error.
//
#[auto_serialize]
#[auto_deserialize]
#[doc="For macro invocations; parsing is delegated to the macro"]
enum token_tree {
tt_tok(span, token::token),
tt_tok(span, token::Token),
tt_delim(~[token_tree]),
// These only make sense for right-hand-sides of MBE macros
tt_seq(span, ~[token_tree], Option<token::token>, bool),
tt_seq(span, ~[token_tree], Option<token::Token>, bool),
tt_nonterminal(span, ident)
}
@ -829,33 +868,32 @@ enum token_tree {
// If you understand that, you have closed to loop and understand the whole
// macro system. Congratulations.
//
#[auto_serialize]
type matcher = spanned<matcher_>;
#[auto_serialize]
#[auto_deserialize]
enum matcher_ {
// match one token
match_tok(token::token),
match_tok(token::Token),
// match repetitions of a sequence: body, separator, zero ok?,
// lo, hi position-in-match-array used:
match_seq(~[matcher], Option<token::token>, bool, uint, uint),
match_seq(~[matcher], Option<token::Token>, bool, uint, uint),
// parse a Rust NT: name to bind, name of NT, position in match array:
match_nonterminal(ident, ident, uint)
}
#[auto_serialize]
type mac = spanned<mac_>;
#[auto_serialize]
type mac_arg = Option<@expr>;
#[auto_serialize]
#[auto_deserialize]
type mac_body_ = {span: span};
#[auto_serialize]
type mac_body = Option<mac_body_>;
#[auto_serialize]
#[auto_deserialize]
enum mac_ {
mac_invoc(@path, mac_arg, mac_body), // old macro-invocation
mac_invoc_tt(@path,~[token_tree]), // new macro-invocation
@ -866,10 +904,10 @@ enum mac_ {
mac_var(uint)
}
#[auto_serialize]
type lit = spanned<lit_>;
#[auto_serialize]
#[auto_deserialize]
enum lit_ {
lit_str(@~str),
lit_int(i64, int_ty),
@ -911,20 +949,23 @@ impl ast::lit_: cmp::Eq {
// NB: If you change this, you'll probably want to change the corresponding
// type structure in middle/ty.rs as well.
#[auto_serialize]
type mt = {ty: @ty, mutbl: mutability};
#[auto_deserialize]
type mt = {ty: @Ty, mutbl: mutability};
#[auto_serialize]
#[auto_deserialize]
type ty_field_ = {ident: ident, mt: mt};
#[auto_serialize]
type ty_field = spanned<ty_field_>;
#[auto_serialize]
#[auto_deserialize]
type ty_method = {ident: ident, attrs: ~[attribute], purity: purity,
decl: fn_decl, tps: ~[ty_param], self_ty: self_ty,
id: node_id, span: span};
#[auto_serialize]
#[auto_deserialize]
// A trait method is either required (meaning it doesn't have an
// implementation, just a signature) or provided (meaning it has a default
// implementation).
@ -934,6 +975,7 @@ enum trait_method {
}
#[auto_serialize]
#[auto_deserialize]
enum int_ty { ty_i, ty_char, ty_i8, ty_i16, ty_i32, ty_i64, }
impl int_ty : to_bytes::IterBytes {
@ -963,6 +1005,7 @@ impl int_ty : cmp::Eq {
}
#[auto_serialize]
#[auto_deserialize]
enum uint_ty { ty_u, ty_u8, ty_u16, ty_u32, ty_u64, }
impl uint_ty : to_bytes::IterBytes {
@ -990,6 +1033,7 @@ impl uint_ty : cmp::Eq {
}
#[auto_serialize]
#[auto_deserialize]
enum float_ty { ty_f, ty_f32, ty_f64, }
impl float_ty : to_bytes::IterBytes {
@ -1008,10 +1052,12 @@ impl float_ty : cmp::Eq {
}
#[auto_serialize]
type ty = {id: node_id, node: ty_, span: span};
#[auto_deserialize]
type Ty = {id: node_id, node: ty_, span: span};
// Not represented directly in the AST, referred to by name through a ty_path.
#[auto_serialize]
#[auto_deserialize]
enum prim_ty {
ty_int(int_ty),
ty_uint(uint_ty),
@ -1059,9 +1105,11 @@ impl prim_ty : cmp::Eq {
}
#[auto_serialize]
#[auto_deserialize]
type region = {id: node_id, node: region_};
#[auto_serialize]
#[auto_deserialize]
enum region_ {
re_anon,
re_static,
@ -1070,6 +1118,7 @@ enum region_ {
}
#[auto_serialize]
#[auto_deserialize]
enum ty_ {
ty_nil,
ty_bot, /* bottom type */
@ -1080,9 +1129,9 @@ enum ty_ {
ty_rptr(@region, mt),
ty_rec(~[ty_field]),
ty_fn(proto, purity, @~[ty_param_bound], fn_decl),
ty_tup(~[@ty]),
ty_tup(~[@Ty]),
ty_path(@path, node_id),
ty_fixed_length(@ty, Option<uint>),
ty_fixed_length(@Ty, Option<uint>),
ty_mac(mac),
// ty_infer means the type should be inferred instead of it having been
// specified. This should only appear at the "top level" of a type and not
@ -1092,16 +1141,16 @@ enum ty_ {
// Equality and byte-iter (hashing) can be quite approximate for AST types.
// since we only care about this for normalizing them to "real" types.
impl ty : cmp::Eq {
pure fn eq(other: &ty) -> bool {
impl Ty : cmp::Eq {
pure fn eq(other: &Ty) -> bool {
ptr::addr_of(&self) == ptr::addr_of(&(*other))
}
pure fn ne(other: &ty) -> bool {
pure fn ne(other: &Ty) -> bool {
ptr::addr_of(&self) != ptr::addr_of(&(*other))
}
}
impl ty : to_bytes::IterBytes {
impl Ty : to_bytes::IterBytes {
pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
to_bytes::iter_bytes_2(&self.span.lo, &self.span.hi, lsb0, f);
}
@ -1109,15 +1158,18 @@ impl ty : to_bytes::IterBytes {
#[auto_serialize]
type arg = {mode: mode, ty: @ty, ident: ident, id: node_id};
#[auto_deserialize]
type arg = {mode: mode, ty: @Ty, ident: ident, id: node_id};
#[auto_serialize]
#[auto_deserialize]
type fn_decl =
{inputs: ~[arg],
output: @ty,
output: @Ty,
cf: ret_style};
#[auto_serialize]
#[auto_deserialize]
enum purity {
pure_fn, // declared with "pure fn"
unsafe_fn, // declared with "unsafe fn"
@ -1139,6 +1191,7 @@ impl purity : cmp::Eq {
}
#[auto_serialize]
#[auto_deserialize]
enum ret_style {
noreturn, // functions with return type _|_ that always
// raise an error or exit (i.e. never return to the caller)
@ -1164,6 +1217,7 @@ impl ret_style : cmp::Eq {
}
#[auto_serialize]
#[auto_deserialize]
enum self_ty_ {
sty_static, // no self: static method
sty_by_ref, // old by-reference self: ``
@ -1217,10 +1271,10 @@ impl self_ty_ : cmp::Eq {
pure fn ne(other: &self_ty_) -> bool { !self.eq(other) }
}
#[auto_serialize]
type self_ty = spanned<self_ty_>;
#[auto_serialize]
#[auto_deserialize]
type method = {ident: ident, attrs: ~[attribute],
tps: ~[ty_param], self_ty: self_ty,
purity: purity, decl: fn_decl, body: blk,
@ -1228,9 +1282,11 @@ type method = {ident: ident, attrs: ~[attribute],
vis: visibility};
#[auto_serialize]
#[auto_deserialize]
type _mod = {view_items: ~[@view_item], items: ~[@item]};
#[auto_serialize]
#[auto_deserialize]
enum foreign_abi {
foreign_abi_rust_intrinsic,
foreign_abi_cdecl,
@ -1239,6 +1295,7 @@ enum foreign_abi {
// Foreign mods can be named or anonymous
#[auto_serialize]
#[auto_deserialize]
enum foreign_mod_sort { named, anonymous }
impl foreign_mod_sort : cmp::Eq {
@ -1263,15 +1320,18 @@ impl foreign_abi : cmp::Eq {
}
#[auto_serialize]
#[auto_deserialize]
type foreign_mod =
{sort: foreign_mod_sort,
view_items: ~[@view_item],
items: ~[@foreign_item]};
#[auto_serialize]
type variant_arg = {ty: @ty, id: node_id};
#[auto_deserialize]
type variant_arg = {ty: @Ty, id: node_id};
#[auto_serialize]
#[auto_deserialize]
enum variant_kind {
tuple_variant_kind(~[variant_arg]),
struct_variant_kind(@struct_def),
@ -1279,22 +1339,28 @@ enum variant_kind {
}
#[auto_serialize]
enum enum_def = { variants: ~[variant], common: Option<@struct_def> };
#[auto_deserialize]
type enum_def_ = { variants: ~[variant], common: Option<@struct_def> };
#[auto_serialize]
#[auto_deserialize]
enum enum_def = enum_def_;
#[auto_serialize]
#[auto_deserialize]
type variant_ = {name: ident, attrs: ~[attribute], kind: variant_kind,
id: node_id, disr_expr: Option<@expr>, vis: visibility};
#[auto_serialize]
type variant = spanned<variant_>;
#[auto_serialize]
#[auto_deserialize]
type path_list_ident_ = {name: ident, id: node_id};
#[auto_serialize]
type path_list_ident = spanned<path_list_ident_>;
#[auto_serialize]
#[auto_deserialize]
enum namespace { module_ns, type_value_ns }
impl namespace : cmp::Eq {
@ -1304,10 +1370,10 @@ impl namespace : cmp::Eq {
pure fn ne(other: &namespace) -> bool { !self.eq(other) }
}
#[auto_serialize]
type view_path = spanned<view_path_>;
#[auto_serialize]
#[auto_deserialize]
enum view_path_ {
// quux = foo::bar::baz
@ -1325,10 +1391,12 @@ enum view_path_ {
}
#[auto_serialize]
#[auto_deserialize]
type view_item = {node: view_item_, attrs: ~[attribute],
vis: visibility, span: span};
#[auto_serialize]
#[auto_deserialize]
enum view_item_ {
view_item_use(ident, ~[@meta_item], node_id),
view_item_import(~[@view_path]),
@ -1336,13 +1404,13 @@ enum view_item_ {
}
// Meta-data associated with an item
#[auto_serialize]
type attribute = spanned<attribute_>;
// Distinguishes between attributes that decorate items and attributes that
// are contained as statements within items. These two cases need to be
// distinguished for pretty-printing.
#[auto_serialize]
#[auto_deserialize]
enum attr_style { attr_outer, attr_inner, }
impl attr_style : cmp::Eq {
@ -1354,6 +1422,7 @@ impl attr_style : cmp::Eq {
// doc-comments are promoted to attributes that have is_sugared_doc = true
#[auto_serialize]
#[auto_deserialize]
type attribute_ = {style: attr_style, value: meta_item, is_sugared_doc: bool};
/*
@ -1366,9 +1435,11 @@ type attribute_ = {style: attr_style, value: meta_item, is_sugared_doc: bool};
trait)
*/
#[auto_serialize]
#[auto_deserialize]
type trait_ref = {path: @path, ref_id: node_id, impl_id: node_id};
#[auto_serialize]
#[auto_deserialize]
enum visibility { public, private, inherited }
impl visibility : cmp::Eq {
@ -1386,29 +1457,29 @@ impl visibility : cmp::Eq {
}
#[auto_serialize]
#[auto_deserialize]
type struct_field_ = {
kind: struct_field_kind,
id: node_id,
ty: @ty
ty: @Ty
};
#[auto_serialize]
type struct_field = spanned<struct_field_>;
#[auto_serialize]
#[auto_deserialize]
enum struct_field_kind {
named_field(ident, class_mutability, visibility),
unnamed_field // element of a tuple-like struct
}
#[auto_serialize]
#[auto_deserialize]
type struct_def = {
traits: ~[@trait_ref], /* traits this struct implements */
fields: ~[@struct_field], /* fields */
methods: ~[@method], /* methods */
/* (not including ctor or dtor) */
/* ctor is optional, and will soon go away */
ctor: Option<class_ctor>,
/* dtor is optional */
dtor: Option<class_dtor>
};
@ -1418,28 +1489,31 @@ type struct_def = {
we just use dummy names for anon items.
*/
#[auto_serialize]
#[auto_deserialize]
type item = {ident: ident, attrs: ~[attribute],
id: node_id, node: item_,
vis: visibility, span: span};
#[auto_serialize]
#[auto_deserialize]
enum item_ {
item_const(@ty, @expr),
item_const(@Ty, @expr),
item_fn(fn_decl, purity, ~[ty_param], blk),
item_mod(_mod),
item_foreign_mod(foreign_mod),
item_ty(@ty, ~[ty_param]),
item_ty(@Ty, ~[ty_param]),
item_enum(enum_def, ~[ty_param]),
item_class(@struct_def, ~[ty_param]),
item_trait(~[ty_param], ~[@trait_ref], ~[trait_method]),
item_impl(~[ty_param],
Option<@trait_ref>, /* (optional) trait this impl implements */
@ty, /* self */
@Ty, /* self */
~[@method]),
item_mac(mac),
}
#[auto_serialize]
#[auto_deserialize]
enum class_mutability { class_mutable, class_immutable }
impl class_mutability : to_bytes::IterBytes {
@ -1460,26 +1534,27 @@ impl class_mutability : cmp::Eq {
pure fn ne(other: &class_mutability) -> bool { !self.eq(other) }
}
#[auto_serialize]
type class_ctor = spanned<class_ctor_>;
#[auto_serialize]
#[auto_deserialize]
type class_ctor_ = {id: node_id,
attrs: ~[attribute],
self_id: node_id,
dec: fn_decl,
body: blk};
#[auto_serialize]
type class_dtor = spanned<class_dtor_>;
#[auto_serialize]
#[auto_deserialize]
type class_dtor_ = {id: node_id,
attrs: ~[attribute],
self_id: node_id,
body: blk};
#[auto_serialize]
#[auto_deserialize]
type foreign_item =
{ident: ident,
attrs: ~[attribute],
@ -1489,20 +1564,21 @@ type foreign_item =
vis: visibility};
#[auto_serialize]
#[auto_deserialize]
enum foreign_item_ {
foreign_item_fn(fn_decl, purity, ~[ty_param]),
foreign_item_const(@ty)
foreign_item_const(@Ty)
}
// The data we save and restore about an inlined item or method. This is not
// part of the AST that we parse from a file, but it becomes part of the tree
// that we trans.
#[auto_serialize]
#[auto_deserialize]
enum inlined_item {
ii_item(@item),
ii_method(def_id /* impl id */, @method),
ii_foreign(@foreign_item),
ii_ctor(class_ctor, ident, ~[ty_param], def_id /* parent id */),
ii_dtor(class_dtor, ident, ~[ty_param], def_id /* parent id */)
}

View file

@ -71,9 +71,6 @@ enum ast_node {
// order they are introduced.
node_arg(arg, uint),
node_local(uint),
// Constructor for a class
// def_id is parent id
node_ctor(ident, ~[ty_param], @class_ctor, def_id, @path),
// Destructor for a class
node_dtor(~[ty_param], @class_dtor, def_id, @path),
node_block(blk),
@ -132,7 +129,7 @@ fn map_decoded_item(diag: span_handler,
// don't decode and instantiate the impl, but just the method, we have to
// add it to the table now:
match ii {
ii_item(*) | ii_ctor(*) | ii_dtor(*) => { /* fallthrough */ }
ii_item(*) | ii_dtor(*) => { /* fallthrough */ }
ii_foreign(i) => {
cx.map.insert(i.id, node_foreign_item(i, foreign_abi_rust_intrinsic,
@path));
@ -155,18 +152,6 @@ fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
cx.local_id += 1u;
}
match fk {
visit::fk_ctor(nm, attrs, tps, self_id, parent_id) => {
let ct = @{node: {id: id,
attrs: attrs,
self_id: self_id,
dec: /* FIXME (#2543) */ copy decl,
body: /* FIXME (#2543) */ copy body},
span: sp};
cx.map.insert(id, node_ctor(/* FIXME (#2543) */ copy nm,
/* FIXME (#2543) */ copy tps,
ct, parent_id,
@/* FIXME (#2543) */ copy cx.path));
}
visit::fk_dtor(tps, attrs, self_id, parent_id) => {
let dt = @{node: {id: id, attrs: attrs, self_id: self_id,
body: /* FIXME (#2543) */ copy body}, span: sp};
@ -382,9 +367,6 @@ fn node_id_to_str(map: map, id: node_id, itr: @ident_interner) -> ~str {
Some(node_local(_)) => { // add more info here
fmt!("local (id=%?)", id)
}
Some(node_ctor(*)) => { // add more info here
fmt!("node_ctor (id=%?)", id)
}
Some(node_dtor(*)) => { // add more info here
fmt!("node_dtor (id=%?)", id)
}

View file

@ -54,10 +54,10 @@ fn variant_def_ids(d: def) -> {enm: def_id, var: def_id} {
pure fn def_id_of_def(d: def) -> def_id {
match d {
def_fn(id, _) | def_static_method(id, _) | def_mod(id) |
def_fn(id, _) | def_static_method(id, _, _) | def_mod(id) |
def_foreign_mod(id) | def_const(id) |
def_variant(_, id) | def_ty(id) | def_ty_param(id, _) |
def_use(id) | def_class(id, _) => {
def_use(id) | def_class(id) => {
id
}
def_arg(id, _) | def_local(id, _) | def_self(id) |
@ -233,7 +233,6 @@ fn is_exported(i: ident, m: _mod) -> bool {
}
}
// FIXME: glob-exports aren't supported yet. (#2006)
_ => ()
}
}
@ -339,7 +338,6 @@ impl inlined_item: inlined_item_utils {
ii_item(i) => /* FIXME (#2543) */ copy i.ident,
ii_foreign(i) => /* FIXME (#2543) */ copy i.ident,
ii_method(_, m) => /* FIXME (#2543) */ copy m.ident,
ii_ctor(_, nm, _, _) => /* FIXME (#2543) */ copy nm,
ii_dtor(_, nm, _, _) => /* FIXME (#2543) */ copy nm
}
}
@ -349,7 +347,6 @@ impl inlined_item: inlined_item_utils {
ii_item(i) => i.id,
ii_foreign(i) => i.id,
ii_method(_, m) => m.id,
ii_ctor(ctor, _, _, _) => ctor.node.id,
ii_dtor(dtor, _, _, _) => dtor.node.id
}
}
@ -359,9 +356,6 @@ impl inlined_item: inlined_item_utils {
ii_item(i) => v.visit_item(i, e, v),
ii_foreign(i) => v.visit_foreign_item(i, e, v),
ii_method(_, m) => visit::visit_method_helper(m, e, v),
ii_ctor(ctor, nm, tps, parent_id) => {
visit::visit_class_ctor_helper(ctor, nm, tps, parent_id, e, v);
}
ii_dtor(dtor, _, tps, parent_id) => {
visit::visit_class_dtor_helper(dtor, tps, parent_id, e, v);
}
@ -407,6 +401,7 @@ fn dtor_dec() -> fn_decl {
// Enumerating the IDs which appear in an AST
#[auto_serialize]
#[auto_deserialize]
type id_range = {min: node_id, max: node_id};
fn empty(range: id_range) -> bool {
@ -476,7 +471,7 @@ fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
visit_expr_post: fn@(_e: @expr) {
},
visit_ty: fn@(t: @ty) {
visit_ty: fn@(t: @Ty) {
match t.node {
ty_path(_, id) => vfn(id),
_ => { /* fall through */ }
@ -494,12 +489,6 @@ fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
vfn(id);
match fk {
visit::fk_ctor(_, _, tps, self_id, parent_id) => {
for vec::each(tps) |tp| { vfn(tp.id); }
vfn(id);
vfn(self_id);
vfn(parent_id.node);
}
visit::fk_dtor(tps, _, self_id, parent_id) => {
for vec::each(tps) |tp| { vfn(tp.id); }
vfn(id);

View file

@ -90,9 +90,7 @@ fn attr_meta(attr: ast::attribute) -> @ast::meta_item { @attr.node.value }
// Get the meta_items from inside a vector of attributes
fn attr_metas(attrs: ~[ast::attribute]) -> ~[@ast::meta_item] {
let mut mitems = ~[];
for attrs.each |a| { mitems.push(attr_meta(*a)); }
return mitems;
do attrs.map |a| { attr_meta(*a) }
}
fn desugar_doc_attr(attr: &ast::attribute) -> ast::attribute {

View file

@ -1,4 +1,8 @@
use dvec::DVec;
use std::serialization::{Serializable,
Deserializable,
Serializer,
Deserializer};
export filename;
export filemap;
@ -7,7 +11,7 @@ export file_substr;
export fss_none;
export fss_internal;
export fss_external;
export codemap;
export CodeMap;
export expn_info;
export expn_info_;
export expanded_from;
@ -55,11 +59,11 @@ type filemap =
@{name: filename, substr: file_substr, src: @~str,
start_pos: file_pos, mut lines: ~[file_pos]};
type codemap = @{files: DVec<filemap>};
type CodeMap = @{files: DVec<filemap>};
type loc = {file: filemap, line: uint, col: uint};
fn new_codemap() -> codemap { @{files: DVec()} }
fn new_codemap() -> CodeMap { @{files: DVec()} }
fn new_filemap_w_substr(+filename: filename, +substr: file_substr,
src: @~str,
@ -77,7 +81,7 @@ fn new_filemap(+filename: filename, src: @~str,
start_pos_ch, start_pos_byte);
}
fn mk_substr_filename(cm: codemap, sp: span) -> ~str
fn mk_substr_filename(cm: CodeMap, sp: span) -> ~str
{
let pos = lookup_char_pos(cm, sp.lo);
return fmt!("<%s:%u:%u>", pos.file.name, pos.line, pos.col);
@ -89,7 +93,7 @@ fn next_line(file: filemap, chpos: uint, byte_pos: uint) {
type lookup_fn = pure fn(file_pos) -> uint;
fn lookup_line(map: codemap, pos: uint, lookup: lookup_fn)
fn lookup_line(map: CodeMap, pos: uint, lookup: lookup_fn)
-> {fm: filemap, line: uint}
{
let len = map.files.len();
@ -112,22 +116,22 @@ fn lookup_line(map: codemap, pos: uint, lookup: lookup_fn)
return {fm: f, line: a};
}
fn lookup_pos(map: codemap, pos: uint, lookup: lookup_fn) -> loc {
fn lookup_pos(map: CodeMap, pos: uint, lookup: lookup_fn) -> loc {
let {fm: f, line: a} = lookup_line(map, pos, lookup);
return {file: f, line: a + 1u, col: pos - lookup(f.lines[a])};
}
fn lookup_char_pos(map: codemap, pos: uint) -> loc {
fn lookup_char_pos(map: CodeMap, pos: uint) -> loc {
pure fn lookup(pos: file_pos) -> uint { return pos.ch; }
return lookup_pos(map, pos, lookup);
}
fn lookup_byte_pos(map: codemap, pos: uint) -> loc {
fn lookup_byte_pos(map: CodeMap, pos: uint) -> loc {
pure fn lookup(pos: file_pos) -> uint { return pos.byte; }
return lookup_pos(map, pos, lookup);
}
fn lookup_char_pos_adj(map: codemap, pos: uint)
fn lookup_char_pos_adj(map: CodeMap, pos: uint)
-> {filename: ~str, line: uint, col: uint, file: Option<filemap>}
{
let loc = lookup_char_pos(map, pos);
@ -150,7 +154,7 @@ fn lookup_char_pos_adj(map: codemap, pos: uint)
}
}
fn adjust_span(map: codemap, sp: span) -> span {
fn adjust_span(map: CodeMap, sp: span) -> span {
pure fn lookup(pos: file_pos) -> uint { return pos.ch; }
let line = lookup_line(map, sp.lo, lookup);
match (line.fm.substr) {
@ -178,14 +182,42 @@ impl span : cmp::Eq {
pure fn ne(other: &span) -> bool { !self.eq(other) }
}
fn span_to_str_no_adj(sp: span, cm: codemap) -> ~str {
#[cfg(stage0)]
impl span: Serializable {
/* Note #1972 -- spans are serialized but not deserialized */
fn serialize<S: Serializer>(&self, _s: &S) { }
}
#[cfg(stage0)]
impl span: Deserializable {
static fn deserialize<D: Deserializer>(_d: &D) -> span {
ast_util::dummy_sp()
}
}
#[cfg(stage1)]
#[cfg(stage2)]
impl<S: Serializer> span: Serializable<S> {
/* Note #1972 -- spans are serialized but not deserialized */
fn serialize(&self, _s: &S) { }
}
#[cfg(stage1)]
#[cfg(stage2)]
impl<D: Deserializer> span: Deserializable<D> {
static fn deserialize(_d: &D) -> span {
ast_util::dummy_sp()
}
}
fn span_to_str_no_adj(sp: span, cm: CodeMap) -> ~str {
let lo = lookup_char_pos(cm, sp.lo);
let hi = lookup_char_pos(cm, sp.hi);
return fmt!("%s:%u:%u: %u:%u", lo.file.name,
lo.line, lo.col, hi.line, hi.col)
}
fn span_to_str(sp: span, cm: codemap) -> ~str {
fn span_to_str(sp: span, cm: CodeMap) -> ~str {
let lo = lookup_char_pos_adj(cm, sp.lo);
let hi = lookup_char_pos_adj(cm, sp.hi);
return fmt!("%s:%u:%u: %u:%u", lo.filename,
@ -194,12 +226,12 @@ fn span_to_str(sp: span, cm: codemap) -> ~str {
type file_lines = {file: filemap, lines: ~[uint]};
fn span_to_filename(sp: span, cm: codemap::codemap) -> filename {
fn span_to_filename(sp: span, cm: codemap::CodeMap) -> filename {
let lo = lookup_char_pos(cm, sp.lo);
return /* FIXME (#2543) */ copy lo.file.name;
}
fn span_to_lines(sp: span, cm: codemap::codemap) -> @file_lines {
fn span_to_lines(sp: span, cm: codemap::CodeMap) -> @file_lines {
let lo = lookup_char_pos(cm, sp.lo);
let hi = lookup_char_pos(cm, sp.hi);
let mut lines = ~[];
@ -218,7 +250,7 @@ fn get_line(fm: filemap, line: int) -> ~str unsafe {
str::slice(*fm.src, begin, end)
}
fn lookup_byte_offset(cm: codemap::codemap, chpos: uint)
fn lookup_byte_offset(cm: codemap::CodeMap, chpos: uint)
-> {fm: filemap, pos: uint} {
pure fn lookup(pos: file_pos) -> uint { return pos.ch; }
let {fm, line} = lookup_line(cm, chpos, lookup);
@ -228,20 +260,20 @@ fn lookup_byte_offset(cm: codemap::codemap, chpos: uint)
{fm: fm, pos: line_offset + col_offset}
}
fn span_to_snippet(sp: span, cm: codemap::codemap) -> ~str {
fn span_to_snippet(sp: span, cm: codemap::CodeMap) -> ~str {
let begin = lookup_byte_offset(cm, sp.lo);
let end = lookup_byte_offset(cm, sp.hi);
assert begin.fm.start_pos == end.fm.start_pos;
return str::slice(*begin.fm.src, begin.pos, end.pos);
}
fn get_snippet(cm: codemap::codemap, fidx: uint, lo: uint, hi: uint) -> ~str
fn get_snippet(cm: codemap::CodeMap, fidx: uint, lo: uint, hi: uint) -> ~str
{
let fm = cm.files[fidx];
return str::slice(*fm.src, lo, hi)
}
fn get_filemap(cm: codemap, filename: ~str) -> filemap {
fn get_filemap(cm: CodeMap, filename: ~str) -> filemap {
for cm.files.each |fm| { if fm.name == filename { return *fm; } }
//XXjdm the following triggers a mismatched type bug
// (or expected function, found _|_)

View file

@ -9,7 +9,7 @@ export codemap_span_handler, codemap_handler;
export ice_msg;
export expect;
type emitter = fn@(cmsp: Option<(codemap::codemap, span)>,
type emitter = fn@(cmsp: Option<(codemap::CodeMap, span)>,
msg: &str, lvl: level);
@ -33,7 +33,7 @@ trait handler {
fn note(msg: &str);
fn bug(msg: &str) -> !;
fn unimpl(msg: &str) -> !;
fn emit(cmsp: Option<(codemap::codemap, span)>, msg: &str, lvl: level);
fn emit(cmsp: Option<(codemap::CodeMap, span)>, msg: &str, lvl: level);
}
type handler_t = @{
@ -43,7 +43,7 @@ type handler_t = @{
type codemap_t = @{
handler: handler,
cm: codemap::codemap
cm: codemap::CodeMap
};
impl codemap_t: span_handler {
@ -107,7 +107,7 @@ impl handler_t: handler {
self.fatal(ice_msg(msg));
}
fn unimpl(msg: &str) -> ! { self.bug(~"unimplemented " + msg); }
fn emit(cmsp: Option<(codemap::codemap, span)>, msg: &str, lvl: level) {
fn emit(cmsp: Option<(codemap::CodeMap, span)>, msg: &str, lvl: level) {
self.emit(cmsp, msg, lvl);
}
}
@ -116,7 +116,7 @@ fn ice_msg(msg: &str) -> ~str {
fmt!("internal compiler error: %s", msg)
}
fn mk_span_handler(handler: handler, cm: codemap::codemap) -> span_handler {
fn mk_span_handler(handler: handler, cm: codemap::CodeMap) -> span_handler {
@{ handler: handler, cm: cm } as span_handler
}
@ -125,7 +125,7 @@ fn mk_handler(emitter: Option<emitter>) -> handler {
let emit = match emitter {
Some(e) => e,
None => {
let f = fn@(cmsp: Option<(codemap::codemap, span)>,
let f = fn@(cmsp: Option<(codemap::CodeMap, span)>,
msg: &str, t: level) {
emit(cmsp, msg, t);
};
@ -189,8 +189,7 @@ fn print_diagnostic(topic: ~str, lvl: level, msg: &str) {
io::stderr().write_str(fmt!(" %s\n", msg));
}
fn emit(cmsp: Option<(codemap::codemap, span)>,
msg: &str, lvl: level) {
fn emit(cmsp: Option<(codemap::CodeMap, span)>, msg: &str, lvl: level) {
match cmsp {
Some((cm, sp)) => {
let sp = codemap::adjust_span(cm,sp);
@ -206,7 +205,7 @@ fn emit(cmsp: Option<(codemap::codemap, span)>,
}
}
fn highlight_lines(cm: codemap::codemap, sp: span,
fn highlight_lines(cm: codemap::CodeMap, sp: span,
lines: @codemap::file_lines) {
let fm = lines.file;
@ -261,12 +260,12 @@ fn highlight_lines(cm: codemap::codemap, sp: span,
}
}
fn print_macro_backtrace(cm: codemap::codemap, sp: span) {
fn print_macro_backtrace(cm: codemap::CodeMap, sp: span) {
do option::iter(&sp.expn_info) |ei| {
let ss = option::map_default(&ei.callie.span, @~"",
|span| @codemap::span_to_str(*span, cm));
print_diagnostic(*ss, note,
fmt!("in expansion of #%s", ei.callie.name));
fmt!("in expansion of %s!", ei.callie.name));
let ss = codemap::span_to_str(ei.call_site, cm);
print_diagnostic(ss, note, ~"expansion site");
print_macro_backtrace(cm, ei.call_site);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
use std::map::HashMap;
use parse::parser;
use diagnostic::span_handler;
use codemap::{codemap, span, expn_info, expanded_from};
use codemap::{CodeMap, span, expn_info, expanded_from};
// obsolete old-style #macro code:
//
@ -80,14 +80,12 @@ fn syntax_expander_table() -> HashMap<~str, syntax_extension> {
builtin_item_tt(
ext::tt::macro_rules::add_new_extension));
syntax_expanders.insert(~"fmt", builtin(ext::fmt::expand_syntax_ext));
syntax_expanders.insert(~"auto_serialize",
item_decorator(ext::auto_serialize::expand));
syntax_expanders.insert(
~"auto_serialize2",
item_decorator(ext::auto_serialize2::expand_auto_serialize));
~"auto_serialize",
item_decorator(ext::auto_serialize::expand_auto_serialize));
syntax_expanders.insert(
~"auto_deserialize2",
item_decorator(ext::auto_serialize2::expand_auto_deserialize));
~"auto_deserialize",
item_decorator(ext::auto_serialize::expand_auto_deserialize));
syntax_expanders.insert(~"env", builtin(ext::env::expand_syntax_ext));
syntax_expanders.insert(~"concat_idents",
builtin(ext::concat_idents::expand_syntax_ext));
@ -122,12 +120,11 @@ fn syntax_expander_table() -> HashMap<~str, syntax_extension> {
return syntax_expanders;
}
// One of these is made during expansion and incrementally updated as we go;
// when a macro expansion occurs, the resulting nodes have the backtrace()
// -> expn_info of their expansion context stored into their span.
trait ext_ctxt {
fn codemap() -> codemap;
fn codemap() -> CodeMap;
fn parse_sess() -> parse::parse_sess;
fn cfg() -> ast::crate_cfg;
fn print_backtrace();
@ -159,7 +156,7 @@ fn mk_ctxt(parse_sess: parse::parse_sess,
mut mod_path: ~[ast::ident],
mut trace_mac: bool};
impl ctxt_repr: ext_ctxt {
fn codemap() -> codemap { self.parse_sess.cm }
fn codemap() -> CodeMap { self.parse_sess.cm }
fn parse_sess() -> parse::parse_sess { self.parse_sess }
fn cfg() -> ast::crate_cfg { self.cfg }
fn print_backtrace() { }
@ -234,7 +231,7 @@ fn mk_ctxt(parse_sess: parse::parse_sess,
mut mod_path: ~[],
mut trace_mac: false
};
move (imp as ext_ctxt)
move ((move imp) as ext_ctxt)
}
fn expr_to_str(cx: ext_ctxt, expr: @ast::expr, error: ~str) -> ~str {
@ -272,21 +269,21 @@ fn get_mac_args(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
match max {
Some(max) if ! (min <= elts_len && elts_len <= max) => {
cx.span_fatal(sp,
fmt!("#%s takes between %u and %u arguments.",
fmt!("%s! takes between %u and %u arguments.",
name, min, max));
}
None if ! (min <= elts_len) => {
cx.span_fatal(sp, fmt!("#%s needs at least %u arguments.",
cx.span_fatal(sp, fmt!("%s! needs at least %u arguments.",
name, min));
}
_ => return elts /* we are good */
}
}
_ => {
cx.span_fatal(sp, fmt!("#%s: malformed invocation", name))
cx.span_fatal(sp, fmt!("%s!: malformed invocation", name))
}
},
None => cx.span_fatal(sp, fmt!("#%s: missing arguments", name))
None => cx.span_fatal(sp, fmt!("%s!: missing arguments", name))
}
}

View file

@ -1,6 +1,6 @@
/*
* The compiler code necessary to support the #env extension. Eventually this
* The compiler code necessary to support the env! extension. Eventually this
* should all get sucked into either the compiler syntax extension plugin
* interface.
*/
@ -15,7 +15,7 @@ fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg,
// FIXME (#2248): if this was more thorough it would manufacture an
// Option<str> rather than just an maybe-empty string.
let var = expr_to_str(cx, args[0], ~"#env requires a string");
let var = expr_to_str(cx, args[0], ~"env! requires a string");
match os::getenv(var) {
option::None => return mk_uniq_str(cx, sp, ~""),
option::Some(s) => return mk_uniq_str(cx, sp, s)

View file

@ -1,7 +1,7 @@
/*
* The compiler code necessary to support the #fmt extension. Eventually this
* The compiler code necessary to support the fmt! extension. Eventually this
* should all get sucked into either the standard library extfmt module or the
* compiler syntax extension plugin interface.
*/
@ -16,7 +16,7 @@ fn expand_syntax_ext(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
let args = get_mac_args_no_max(cx, sp, arg, 1u, ~"fmt");
let fmt =
expr_to_str(cx, args[0],
~"first argument to #fmt must be a string literal.");
~"first argument to fmt! must be a string literal.");
let fmtspan = args[0].span;
debug!("Format string:");
log(debug, fmt);
@ -76,7 +76,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span,
let count_is_args = ~[count_lit];
return mk_call(cx, sp, count_is_path, count_is_args);
}
_ => cx.span_unimpl(sp, ~"unimplemented #fmt conversion")
_ => cx.span_unimpl(sp, ~"unimplemented fmt! conversion")
}
}
fn make_ty(cx: ext_ctxt, sp: span, t: Ty) -> @ast::expr {
@ -133,7 +133,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span,
_ => return false
}
}
let unsupported = ~"conversion not supported in #fmt string";
let unsupported = ~"conversion not supported in fmt! string";
match cnv.param {
option::None => (),
_ => cx.span_unimpl(sp, unsupported)
@ -145,14 +145,14 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span,
if !is_signed_type(cnv) {
cx.span_fatal(sp,
~"+ flag only valid in " +
~"signed #fmt conversion");
~"signed fmt! conversion");
}
}
FlagSpaceForSign => {
if !is_signed_type(cnv) {
cx.span_fatal(sp,
~"space flag only valid in " +
~"signed #fmt conversions");
~"signed fmt! conversions");
}
}
FlagLeftZeroPad => (),
@ -252,7 +252,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span,
n += 1u;
if n >= nargs {
cx.span_fatal(sp,
~"not enough arguments to #fmt " +
~"not enough arguments to fmt! " +
~"for the given format string");
}
debug!("Building conversion:");
@ -267,7 +267,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span,
if expected_nargs < nargs {
cx.span_fatal
(sp, fmt!("too many arguments to #fmt. found %u, expected %u",
(sp, fmt!("too many arguments to fmt!. found %u, expected %u",
nargs, expected_nargs));
}

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