Merge remote-tracking branch 'original/incoming' into incoming
This commit is contained in:
commit
cc0f2c6bb2
401 changed files with 11020 additions and 10248 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
63
README.md
63
README.md
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
28
configure
vendored
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"};
|
||||
|
|
|
|||
1401
doc/rust.md
1401
doc/rust.md
File diff suppressed because it is too large
Load diff
|
|
@ -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 we’d 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 (I’ll 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
|
||||
|
||||
We’ve seen a few examples so far where heap boxes (both managed and
|
||||
unique) are borrowed. Up till this point, we’ve glossed over issues of
|
||||
We’ve seen a few examples so far of borrowing heap boxes, both managed
|
||||
and unique. Up till this point, we’ve 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. We’ll 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
|
||||
we’re 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 doesn’t 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`. We’ll 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
|
||||
won’t 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, let’s 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, let’s 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 we’ve 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, let’s look at a variation on the example, this
|
||||
time one which does not compile:
|
||||
To emphasize this point, let’s 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.)
|
||||
|
||||
Let’s revisit a previous example and show how purity can affect the
|
||||
compiler’s result. Here is `example5a()`, which borrows the interior of
|
||||
a unique box found in an aliasable, mutable location, only now we’ve
|
||||
Let’s 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 we’ve
|
||||
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
|
||||
doesn’t 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.
|
||||
|
|
|
|||
|
|
@ -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 that—they 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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
1256
doc/tutorial.md
1256
doc/tutorial.md
File diff suppressed because it is too large
Load diff
43
man/rustc.1
43
man/rustc.1
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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)}
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
_ => { }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
300
src/libcore/condition.rs
Normal 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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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: ~[]})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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})}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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!");
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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>();
|
||||
|
|
|
|||
|
|
@ -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 */)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 _|_)
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue